python - 在OpenCV图像上的Tkinter Canvas 上绘制相同的线

标签 python opencv tkinter mouseevent

我使用鼠标让用户在Tkinter Canvas 上绘制随机曲线。这些曲线绘制为鼠标移动的点之间的短线。

我的目的是保存用于在Canvas上绘制线条的点,并在简单的OpenCV窗口上使用相同的点绘制相同的曲线。

Canvas上的绘图效果很好,但是,无论我将OpenCV窗口放在何处,都无法成功实现我的目标。我认为问题可能出在错误的函数调用顺序上?

from Tkinter import *
import numpy as np
import cv2

class Test:
   def __init__(self):
       self.b1="up"
       self.xold=None
       self.yold=None
       self.liste=[]
   def test(self,obj):
       self.drawingArea=Canvas(obj)
       self.drawingArea.pack() 
       self.drawingArea.bind("<Motion>",self.motion)
       self.drawingArea.bind("<ButtonPress-1>",self.b1down)
       self.drawingArea.bind("<ButtonRelease-1>",self.b1up)
   def b1down(self,event):
       self.b1="down"
   def b1up(self,event):
       self.b1="up"
       self.xold=None
       self.yold=None
   def motion(self,event):
       if self.b1=="down":
           if self.xold is not None and self.yold is not None:
               event.widget.create_line(self.xold,self.yold,event.x,event.y,fill="red",width=3,smooth=TRUE)
           self.xold=event.x
           self.yold=event.y
           self.liste.append((self.xold,self.yold))
       self.MC=MaClasse()
       self.MC.dessiner_lignes()
       self.MC.maclasse()
   def get_points(self):
       for i in range(len(self.liste)):
           print self.liste[i]
       return self.liste
class MaClasse:
   def __init__(self):   
       self.s=600,600,3
       self.les_points=[]# Empty list
       self.ma=np.zeros(self.s,dtype=np.uint8)
   def maclasse(self):
       cv2.namedWindow("OpenCV",cv2.WINDOW_AUTOSIZE)
       cv2.imshow("OpenCV",self.ma)
       cv2.waitKey(0)
       cv2.destroyAllWindows()
   def dessiner_lignes(self):
       self.voi=Test()
       self.les_points=self.voi.get_points()
       # It always displays 0
       print "number of points: {}".format(len(self.les_points))
       for i in range(len(self.les_points)):
           print i
           if i<len(self.les_points)-1:
               print self.les_points[i]
               self.first_point=self.les_points[i]
               self.second_point=self.les_points[i+1]
               cv2.line(self.ma,self.first_point,self.second_point,[255,255,255],2)

if __name__=="__main__":
   root=Tk()
   root.wm_title("Test")
   v=Test()
   v.test(root)
   root.mainloop()
   MC=MaClasse()
   v.get_points() # I get the points here

最佳答案

您不应在Motion事件期间创建MaClasse实例,因为那样的话,每次绘制新线时,您都将创建一个新的MaClasse。您只想创建一个MaClasse并将Test中的点放入其中。因此,您可以完全分隔MaClasseTest

你得到的积分

root = Tk()
v = Test()
v.test(root)
root.mainloop()
points = v.get_points()

这将设置Test应用程序,并在绘制所有点之后,使用get_points()获取点。

然后,您可以设置一个MaClasse实例,但是您需要一种将点传递到其中的方法。 (对我而言)最明智的方法似乎是将它们传递给dessiner_lignes函数,因为这样可以划清界限。如果您更改dessiner_lignes使其接受les_points变量(def dessiner_lignes(self, les_points=[]):),则可以使用以下方式绘制并显示图像
MC = MaClasse()
MC.dessiner_lignes(points)
MC.maclasse()

要分离单独绘制的曲线,可以在释放鼠标按钮时放置一个(None, None)“坐标”(因此在b1up中)。然后在dessiner_lignes中,只需在绘制线段之前检查两个坐标是否都不是(None, None)

您的完整代码如下所示。请注意,我还从self中的les_pointsfirst_pointsecond_point中删除了dessiner_lignes,因为它们仅在该方法中使用,因此无需将它们另存为类属性。
from Tkinter import *
import numpy as np
import cv2

class Test:
    def __init__(self):
        self.b1="up"
        self.xold=None
        self.yold=None
        self.liste=[]
    def test(self,obj):
        self.drawingArea=Canvas(obj)
        self.drawingArea.pack() 
        self.drawingArea.bind("<Motion>",self.motion)
        self.drawingArea.bind("<ButtonPress-1>",self.b1down)
        self.drawingArea.bind("<ButtonRelease-1>",self.b1up)
    def b1down(self,event):
        self.b1="down"
    def b1up(self,event):
        self.b1="up"
        self.xold=None
        self.yold=None
        self.liste.append((self.xold,self.yold))
    def motion(self,event):
        if self.b1=="down":
            if self.xold is not None and self.yold is not None:
                event.widget.create_line(self.xold,self.yold,event.x,event.y,fill="red",width=3,smooth=TRUE)
            self.xold=event.x
            self.yold=event.y
            self.liste.append((self.xold,self.yold))
    def get_points(self):
        #for i in range(len(self.liste)):
            #print self.liste[i]
        return self.liste

class MaClasse:
    def __init__(self):   
        self.s=600,600,3
        self.ma=np.zeros(self.s,dtype=np.uint8)
    def maclasse(self):
        cv2.namedWindow("OpenCV",cv2.WINDOW_AUTOSIZE)
        cv2.imshow("OpenCV",self.ma)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
    def dessiner_lignes(self, les_points=[]):
        print "number of points: {}".format(len(les_points))
        for i in range(len(les_points)):
            #print i
            if i<len(les_points)-1:
                #print les_points[i]
                first_point=les_points[i]
                second_point=les_points[i+1]
                if not first_point == (None, None) and not second_point == (None, None):
                    cv2.line(self.ma,first_point,second_point,[255,255,255],2)

if __name__=="__main__":
    root = Tk()
    root.wm_title("Test")
    v = Test()
    v.test(root)
    root.mainloop()
    points = v.get_points()

    MC = MaClasse()
    MC.dessiner_lignes(points)
    MC.maclasse()

关于python - 在OpenCV图像上的Tkinter Canvas 上绘制相同的线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30185235/

相关文章:

python - 正在为电影预告片搜寻IMDB?

python - cv2.IMREAD_GRAYSCALE 如何将 16 位图像转换为 8 位图像(OpenCV python)?

opencv - 调整代码以检测多个圆圈,而不是OPENCV中的一个圆圈

python - 使用 python 3 和 tkinter 中的 colorchooser 更改 tkinter 窗口中文本的颜色

python - 当我在 tkinter 中删除文本框时,总是留下一个空行

python - 在 Python 中替换文本

python - 为什么在我停止程序之前不会写入文件?

python - 获取具有 0 或 1 序列的二进制列表的开始和结束 1 的索引

python - 在 OpenCV SIFT (Python) 中删除梯度方向直方图的高斯加权

python - 如何在事件中获取小部件名称?