在OpenCV图像上的Tkinter画布上绘制相同的线 [英] Draw same lines drawn on a Tkinter Canvas on an OpenCV image
问题描述
我使用鼠标让用户在Tkinter画布上绘制随机曲线.这些曲线绘制为鼠标移动的点之间的短线.
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.
我的目的是保存用于在Canvas上绘制线条的点,并在一个简单的OpenCV窗口上使用相同的点绘制相同的曲线.
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.
Canvas上的图形可以完美地工作,但是,无论我将OpenCV窗口放在何处,都无法成功实现我的目标.我认为问题可能出在错误的函数调用顺序上?
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
推荐答案
您不应在Motion事件期间创建MaClasse
实例,因为那样的话,每次绘制新线时,您都会创建一个新的MaClasse
.您只想创建一个MaClasse
并将点从Test
中获取.因此,您可以将MaClasse
和Test
完全分开.
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
.
您可以使用
root = Tk()
v = Test()
v.test(root)
root.mainloop()
points = v.get_points()
这将设置Test
应用,并在绘制所有点之后,使用get_points()
来获取点.
This sets up the Test
app, and after all points have been drawn, uses get_points()
to get the points.
然后,您可以设置一个MaClasse
实例,但是您需要一种将点传递到其中的方法. (对我而言)最明智的方法似乎是将它们传递给dessiner_lignes
函数,因为这样可以划清界限.如果您更改dessiner_lignes
使其接受les_points
变量(def dessiner_lignes(self, les_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()
要分离单独绘制的曲线,可以在释放鼠标按钮时放置(None, None)
坐标"(在b1up
中也是如此).然后在dessiner_lignes
中,只需在绘制线段之前检查两个坐标是否都不为(None, None)
.
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.
您的完整代码如下所示.请注意,我还从dessiner_lignes
的les_points
,first_point
和second_point
中删除了self
,因为它们仅在该方法中使用,因此无需将它们另存为类属性.
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()
这篇关于在OpenCV图像上的Tkinter画布上绘制相同的线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!