在OpenCV图像上的Tkinter画布上绘制相同的线 [英] Draw same lines drawn on a Tkinter Canvas on an OpenCV image

查看:82
本文介绍了在OpenCV图像上的Tkinter画布上绘制相同的线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用鼠标让用户在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中获取.因此,您可以将MaClasseTest完全分开.

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_lignesles_pointsfirst_pointsecond_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