【问题标题】:Opencv/python - how can i get the coordinates of detected areas after image processingOpencv/python - 如何在图像处理后获取检测区域的坐标
【发布时间】:2017-08-31 13:55:02
【问题描述】:

我的目标是编写一个玩扫雷的机器人,但是当我想告诉机器人方块在哪里时,我就卡在了这一点上。我尝试了很多不同的功能。 首先,我的工具会抓取一个预定义区域的屏幕截图。这张图是这样的:screenshot of game board

之后我想用这种方式填充一个 numpy 数组:

info_map = np.ones((board_height=9, board_width=9),
                   dtype = np.uint8)*11
>array([[11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11],
        [11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11],
        ...
        [11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11]], dtype=uint8

在本例中,11 代表“未发现”或蓝色、未触及的正方形。

在示例中的 opencv 方形检测器的帮助下,我得到了一个包含检测点的巨大列表(对于 9x9 网格,将近 5000 个点)。我不知道如何消除所有噪音,以获得正确的角落坐标。所以我来到下一个示例,如下所示:

我的最后一次尝试如下:

import glob
import cv2
import numpy as np
import sys   

def canny_edge():
"""This function is taken from SentDex from one of his fantastic Python
tutorials.
https://pythonprogramming.net/canny-edge-detection-gradients-python-opencv-tutorial/
"""
for fn in glob('full_snap.png'):
    img = cv2.imread(fn)
    while(1):
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        lower_red = np.array([30,150,50])
        upper_red = np.array([255,255,180])
        mask = cv2.inRange(hsv, lower_red, upper_red)
        #res = cv2.bitwise_and(img, img, mask= mask)
        laplacian = cv2.Laplacian(img, cv2.CV_64F)
        #edges = cv2.Canny(img,100,200)

        cv2.imwrite(os.getcwd() + '\\laplace.png', laplacian)

这是保存的图片: laplace.png

在这里,我尝试在拉普拉斯算子上进行 for 循环以检查像素是否为蓝色,并将第一个作为锚点告诉机器人,从锚点(起点)开始,每个像素都有一个正方形x 方向和 y 方向的 x 像素。但是有没有更好的方法来自动完成呢?

但我的主要问题是如何将经过图像处理的正方形连接到一个 numpy 数组中,我可以告诉机器人 click_square(1,2),他知道像素是第 1 行和第 2 列的正方形。

提示:我的坐标系从屏幕的左上角开始。

感谢您的帮助。 罗宾亚瑟

【问题讨论】:

  • opencv 中的这个示例不正是这样做的吗? github.com/opencv/opencv/blob/master/samples/python/squares.py
  • 这是我第一次使用的方法,在你的回答之后,我保存了我的函数对这个例子所做的图像,我得到了我认为的答案。几天前,squares.py 给了我一个包含 5000 点的巨大列表,每个角落都可能有 10 个不同的点。但是几秒钟前我得到了我认为的正确答案。现在我只需要粗点的中心点,从 squares.py 第 51 行绘制。谢谢

标签: python opencv numpy image-processing bots


【解决方案1】:

我不知道扫雷器是什么,但据我了解,您想知道哪些瓷砖是蓝色的,然后对您的 numpy 数组进行必要的更改(如果有其他问题,请纠正我,我将编辑或删除答案)。

这是将四个图块设为蓝色后的输出:

我做了什么?

首先我对蓝色进行阈值处理,发现范围内的轮廓与您的瓷砖大致相同。

找到他们的中心,看看他们遵循什么模式 -

它们都被大约 55-57 像素(都是 x,y 坐标)分开。休息很简单。

for i in range(len(coords)):
np_arr[int(coords[i][1]/57)][int(coords[i][0]/57)]=0

蓝色瓦片坐标存储在coords中,np_arr是我的数组。

【讨论】:

  • 是的,你做到了,我想我明白你所做的背后的想法。我只有两个问题: - 你的“坐标”中的值只是瓷砖的中心坐标还是所有角落的坐标? - 你选择了蓝色的哪个范围?来自典型 opencv 示例的“正常”upper_blue/lower_blue(HSV 颜色空间)还是我的蓝色图块的特殊值?
  • 目前只有中心。那就足够了。您可以为中心添加一个范围,但我认为这是多余的。我在 HSV 中对图像进行了阈值处理,因为如果图像中稍后还有其他类似的灰度级别的东西,直接灰度阈值可能会毁掉它。 lower_red = np.array([100,80,50])。你可以玩一点不要被该图像中的蓝色误导。它只是一个空白数组,为 hsv 范围内的一些蓝色图块绘制了 (255,0,0)
  • 谢谢,我做到了。在接下来的几天里,我会用我最后用来解决我的问题的代码来回答这个问题。由于 rgb/bgr 和 hsv,要找到正确的像素值并将其提供给 opencv 真的很困难 :-) 但现在我做到了。
  • 太好了!谢谢你让我知道:)
  • 为像素 hsv、bgr 值制作一个 opencv 轨迹栏以简化任务。
【解决方案2】:

这是我使用的代码。最后我必须重新排列我的数据框,但只是为了更好的人类阅读。我认为我的代码有很多可能的改进,但我很高兴我的代码的行为足以满足我的需求。

import cv2
import numpy as np
import pandas as pd

img = cv2.imread('full_snap.png')
"""
some of my blue pixels
R: between 98 and 128
G: between 176 and 211
B: between 255

h: between 210 and 200
s: between 100 and 48
v: between 68 and 100

hsv/2 in opencv and opencv uses BGR not RGB
"""

blue_MIN = np.array([255, 176, 98])
blue_MAX = np.array([255, 211, 128])
"""
https://pythonprogramming.net/color-filter-python-opencv-tutorial/
"""

# find the blue pixels and save it in frame_threshed
frame_threshed = cv2.inRange(img, blue_MIN, blue_MAX)

# find contours in the thresholded image
cnts = cv2.findContours(frame_threshed.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]

#print("cnts", cnts)
i = len(cnts)
print("i", i)

# we know we're gonna have x rows of data, where x is the product of
# board_width * board_height
numberOfRows = 81

# check if the length of cnts are euqal to the number of rows/ number of tiles
# then go further

# TODO

# create x,y data
# df = pd.DataFrame(index=np.arange(numberOfRows, 0), columns=('x', 'y'))
d = []
print("d", d)
print(type(d))


for c in cnts:
    # compute the center of the contour
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])

    # fill the data with the coords
    d.append({'tilenumber': i, 'X-Value': cX, 'Y-Value': cY})

    # decrease i to go backwards, because tile number 81 is the first contour
    i-=1
    # draw the center of the shape on the image
    cv2.circle(img, (cX, cY), 1, (255, 255, 255), -1)

df = pd.DataFrame(d)

# only for debugging
print("x,y dataframe", df)
cv2.imshow("Image_with_contours",img)

# Destroys all of the HighGUI windows.
cv2.destroyAllWindows()

感谢大家的帮助! 罗宾亚瑟

【讨论】:

    猜你喜欢
    • 2015-03-27
    • 2016-11-09
    • 2018-06-17
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 2015-08-28
    • 2016-07-12
    • 1970-01-01
    相关资源
    最近更新 更多