python - 如何获取 Canvas 图像来检测并传送到另一个 Canvas 图像?

标签 python tkinter

我有一个带有道路图像的程序,允许用户在 Canvas 上修建道路。目前,用户可以选择道路通向何处,并且不必连接到另一条道路。 这是一个例子:(道路图像由用户放置)

我想要发生的是,一旦按下构建道路(垂直)构建道路(水平),它将检测该道路的任何现有图像,然后根据按下的按钮将其垂直或水平放置。我知道这听起来有点牵强,但这是我的代码:

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

为了再次概述我的目标,我希望程序能够检测是否已有道路,如果存在,则相应地放置新道路。例如:

我希望这已经足够解释了。对于这样一个具体的问题/广泛的答案,我深表歉意。

最佳答案

好吧,这对于你正在做的事情来说可能是疯狂的矫枉过正。您可能只需使用上次单击的坐标来提取道路的尺寸和位置。不幸的是,如果无法访问图像,我无法对此进行测试,所以我想我应该为您提供一种更通用的解决方案,即使您将像您提供的图像这样的图像加载到 Canvas 上(没有点击),该解决方案也能工作。记住。此外,正如一些评论所指出的,如果您已经知道路障的坐标和尺寸,那么放置它们就很简单了。只需根据您保存的值将新道路设置在适当的位置即可。当您不知道道路在哪里时,即当您查看原始图像时,事情会变得有点困难。这就是我要研究的问题。我采取的基本策略是像对待任何其他图像处理/计算机视觉问题一样对待这个问题,并将道路视为图像中的对象。

第一步是隔离道路。为此,您可以使用索贝尔过滤器来查找边缘,然后进行阈值处理和填充,将它们变成实心 block :

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)

接下来,标记你的 block :

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

现在您已经标记了图像中的对象,您可以使用 labeled_Edges 切片作为该 block 开始和停止位置的索引。 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,但是一旦您有了切片,您就拥有了索引任何道路图 block 的开始和结束,您只需将下一个道路图 block 的边缘放置在下一个像素上。因此,在上面的示例中,我们的角点位于 (127, 37)、(127, 71)、(166, 37) 和 (166,71)。只需使用这些拐角即可自动放置下一条道路。例如,如果您想在该路段的右侧放置一个路 block ,并且您正在使用左上角引用要放置的路 block ,则新道路将放置在 (166, 37) 。要将相同的 block 放置在该 block 的左侧,并使用相同的角作为 anchor ,您可以将其放置在 (127 - new_block_length, 37) 处。

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

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

关于python - 如何获取 Canvas 图像来检测并传送到另一个 Canvas 图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53750598/

相关文章:

python - 使用 seaborn 对 python 中的 matplotlib 进行核密度估计的下限

java - Python 生成的 XML 中的错误

javascript - 我正在尝试以一种奇怪的方式用 python 创建一个网站

python - 在 Python 中速记添加/追加

python-2.7 - Tkinter 中的多个窗口 (Python 2.7)

python - Django 站点地图框架。接受查询参数

python - tkinter中如何绑定(bind)退格键删除多个字符?

python - 如何将 '<Return>' 绑定(bind)到 tkinter 中的焦点(选项卡式)按钮?

python - 向 Tkinter 添加单选按钮

python - 如何在 tkinter 中验证输入字段