2017-08-24 43 views
2

我的目标是编写一个玩扫雷机的机器人,但当我想告诉机器人,正方形在哪里时,我被卡住了。我尝试了很多不同的功能。 首先,我的工具抓取预定义区域的屏幕截图。这张照片看起来是这样的: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

+0

不是在opencv中的这个样本做到这一点吗? https://github.com/opencv/opencv/blob/master/samples/python/squares.py – BoboDarph

+0

这是我第一次使用的方法,并在你的答案,而我保存图像后,我的功能与这个例子做了我得到回答我想。几天前squares.py给了我5000点的巨大名单,每个角落都有10个不同的点。但几秒钟前,我想到了正确的答案。现在我只需要厚点的中心点,从squares.py第51行开始画。谢谢 – robinarthur

回答

1

我不知道扫雷是什么,但从我的理解,你想知道哪些瓷砖是蓝色,然后对你的numpy数组进行必要的修改(纠正我,如果它的东西,我会编辑或删除答案)。

下面是输出使四个区域的蓝色后:

enter image description here

我干了什么?

首先,我设定了蓝色,在范围内找到与您的瓷砖大致相同的轮廓。

发现自己的中心,看看他们遵循什么模式 -

enter image description here

他们都被一些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是我的数组。

+0

是的,你做到了,我想我明白了你的做法。 我只有2个问题: - 你的“坐标”中的值只是瓷砖的中心坐标或所有拐角的坐标? - 你为什么选择了蓝色的范围?来自典型opencv示例的“正常”upper_blue/lower_blue(HSV色彩空间)还是我的蓝色瓷砖的特殊值? – robinarthur

+0

只有现在的中心。这就够了。你可以为中心添加一个范围,但这是多余的我想。我对HSV中的图像进行阈值处理,因为如果在图像中后面还有其他类似的灰度级事物,则直接灰度阈值可能会使其损坏。 lower_red = np.array([100,80,50])。你可以玩一些不要被那个图像中的蓝色误导。这只是一个空白阵列(255,0,0),用于在hsv范围内的一些蓝色瓦片 –

+0

谢谢,我做到了。接下来的几天我会用我最终解决问题的代码回答这个问题。要找到正确的像素值并将其提供给opencv真的很难,因为rgb/bgr和hsv :-)但现在我做到了。 – robinarthur

0

这是我使用的代码。最后,我必须重新排列我的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

相关问题