如何获得画布图像以检测并传送到另一个画布图像?

时间:2018-12-12 20:07:16

标签: python tkinter

我有一个带有道路图像的程序,允许用户在画布上构建道路。当前,用户可以选择道路的去向,而不必连接到另一条道路。 这是一个示例:(道路图像由用户放置)

我想发生的是,一旦按下Build Road(vertical)Build Road(horizontal),它将检测到该道路的任何现有图像,并根据所按下的按钮将其垂直或水平放置。我知道这听起来有些牵强,但这是我的代码:

from tkinter import *


root = Tk()
root.title("root")


road1 = PhotoImage(file=r"road1.png")
road2 = PhotoImage(file=r"road2.png")
road3 = PhotoImage(file=r"intersection.png")

canvas = Canvas(root, width=500, height=400, bg='green')

button_frame = Frame(root)

button_frame.pack(side="left", fill="y")
canvas.pack(side="right", fill="both", expand=True)
roadstart = canvas.create_image(100, 0, image=road1)

clickedv = None
clickedh = None
clickedm = None


def buildroadv():
    global clicked
    clickedv = False
    road = canvas.create_image(50, 50, image=road1)
    def move(event):
        global clickedv
        if clickedv == False:
            x = event.x
            y = event.y
            canvas.coords(road, x, y)
    def placeroad(event):
        global clickedv
        clickedv = True
    canvas.tag_bind(road, "<Motion>", move)
    canvas.tag_bind(road, "<ButtonPress-1>", placeroad)

def buildroadh():
    global clickedh
    clickedh = False
    road = canvas.create_image(50, 50, image=road2)
    def move(event):
        global clickedh
        if clickedh == False:
            x = event.x
            y = event.y
            canvas.coords(road, x, y)
    def placeroad(event):
        global clickedh
        clickedh = True
    canvas.tag_bind(road, "<Motion>", move)
    canvas.tag_bind(road, "<ButtonPress-1>", placeroad)

def buildroadm():
    global clickedm
    clickedm = False
    road = canvas.create_image(50, 50, image=road3)
    def move(event):
        global clickedm
        if clickedm == False:
            x = event.x
            y = event.y
            canvas.coords(road, x, y)
    def placeroad(event):
        global clickedm
        clickedm = True
    canvas.tag_bind(road, "<Motion>", move)
    canvas.tag_bind(road, "<ButtonPress-1>", placeroad)



button1 = Button(button_frame, text="Build Road (vertical)", command=buildroadv)
button2 = Button(button_frame, text="Build Road (horizontal)", command=buildroadh)
button3 = Button(button_frame, text="Build Road (intersection)", command=buildroadm)
button4 = Button(button_frame, text="Build -")
button5 = Button(button_frame, text="Build -")
button6 = Button(button_frame, text="Build -")
button7 = Button(button_frame, text="Build -")
button8 = Button(button_frame, text="Build -")


button1.pack(side="top", fill="x")
button2.pack(side="top", fill="x")
button3.pack(side="top", fill="x")
button4.pack(side="top", fill="x")
button5.pack(side="top", fill="x")
button6.pack(side="top", fill="x")
button7.pack(side="top", fill="x")
button8.pack(side="top", fill="x")

为再次概述我的目标,我希望程序检测是否已经存在road,如果存在,请相应地放置新路。例如:

我希望这足以解释。对于如此具体的问题/广泛的答案,我深表歉意。

1 个答案:

答案 0 :(得分:0)

好,所以这可能是您所做的疯狂的过度杀伤力。您可能只需要使用最后一次单击的坐标即可提取道路的尺寸和位置。不幸的是,由于无法访问图像,因此无法测试,因此我想为您提供一种更通用的解决方案,即使您将像您提供的图像一样加载到画布上,也不会点击,该解决方案仍然可以使用要记住。此外,正如一些评论所指出的那样,如果您已经知道路障的坐标和尺寸,则放置它们是微不足道的。只需根据保存的值将新道路设置在适当的位置即可。当您不知道道路在哪里时,即当您查看原始图像时,它会变得有点困难。那就是我要研究的问题。我采取的基本策略是像对待其他图像处理/计算机视觉问题一样对待它,并在图像中找到道路作为对象。

第一步是隔离道路。为此,您可以使用sobel过滤器查找边缘,然后进行阈值处理和填充以将其变成实体块:

