【发布时间】:2014-03-28 06:00:15
【问题描述】:
我正在做一个使用 OpenCV 检测形状及其颜色的项目。
有 5 种颜色(红色、绿色、黄色、蓝色和白色)和 4 种形状(矩形、星形、圆形和心形)。当使用的图像是像this 这样的绘制图像时,我已经能够可靠地辨别颜色并且可以检测到形状 使用此代码。请注意,图片仅用于演示,我的代码中的范围值不适用于这些颜色。
import cv2
import numpy as np
class Shape():
def __init__(self, color, shape, x, y, approx):
self.color = color
self.shape = shape
self.x = x
self.y = y
self.approx = approx
def closing(mask):
kernel = np.ones((7,7),np.uint8)
closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
return closing
def opening(mask):
kernel = np.ones((6,6),np.uint8)
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
return opening
#Define Red
lower_red = np.array([0, 90, 60], dtype=np.uint8)
upper_red = np.array([10, 255, 255], dtype=np.uint8)
red = [lower_red, upper_red, 'red']
#Define Green
lower_green = np.array([60, 55, 0], dtype=np.uint8)
upper_green = np.array([100, 255, 120], dtype=np.uint8)
green = [lower_green, upper_green, 'green']
#Define Blue
lower_blue = np.array([90, 20, 60], dtype=np.uint8)
upper_blue = np.array([130, 255, 180], dtype=np.uint8)
blue = [lower_blue, upper_blue, 'blue']
#Define Yellow
lower_yellow = np.array([5, 110, 200], dtype=np.uint8)
upper_yellow = np.array([50, 255, 255], dtype=np.uint8)
yellow = [lower_yellow, upper_yellow, 'yellow']
#Define White
lower_white = np.array([0, 90, 60], dtype=np.uint8)
upper_white = np.array([10, 255, 255], dtype=np.uint8)
white = [lower_white, upper_white ,'white']
colors = [red, green, blue, yellow, white]
def detect_shapes(image_location):
#Open image
img = cv2.imread(image_location)
#Convert to hsv
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
#Shape list
shapes = []
#Lay over masks and detect shapes
for color in colors:
mask = cv2.inRange(hsv, color[0], color[1])
mask = closing(mask)
mask = opening(mask)
contours, h = cv2.findContours(mask, 1, cv2.CHAIN_APPROX_SIMPLE)
contours.sort(key = len)
for contour in contours[-3:]:
#Amount of edges
approx = cv2.approxPolyDP(contour, 0.01*cv2.arcLength(contour, True), True)
#Center locations
M = cv2.moments(contour)
if M['m00'] == 0.0:
continue
centroid_x = int(M['m10']/M['m00'])
centroid_y = int(M['m01']/M['m00'])
if len(approx) == 4:
shape_name = 'rectangle'
elif len(approx) == 10:
shape_name = 'star'
elif len(approx) >= 11:
shape_name = 'oval'
else:
shape_name ='undefined'
shape = Shape(color[2], shape_name, centroid_x, centroid_y, len(approx))
shapes.append(shape)
return shapes
这主要基于this question 上的答案。
但是,当我尝试检测实际照片上的形状时,我无法可靠地使用它。我得到的边缘数量变化很大。 This 是我需要识别其形状的照片示例。 我猜这是因为形状边缘的小瑕疵造成的,但我不知道如何用直线逼近这些边缘,或者如何可靠地识别圆形。我需要在代码中进行哪些更改才能做到这一点?密集的谷歌搜索还没有给我答案,但这可能是因为我在搜索中没有使用正确的术语......
另外,如果这个问题的格式不正确,请告诉我!
【问题讨论】:
-
在计算
approx时使用大于0.01的数字可能会更好。但是,您可能会遇到圆形组件的问题,最好单独处理。 -
@Habba 试试Convex Hull
-
@Haris 这可能适用于圆形和矩形,但可以识别星星吗?或者我应该寻找五边形吗?
-
@Habba 如果您没有复杂的形状,您可以继续使用 approxPolyDP() ,您将为星形设置另外 15 个点,请参阅我得到的 result,这里绿色是检测到的形状.
-
@Haris 哇,看起来真不错。你能解释一下你做了什么吗?首先是凸包,然后是近似PolyDP?还是坎尼?我已经阅读了相关内容,但不知道它是否对这个问题有用。