简体   繁体   English

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

[英]OpenCV: how to detect and identify objects on solid color background using chroma key and contour detection

I have a camera (calibrated, warped with OpenCV) facing a flat surface top down.我有一个相机(校准,用 OpenCV 扭曲)面向一个平面自上而下。 The surface will be a single solid color.表面将是单一的纯色。

I want to be able to identify objects lying on the surface and determine what they are.我希望能够识别表面上的物体并确定它们是什么。 The objects are metal parts varying from 15mm to 100mm made of the same alloy (so same color).这些物体是由相同合金(因此颜色相同)制成的从 15 毫米到 100 毫米不等的金属部件。 The parts will generally be placed top down on the surface, but handling lying parts would be a nice to have.零件通常会自上而下放置在表面上,但处理躺着的零件会很不错。 What I have so far:到目前为止我所拥有的:

  1. Contour detection: (see attached image) is effective but very unreliable and jittery.轮廓检测:(见附图)是有效的,但非常不可靠和紧张。 Also cannot differentiate between similar sized parts or detect same part but rotated.也无法区分尺寸相似的零件或检测相同但旋转的零件。
  2. Template detection: might work but does not seem terribly robust.模板检测:可能有效,但似乎不是非常健壮。
  3. Cascade detection and custom cascade classifier: seems like this would work, but it just feels like overkill as my objects will always be on a solid contrasting background and seen from more or less the same camera angle.级联检测和自定义级联分类器:似乎这会起作用,但感觉有点矫枉过正,因为我的对象将始终位于对比鲜明的背景上,并且从或多或少相同的摄像机角度看到。

在此处输入图像描述

What my future setup should look like:我未来的设置应该是什么样子: 在此处输入图像描述

I want the algorithm to identify all 3 screws as screws in the easiest way possible, and return their outline in pixels.我希望算法以最简单的方式将所有 3 个螺钉识别为螺钉,并以像素为单位返回它们的轮廓。 I also want it to be able to differentiate between completely different screws or parts of similar colour and size.我还希望它能够区分完全不同的螺钉或颜色和尺寸相似的部件。

I am a noob in OpenCV, so I really would like to hear techniques with pro's and cons from people with experience.我是 OpenCV 的菜鸟,所以我真的很想听听有经验的人的优点和缺点的技术。 How would you approach this problem effectively?你将如何有效地解决这个问题?

Uncertain why this got downvoted, but after a week of experimenting, I found a really good way to find objects on a solid background in OpenCV:不确定为什么这被否决了,但经过一周的实验,我找到了一个非常好的方法来在 OpenCV 中的纯色背景上找到对象:

  1. Use chroma key correction to remove the background with function cv2.inRange使用色度键校正去除带有 function cv2.inRange 的背景

  2. Invert colours so that found objects are white and everything else is black with image = cv2.bitwise_not(image)反转颜色,以便找到的对象是白色的,其他一切都是黑色的 image = cv2.bitwise_not(image)

  3. Use contour detection with the cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE parameter as the 'EXTERNAL' parameter will not work: cv2.findContours(img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)使用带有 cv2.RETR_LIST、cv2.CHAIN_APPROX_NONE 参数的轮廓检测,因为“EXTERNAL”参数将不起作用:cv2.findContours(img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

  4. return both the area (number of pixels) and the bounding box of all found contours.返回所有找到的轮廓的区域(像素数)和边界框。 The combination of these is actually very powerful for identifying most 2D objects in my case.在我的案例中,这些组合对于识别大多数 2D 对象实际上非常强大。

  5. If you have an aruco tag or other element with known real world mm sizes in your picture, it becomes easy to convert the area to mm2.如果您的图片中有 aruco 标签或其他已知真实世界 mm 尺寸的元素,则将面积转换为 mm2 变得很容易。 Function for finding an aruco tag: Function 用于查找 aruco 标签:

    arucoDict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_4X4_50) arucoParams = cv2.aruco.DetectorParameters_create() (corners, ids, rejected) = cv2.aruco.detectMarkers(image, arucoDict, parameters=arucoParams) arucoDict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_4X4_50) arucoParams = cv2.aruco.DetectorParameters_create() (corners, ids, denied) = cv2.aruco.detectMarkers(image, arucoDict, parameters=arucoParams)

在此处输入图像描述

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

while True:而真:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM