如何使用opencv python计算乐高积木上的洞?

如何使用opencv python计算乐高积木上的洞?,python,opencv,image-processing,Python,Opencv,Image Processing,我正在做我的python项目,我需要计算每个乐高积木组件中有多少个洞。关于我将从input.json文件中获取需要计数的程序集的信息,该文件如下所示: "img_001": [ { "red": "0", "blue": "2", "white": "1", "grey": "1", "yellow": "1" }, { "red": "0", "blue":

我正在做我的python项目,我需要计算每个乐高积木组件中有多少个洞。关于我将从input.json文件中获取需要计数的程序集的信息,该文件如下所示:

"img_001": [
    {
        "red": "0",
        "blue": "2",
        "white": "1",
        "grey": "1",
        "yellow": "1"
    },
    {
        "red": "0",
        "blue": "1",
        "white": "0",
        "grey": "1",
        "yellow": "0"
因此,我需要识别我必须按颜色计数的部件。然后,我必须在特定的砖块装配中确定孔的数量和数量

这是我使用的图像示例:

我已经开始将我的图像更改为hsv颜色空间,并使用轨迹栏为每种颜色找到了一个遮罩。使用
cv2.inRange
我可以得到一个遮罩,例如红色: 正如你所看到的,反射光没有帮助。 在这一点上,我不知道如何才能前进。我觉得我应该使用
cv2.findContour
来获得每个组件的轮廓。我在想直方图均衡化在这里可能有用。要检测圆,我想使用
cv2.HoughCircles
或者
cv2.SimpleBloopDetector
。但我不知道如何检查每个区域有多少砖。输出只是特定部件中的若干孔。
你能给我一些想法吗?哪种OpenCv函数可能适用于此处?您将如何解决这种图像处理问题?感谢您的回答。

这是一个简单但非常有趣的颜色分割练习。这一主题已被广泛地覆盖在各地,并有几个例子流传开来。在许多情况下,颜色分割在HSV颜色空间中效果最好

在下面的左图中,您可以看到带有蓝色孔的黄色砖块的分割结果,只是为了表明它们也是通过这种方法检测到的

在这个回答中,我提供了检测黄砖所需操作的高级概述,并确定其中的漏洞。然而,它并没有演示如何计算特定砖块内的孔数,以避免破坏您的家庭作业。我故意把答案漏掉的那部分留给你做

以下是我的方法的主要步骤

  • 对图像进行预处理以提高分割效果:这里使用的技术称为颜色量化,可将图像分割为42种颜色。很难在下图中显示结果,但如果放大,它显示的颜色会比原始图像少:

  • 将预处理后的图像转换到HSV颜色空间,实现更好的颜色分割

  • 由于该方法仅关注黄砖的分割,因此该算法定义了黄色的低值和高值(以HSV为单位)以使用该范围对图像进行阈值设置:该范围外的任何颜色都将变为黑色像素。图像编辑器可以帮助您放大原始图像并检查像素的精确HSV值。以下是分段的结果:

  • 然后对分割后的图像进行处理,我们丢弃小斑点,只保留最大的斑点(即砖块)。在这个过滤机制之后,可以计算出有多少块黄砖。这里有一个妙招:如果您使用
    cv2.fillPoly()
    绘制一块砖的轮廓并用白色填充,您将能够在单独的图像中绘制整个砖,而不需要任何孔来创建遮罩。这很快就会派上用场的!下面是黄色面具的外观:

  • 在这个阶段,我们已经知道了图像中所有黄砖的位置。剩下要做的就是找出每一块砖上的洞。这就是遮罩的作用:如果你注意上面的两幅图像,分割图像和遮罩之间的区别主要是砖块上的洞:

  • 处理此图像的轮廓可以丢弃所有不符合孔条件的小斑点,只留下砖块的孔。我们可以在分割图像或原始图像上绘制孔的位置以显示它们:

总之,此代码提供了一个黄色砖块列表和另一个包含这些砖块中的孔的列表。从这一点上说,这取决于你。代码可以很容易地扩展到处理其他颜色的砖块。玩得开心:

import cv2
import numpy as np

# convertToOpenCVHSV():
#   converts from HSV range (H: 0-360, S: 0-100, V: 0-100)
#   to what OpenCV expects: (H: 0-179, S: 0-255, V: 0-255)
def convertToOpenCVHSV(H, S, V):
    return np.array([H // 2, S * 2.55, V * 2.55], np.uint8)


# 1. Load input image
img = cv2.imread('test_images/legos.jpg')

# 2. Preprocess: quantize the image to reduce the number of colors
div = 6
img = img // div * div + div // 2
cv2.imwrite('lego2_quantized.jpg', img)


# 3. Convert to HSV color space
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)


# 4. Segment the image using predefined values of yellow (min and max colors)
low_yellow = convertToOpenCVHSV(40, 35, 52)
high_yellow = convertToOpenCVHSV(56, 95, 93)
yellow_seg_img = cv2.inRange(hsv_img, low_yellow, high_yellow)
#cv2.imshow('yellow_seg_img', yellow_seg_img)
cv2.imwrite('lego4_yellow_seg_img.jpg', yellow_seg_img)

# 5. Identify and count the number of yellow bricks and create a mask with just the yellow objects
bricks_list = []
min_size = 5

contours, hierarchy = cv2.findContours(yellow_seg_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for contourIdx, cnt in enumerate(contours):
    # filter out tiny segments
    x, y, w, h = cv2.boundingRect(cnt)
    if (w < min_size) or (h < min_size):
        continue

    #print('contourIdx=', contourIdx, 'w=', w, 'h=', h)

    bricks_list.append(cnt)

    # debug: draw green contour in the original image
    #cv2.drawContours(img, cnt, -1, (0, 255, 0), 2) # green

print('Detected', len(bricks_list), 'yellow pieces.')

# Iterate the list of bricks and draw them (filled) on a new image to be used as a mask
yellow_mask_img = np.zeros((img.shape[0], img.shape[1]), np.uint8)
for cnt in bricks_list:
    cv2.fillPoly(yellow_mask_img, pts=[cnt], color=(255,255,255))

cv2.imshow('yellow_mask_img', yellow_mask_img)
cv2.imwrite('lego5_yellow_mask_img.jpg', yellow_mask_img)

# debug: display only the original yellow bricks found
bricks_img = cv2.bitwise_and(img, img, mask=yellow_mask_img)
#cv2.imshow('bricks_img', bricks_img)
cv2.imwrite('lego5_bricks_img.jpg', bricks_img)

# 6. Identify holes in each Lego brick
diff_img = yellow_mask_img - yellow_seg_img
cv2.imshow('diff_img', diff_img)
cv2.imwrite('lego6_diff_img.jpg', diff_img)

# debug: create new BGR image for debugging purposes
dbg_img = cv2.cvtColor(yellow_mask_img, cv2.COLOR_GRAY2RGB)
#dbg_img = bricks_img

holes_list = []
min_area_size = 10
max_area_size = 24
contours, hierarchy = cv2.findContours(yellow_seg_img, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
for contourIdx, cnt in enumerate(contours):
    # filter out tiny segments by area
    area = cv2.contourArea(contours[contourIdx])

    if (area < min_area_size) or (area > max_area_size):
        #print('contourIdx=', contourIdx, 'w=', w, 'h=', h, 'area=', area, '(ignored)')
        #cv2.drawContours(dbg_img, cnt, -1, (0, 0, 255), 2) # red
        continue

    #print('contourIdx=', contourIdx, 'w=', w, 'h=', h, 'area=', area)
    holes_list.append(cnt)

# debug: draw a blue-ish contour on any BGR image to show the holes of the bricks
for cnt in holes_list:
    cv2.fillPoly(dbg_img, pts=[cnt], color=(255, 128, 0))
    cv2.fillPoly(img, pts=[cnt], color=(255, 128, 0))

cv2.imwrite('lego6_dbg_img.jpg', dbg_img)
cv2.imwrite('lego6_img.jpg', img)

# 7. Iterate though the list of holes and associate them with a particular brick
# TODO

cv2.imshow('img', img)
cv2.imshow('dbg_img', dbg_img)
cv2.waitKey(0)
导入cv2
将numpy作为np导入
#converttoovhsv():
#从HSV范围(H:0-360,S:0-100,V:0-100)转换
#符合OpenCV的期望:(H:0-179,S:0-255,V:0-255)
def转换器至VHSV(高、低、低):
返回np.array([H//2,S*2.55,V*2.55],np.uint8)
# 1. 加载输入图像
img=cv2.imread('test_images/legos.jpg'))
# 2. 预处理:量化图像以减少颜色数量
div=6
img=img//div*div+div//2
cv2.imwrite('lego2_quantized.jpg',img)
# 3. 转换为HSV颜色空间
hsv_img=cv2.cvt颜色(img,cv2.COLOR_BGR2HSV)
# 4. 使用预定义的黄色值(最小和最大颜色)分割图像
低_黄色=VHSV(40、35、52)
高_黄色=VHSV(56、95、93)
黄色seg img=cv2.inRange(hsv img、低黄色、高黄色)
#cv2.imshow(“黄色分段img”,黄色分段img)
cv2.imwrite('lego4_yellow_seg_img.jpg',yellow_seg_img)
# 5. 识别并计算黄色砖块的数量,并仅使用黄色对象创建遮罩
砖块列表=[]
最小尺寸=5
轮廓,层次=cv2.已查找轮廓(黄色,cv2.RETR\u外部,cv2.链约无)
对于轮廓,枚举中的cnt(轮廓):
#过滤掉细小的片段
x、 y,w,h=cv2.boundingRect(cnt)
如果(w<最小尺寸)或(h<最小尺寸):
持续
#打印('contourIdx=',contourIdx',w=',w',h=',h)
砖块列表。附加(cnt)
#调试:在原始图像中绘制绿色轮廓
#cv2.绘制轮廓(img,cnt,-1,(0,255,0),2)#绿色
打印('检测到',len(砖块列表),'黄色块')
#迭代砖块列表,并在用作遮罩的新图像上绘制它们(填充)
黄色掩码=np.零((i