Draw same lines drawn on a Tkinter Canvas on an OpenCV image

守給你的承諾、 提交于 2019-12-13 04:52:46

问题


Using the mouse, I let the user to draw random curves on a Tkinter Canvas. These curves are drawn as short lines between points over which the mouse moves.

My aim is to save the points used to draw the lines on the Canvas and to draw the same curves using the same points on a simple OpenCV window.

The drawing on the Canvas works perfectly, however, wherever I place the OpenCV window I never succeed to fulfill my goal. I think the problem may be in a wrong functions call order?

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

回答1:


You shouldn't create a MaClasse instance during the Motion event, since that way you create a new MaClasse every time a new line is drawn. You only want to create one MaClasse and get the points from Test into it. Therefore, you can completely separate MaClasse and Test.

You get the points using

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

This sets up the Test app, and after all points have been drawn, uses get_points() to get the points.

Then, you can set up a MaClasse instance, but you need a way to pass the points into it. The most sensible way (to me) seems to be to pass them into the dessiner_lignes function, since that draws the lines. If you alter dessiner_lignes so that it accepts a les_points variable (def dessiner_lignes(self, les_points=[]):), you can then draw and show the image using

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

To separate separately drawn curves, you can place a (None, None) "coordinate" when the mouse button is released (so in b1up). Then in dessiner_lignes just check if both coordinates are not (None, None) before drawing the line segment.


Your complete code then looks like this. Note that I've also removed self from les_points, first_point and second_point in dessiner_lignes since they are only used in that method, so there is no need to save them as class attributes.

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


来源:https://stackoverflow.com/questions/30185235/draw-same-lines-drawn-on-a-tkinter-canvas-on-an-opencv-image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!