Reputation:
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
Upvotes: 0
Views: 1815
Reputation: 10602
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()
Upvotes: 1