Opencv/python - 我如何获得图像处理后检测到的区域的坐标
我的目标是编写一个玩扫雷机的机器人,但当我想告诉机器人,正方形在哪里时,我被卡住了。我尝试了很多不同的功能。 首先,我的工具抓取预定义区域的屏幕截图。这张照片看起来是这样的:screenshot of game boardOpencv/python - 我如何获得图像处理后检测到的区域的坐标
后,我要填补这样一个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 square检测器,我从例子中得到了一个包含检测点的巨大列表(一个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
在这里,我试图做一个为了遍历拉普拉斯算子来检查像素是否是蓝色的,并且将第一个像素作为锚点告诉机器人,从锚点(起始点)开始,在x方向上和x方向上每x个像素有一个正方形年。但有没有更好的方法来自动执行它?
但我的主要问题是如何将图像处理后的方块连接成一个numpy数组,我可以告诉机器人click_square(1,2),他知道至少有第1行和第2列的方块。
提示:我的坐标系在屏幕的左上角开始。
谢谢你的帮助。 Robinarthur
我不知道扫雷是什么,但从我的理解,你想知道哪些瓷砖是蓝色,然后对你的numpy数组进行必要的修改(纠正我,如果它的东西,我会编辑或删除答案)。
下面是输出使四个区域的蓝色后:
我干了什么?
首先,我设定了蓝色,在范围内找到与您的瓷砖大致相同的轮廓。
发现自己的中心,看看他们遵循什么模式 -
他们都被一些55-57像素(包括x,y坐标)分离。休息很简单。
for i in range(len(coords)):
np_arr[int(coords[i][1]/57)][int(coords[i][0]/57)]=0
蓝色瓷砖坐标存储在坐标中,np_arr是我的数组。
是的,你做到了,我想我明白了你的做法。 我只有2个问题: - 你的“坐标”中的值只是瓷砖的中心坐标或所有拐角的坐标? - 你为什么选择了蓝色的范围?来自典型opencv示例的“正常”upper_blue/lower_blue(HSV色彩空间)还是我的蓝色瓷砖的特殊值? – robinarthur
只有现在的中心。这就够了。你可以为中心添加一个范围,但这是多余的我想。我对HSV中的图像进行阈值处理,因为如果在图像中后面还有其他类似的灰度级事物,则直接灰度阈值可能会使其损坏。 lower_red = np.array([100,80,50])。你可以玩一些不要被那个图像中的蓝色误导。这只是一个空白阵列(255,0,0),用于在hsv范围内的一些蓝色瓦片 –
谢谢,我做到了。接下来的几天我会用我最终解决问题的代码回答这个问题。要找到正确的像素值并将其提供给opencv真的很难,因为rgb/bgr和hsv :-)但现在我做到了。 – robinarthur
这是我使用的代码。最后,我必须重新排列我的Dataframe,但仅限于更好的人类阅读。我认为我的代码有很多可能的改进,但我很高兴我的代码的行为足以满足我的需求。
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()
谢谢大家的帮忙! Robinarthur
不是在opencv中的这个样本做到这一点吗? https://github.com/opencv/opencv/blob/master/samples/python/squares.py – BoboDarph
这是我第一次使用的方法,并在你的答案,而我保存图像后,我的功能与这个例子做了我得到回答我想。几天前squares.py给了我5000点的巨大名单,每个角落都有10个不同的点。但几秒钟前,我想到了正确的答案。现在我只需要厚点的中心点,从squares.py第51行开始画。谢谢 – robinarthur