import imageio
import skimage
import numpy
import scipy.ndimage.filters
import skimage.io
import skimage.filters
import skimage.morphology


image = imageio.imread(r'C:\Users\Jeremiah\Pictures\roads.PNG')
image_array = numpy.float64(image)

#Sobel Filter for color image.  First the kernel is applied to the RGB values, then some linear algebra is done to marry the results together and apply them to the image as a whole.

R_x = scipy.ndimage.filters.correlate(image_array[:, :, 0], [[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
G_x = scipy.ndimage.filters.correlate(image_array[:, :, 1], [[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
B_x = scipy.ndimage.filters.correlate(image_array[:, :, 2], [[1, 2, 1], [0, 0, 0], [-1, -2, -1]])

R_y = scipy.ndimage.filters.correlate(image_array[:, :, 0], [[1, 0 , -1], [2, 0, -2], [1, 0, -1]])
G_y = scipy.ndimage.filters.correlate(image_array[:, :, 1], [[1, 0 , -1], [2, 0, -2], [1, 0, -1]])
B_y = scipy.ndimage.filters.correlate(image_array[:, :, 2], [[1, 0 , -1], [2, 0, -2], [1, 0, -1]])

Jacobian_x = R_x**2 + G_x**2 + B_x**2
Jacobian_y = R_y**2 + G_y**2 + B_y**2
Jacobian_xy = R_x * R_y + G_x * G_y + B_x * B_y
Determinant = numpy.sqrt(numpy.fabs((Jacobian_x**2) - (2 * Jacobian_x * Jacobian_y) + (Jacobian_y**2) + 4 * (Jacobian_xy**2)))
Maximum_Eigenvalue = (Jacobian_x + Jacobian_y + Determinant) / 2
Edges = numpy.sqrt(Maximum_Eigenvalue)

#A threshold is set, and a binary image is produced that sets everything above the threshold to 255 and everything below it to 0.

Threshold = skimage.filters.threshold_mean(Edges)
Binary_Image = Edges > Threshold   

#The holes in the objects are filled in, so that each road is a solid block.

Filled_Holes = scipy.ndimage.morphology.binary_fill_holes(Binary_Image)

接下来,您要标记块:

labeled_Edges, features = scipy.ndimage.label(Filled_Holes)

现在您已在图像中标记了对象,您可以使用labeled_Edges切片作为此块开始和停止位置的索引。 features为您提供图像中的对象数量。例如:

sliced = scipy.ndimage.find_objects(labeled_Edges)[3]
>>>(slice(127, 166, None), slice(37, 71, None))

如果我们将该切片用作原始图像数组中的索引,则会得到一个仅包含该对象像素的数组,为方便起见将其标记为

slices = labeled_Edges[sliced]
>>>[[4 4 4 ... 4 4 4]
   [4 4 4 ... 4 4 4]
   [4 4 4 ... 4 4 4]
   ...
   [4 4 4 ... 4 4 4]
   [4 4 4 ... 4 4 4]
   [4 4 4 ... 4 4 4]]

4仅表示这是图像中的第四个标记对象,因为在这种情况下我们搜索了labeled_Edges[3]。在实践中,您可能希望使用for循环来自动执行此操作,将范围设置为1到features,但是一旦有了分片,便有了任何索引的开始和结束索引道路瓷砖,然后将下一个道路瓷砖的边缘放在下一个像素上。因此,在上述示例中,我们的拐角位于(127, 37), (127, 71), (166, 37), and (166,71)。仅通过使用这些拐角即可自动布置下一条路。例如,如果要在此路障的右侧放置路障,并且要使用左上角引用要放置的路障,则新路将放置在(166, 37)处。要将相同的块放置在该块的左侧,并使用与锚点相同的角,请将其放置在(127 - new_block_length, 37)上。

不幸的是,您问题的某些方面不是很具体。您是否将道路图像的位置存储在任何地方,还是需要让程序实际查看图像?当您单击“水平”时是否要放置所有可能的水平道路,或者是否有引用特定道路的方法?您是使用中心像素还是拐角之一放置道路?有很多变量会阻止您为该解决方案编写代码,但这可能会为您提供一些尝试的思路,至少让您了解如何在图像本身中定位对象。

这个答案有点宽泛,但问题有点宽泛。如果您已经存储了道路的位置,则不需要计算机视觉的东西。您只需使用简单的变量调用即可找到道路的坐标,然后执行相同的操作,即可根据最后一条道路的位置放置新道路。