我如何使用opencv python计算Lego积木的孔数? - python

我正在处理我的python项目,在这里我需要计算每个乐高积木装配中有多少个孔。我需要从哪个输入的.json文件中获取有关我需要计算哪个程序集的信息,如下所示:

"img_001": [
    {
        "red": "0",
        "blue": "2",
        "white": "1",
        "grey": "1",
        "yellow": "1"
    },
    {
        "red": "0",
        "blue": "1",
        "white": "0",
        "grey": "1",
        "yellow": "0"

所以我需要识别我必须按颜色计算的装配体。然后,我必须对砖组装中的孔和孔进行特别的组装。

这是我使用的图像示例:

我如何使用opencv python计算Lego积木的孔数? - python

我开始将图像更改为hsv颜色空间,并使用轨迹栏找到了每种颜色的遮罩。使用cv2.inRange可以得到例如红色的蒙版:
我如何使用opencv python计算Lego积木的孔数? - python
如您所见,反射光没有帮助。
在这一点上,我不知道该如何前进。我觉得我应该使用cv2.findContour来获取每个装配的轮廓。我当时在考虑直方图均衡化。要检测圈子,我想使用cv2.HoughCirclescv2.SimpleBloopDetector。但是我不知道如何检查每个区域有多少个砖块。输出只是特定装配体中的许多孔。
你能给我一些想法吗?哪些OpenCv功能可能在这里适用?您将如何解决这种图像处理问题?感谢您的回答。

python参考方案

这是一个简单但非常有趣的颜色分割练习。该主题已在所有地方广泛涉及,并围绕Stackoverflow散布了几个示例。在许多情况下,颜色分割在HSV颜色空间中效果最好。

在左下方的图像中,您可以看到带有蓝色孔的黄色砖的分割结果,只是表明该方法也检测到了它们。

在此答案中,我提供了检测黄色砖块并识别其中的孔所需的操作的高级概述。但是,它没有演示如何计算特定砖内的孔数,以免破坏作业。我故意遗漏了那部分,留给您一些工作。

这是我的方法的主要步骤:

预处理图像以提高分割效果:此处使用的技术称为色彩量化,将it reduces the numbers of colors in the image设置为〜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)

用大写字母拆分字符串,但忽略AAA Python Regex - python

我的正则表达式:vendor = "MyNameIsJoe. I'mWorkerInAAAinc." ven = re.split(r'(?<=[a-z])[A-Z]|[A-Z](?=[a-z])', vendor) 以大写字母分割字符串,例如:'我的名字是乔。 I'mWorkerInAAAinc”变成…

R'relaimpo'软件包的Python端口 - python

我需要计算Lindeman-Merenda-Gold(LMG)分数,以进行回归分析。我发现R语言的relaimpo包下有该文件。不幸的是,我对R没有任何经验。我检查了互联网,但找不到。这个程序包有python端口吗?如果不存在,是否可以通过python使用该包? python参考方案 最近,我遇到了pingouin库。

字符串文字中的正斜杠表现异常 - python

为什么S1和S2在撇号位置方面表现不同?S1="1/282/03/10" S2="4/107/03/10" R1="".join({"N\'" ,S1,"\'" }) R2="".join({"N\'…

查找字符串中的行数 - python

我正在创建一个python电影播放器​​/制作器,我想在多行字符串中找到行数。我想知道是否有任何内置函数或可以编写代码的函数来做到这一点:x = """ line1 line2 """ getLines(x) python大神给出的解决方案 如果换行符是'\n',则nlines …

将字符串分配给numpy.zeros数组[重复] - python

This question already has answers here: Weird behaviour initializing a numpy array of string data                                                                    (4个答案)         …