我正试图教我的自动化测试框架,以使用opencv在应用程序中检测选定的项目(该框架从被测设备获取帧/屏幕截图)。所选项目始终具有一定的大小,并且始终带有蓝色边框,这有帮助,但它们包含不同的缩略图。请参阅提供的示例图像。
我已经完成了很多关于该主题的搜索和阅读工作,并且对于一种情况(示例图像中的图像C),我已经接近使其工作了。 example image就是在所选项目上有播放符号的地方。
我的理论是OpenCV在这种情况下会感到困惑,因为播放符号基本上是带有三角形的圆形,并且我要它找到矩形。
我发现这非常有帮助:https://www.learnopencv.com/blob-detection-using-opencv-python-c/
我的代码如下:
import cv2
import numpy as np
img = "testimg.png"
values = {"min threshold": {"large": 10, "small": 1},
"max threshold": {"large": 200, "small": 800},
"min area": {"large": 75000, "small": 100},
"max area": {"large": 80000, "small": 1000},
"min circularity": {"large": 0.7, "small": 0.60},
"max circularity": {"large": 0.82, "small": 63},
"min convexity": {"large": 0.87, "small": 0.87},
"min inertia ratio": {"large": 0.01, "small": 0.01}}
size = "large"
# Read image
im = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()
# Change thresholds
params.minThreshold = values["min threshold"][size]
params.maxThreshold = values["max threshold"][size]
# Filter by Area.
params.filterByArea = True
params.minArea = values["min area"][size]
params.maxArea = values["max area"][size]
# Filter by Circularity
params.filterByCircularity = True
params.minCircularity = values["min circularity"][size]
params.maxCircularity = values["max circularity"][size]
# Filter by Convexity
params.filterByConvexity = False
params.minConvexity = values["min convexity"][size]
# Filter by Inertia
params.filterByInertia = False
params.minInertiaRatio = values["min inertia ratio"][size]
# Create a detector with the parameters
detector = cv2.SimpleBlobDetector(params)
# Detect blobs.
keypoints = detector.detect(im)
for k in keypoints:
print k.pt
print k.size
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures
# the size of the circle corresponds to the size of blob
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0, 0, 255),
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# Show blobs
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)
如何让OpenCV只查看由蓝色边框定义的外部形状而忽略内部形状(播放符号,当然还有缩略图)?我确信它一定是可行的。
答案 0 :(得分:0)
有很多不同的技术可以完成这项工作。我不太确定BlobDetector的工作方式,所以我采取了另一种方法。另外,我不确定自己需要什么,但是可以根据需要修改此解决方案。
import cv2
import numpy as np
from matplotlib.pyplot import figure
import matplotlib.pyplot as plt
img_name = "CbclA.png" #Image you have provided
min_color = 150 #Color you are interested in (from green channel)
max_color = 170
min_size = 4000 #Size of border you are interested in (number of pixels)
max_size = 30000
img_rgb = cv2.imread(img_name)
img = img_rgb[:,:,1] #Extract green channel
img_filtered = np.bitwise_and(img>min_color, img < max_color) #Get only colors of your border
nlabels, labels, stats, centroids = cv2.connectedComponentsWithStats(img_filtered.astype(np.uint8))
good_area_index = np.where(np.logical_and(stats[:,4] > min_size,stats[:,4] < max_size)) #Filter only areas we are interested in
for area in stats[good_area_index] : #Draw it
cv2.rectangle(img_rgb, (area[0],area[1]), (area[0] + area[2],area[1] + area[3]), (0,0,255), 2)
cv2.imwrite('result.png',img_rgb)
看看connectedComponentsWithStats
的文档注意:我正在使用Python 3
编辑:添加了结果图像
答案 1 :(得分:0)
如果我做对了,您想要一个矩形,该矩形将带有弯曲边缘的蓝色框界定为边界。如果是这样,这非常容易。 应用此-
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edged = cv2.Canny(gray, 75, 200) # You'll have to tune these
# Find contours
(_, contour, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# This should return only one contour in 'contour' in your case
这应该可以,但是如果您仍然获得带有弯曲边缘的轮廓(边界框),请应用此-
rect = cv2.approxPolyDP(contour, 0.02 * cv2.arcLength(contour, True), True)
# Play with the second parameter, appropriate range would be from 1% to 5%
答案 2 :(得分:0)
在阅读了您的建议后,我对此进行了更多的研究,发现斑点检测不是可行的方法。然而,如上所述,使用颜色识别来找到轮廓解决了该问题。再次感谢!
我的解决方案如下:
frame = cv2.imread("image.png")
color = ((200, 145, 0), (255, 200, 50))
lower_color = numpy.array(color[0], dtype="uint8")
upper_color = numpy.array(color[1], dtype="uint8")
# Look for the color in the frame and identify contours
color = cv2.GaussianBlur(cv2.inRange(frame, lower_color, upper_color), (3, 3), 0)
contours, _ = cv2.findContours(color.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
for c in contours:
rectangle = numpy.int32(cv2.cv.BoxPoints(cv2.minAreaRect(c)))
# Draw a rectangular frame around the detected object
cv2.drawContours(frame, [rectangle], -1, (0, 0, 255), 4)
cv2.imshow("frame", frame)
cv2.waitKey(0)
cv2.destroyAllWindows()