【问题标题】:Draw same lines drawn on a Tkinter Canvas on an OpenCV image在 OpenCV 图像上的 Tkinter 画布上绘制相同的线条
【发布时间】:2015-07-22 23:51:46
【问题描述】:

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

我的目标是保存用于在 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

【问题讨论】:

    标签: python opencv tkinter mouseevent


    【解决方案1】:

    您不应在 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)


    您的完整代码如下所示。请注意,我还删除了 les_points 中的 selffirst_pointdessiner_lignes 中的 second_point,因为它们仅用于该方法,因此无需将它们保存为类属性。

    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()
    

    【讨论】:

    • 是的,从这两个属性中删除 self 是对的。再次非常感谢您。
    • 不客气。此外,分离TestMaClasse 并将点传递给dessiner_lignes 的优点是,如果您可能从Test 的多个实例中获得点,则可以多次调用dessiner_lignes。因此,您可以运行 root=Tk() ... points=v.get_points() 部分两次(例如,第二次分配给 points2 ),然后您只需要额外调用 dessiner_lignes(points2) 即可从两个 Test 实例中绘制线条。
    • 很抱歉再次打扰您,但我在我们的程序中发现了一个问题 :( 假设我在画布上绘制了 2 条单独的曲线/段:它们在 OpenCV 窗口上看起来总是统一的 :( 我不知道要检查的条件不是每 2 个连续点链接一次,除非它们以前在画布上链接过
    • 对了。您可以通过将(None, None) 置于休息时间(因此在b1up 事件中)来解决此问题。然后,您可以忽略 OpenCV 绘图中坐标为无的任何线段。我将更新答案以包含此内容。
    猜你喜欢
    • 2021-10-30
    • 1970-01-01
    • 2018-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    相关资源
    最近更新 更多