OpenCV:如何使用色度键和轮廓检测在纯色背景上检测和识别对象

2024-06-16 10:18:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个摄像头(经过校准,使用OpenCV扭曲),面向平面自上而下。 曲面将为单一纯色

我希望能够识别表面上的物体并确定它们是什么。 这些物体是由相同合金制成的15毫米到100毫米不等的金属零件(颜色相同)。零件通常会自上而下地放置在表面上,但处理躺着的零件将是一个很好的选择。到目前为止,我所拥有的:

  1. 轮廓检测:(见附图)是有效的,但非常不可靠和不稳定。也无法区分相似尺寸的零件或检测相同但旋转的零件
  2. 模板检测:可能有效,但似乎不太可靠
  3. 层叠检测和自定义层叠分类器:看起来这会起作用,但感觉太过分了,因为我的对象总是在一个坚实的对比背景上,从或多或少相同的相机角度看

enter image description here

我未来的设置应该是什么样的: enter image description here

我希望算法以最简单的方式将所有3个螺钉识别为螺钉,并以像素为单位返回它们的轮廓。我还希望它能够区分完全不同的螺钉或类似颜色和尺寸的零件

我是OpenCV的新手,所以我真的很想听听有经验的人的正反两方面的技巧。你将如何有效地解决这个问题


Tags: 面向颜色尺寸表面opencv平面区分物体
1条回答
网友
1楼 · 发布于 2024-06-16 10:18:35

不确定为什么会被否决,但经过一周的实验,我发现了一种在OpenCV中找到坚实背景上的对象的非常好的方法:

  1. 使用色度键校正功能cv2.inRange去除背景

  2. 反转颜色,使找到的对象为白色,其他所有对象为黑色,image=cv2。按位_not(image)

  3. 将轮廓检测与cv2.RETR\u列表、cv2.CHAIN\u近似值无参数一起使用,因为“外部”参数将不起作用:cv2.findContours(img、cv2.RETR\u列表、cv2.CHAIN\u近似值无)

  4. 返回所有找到轮廓的区域(像素数)和边界框。 在我的例子中,这两者的结合对于识别大多数2D对象来说是非常强大的

  5. 如果您的图片中有一个阿鲁科标签或其他具有已知真实世界mm尺寸的元素,则可以很容易地将面积转换为mm2。查找阿鲁科标签的功能:

    arucoDict=cv2.aruco.Dictionary\u get(cv2.aruco.DICT\u 4X4\u 50) arucoParams=cv2.aruco.DetectorParameters_create() (角点、ID、拒绝)=cv2.阿鲁科检测标记(图像、阿鲁科ICT、, 参数=arucoParams)

enter image description here

import cv2
import numpy as np

def getContours(img,imgContour):

""" DRAWS AND FINDS CONTOURS, THEN RETURNS a list of lists incl x0, y0, w, h"""

contour_list = []
contours, hierarchy = cv2.findContours(img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# print('contours:', contours)
for cnt in contours:
    area = cv2.contourArea(cnt)
    areaMin = 200
    if area > areaMin and area < 5000:
        cv2.drawContours(imgContour, cnt, -1, (255, 0, 0), 7)
        peri = cv2.arcLength(cnt, True)
        approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
        # print(len(approx))
        x , y , w, h = cv2.boundingRect(approx)
        print('contour bounding:', x,y,w,h)
        center_x = int(x + w/2)
        center_y = int(y + h/2)

        cv2.circle(imgContour,(center_x, center_y), 5, (0, 0, 255), 5)
        cv2.rectangle(imgContour, (x , y ), (x + w , y + h ), (0, 255, 0), 5)

        cv2.putText(imgContour, "Points: " + str(len(approx)), (x + w + 20, y + 20), cv2.FONT_HERSHEY_COMPLEX, .7,
                    (0, 255, 0), 2)
        cv2.putText(imgContour, "Area: " + str(int(area)), (x + w + 20, y + 45), cv2.FONT_HERSHEY_COMPLEX, 0.7,
                    (0, 255, 0), 2)

        if area < 3500:
            cv2.putText(imgContour, "THIS IS A SMALL PART" , (x + w + 20, y + 70), cv2.FONT_HERSHEY_COMPLEX, 0.7,
                        (0, 255, 0), 2)

        contour_list.append([x,y,w,h])

return contour_list

尽管如此:

img = cv2.imread('yellowcropped.jpg', 1)
image_original = img.copy()

lower_blue = np.array([160, 140, 15])  ##[R value, G value, B value]
upper_blue = np.array([255, 235, 60])


image_copy = np.copy(img)
image_copy = cv2.cvtColor(image_copy, cv2.COLOR_BGR2RGB)

mask = cv2.inRange(image_copy, lower_blue, upper_blue)
mask = cv2.bitwise_not(mask)
img = cv2.cvtColor(mask, cv2.COLOR_BGR2RGB)


# img = image
imgContour = image_original.copy()

getContours(mask,imgContour)
imgStack = stackImages(0.6,([mask],[imgContour]))

# cv2.imshow("Result", imgStack)
cv2.imshow('Img_contour', imgContour)
# cv2.setMouseCallback("Img_contour", mouse_callback)
if cv2.waitKey(1) & 0xFF == ord('q'):
    break

相关问题 更多 >