Как я могу считать отверстия на кирпичах Le go, используя opencv python? - PullRequest
3 голосов
/ 31 января 2020

Я работаю над проектом python, в котором мне нужно посчитать, сколько отверстий в каждой сборке брикетов Le go. Информацию о том, какую сборку мне нужно сосчитать, я возьму из файла ввода. json, который выглядит следующим образом:

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

Поэтому мне нужно распознать, какую сборку мне нужно посчитать по цветам. Тогда мне нужно и количество отверстий в конкретной сборке брикетов.

Это пример изображения, с которым я работаю:

This is example of image that I work with

Я начал с изменения своего изображения на цветовое пространство hsv и с помощью трекбара я нашел маску для каждого цвета. Используя cv2.inRange, я получаю маску, например, для красного цвета: mask for red color without any filter Как видите, отражение света не помогает. На данный момент я не знаю, как я мог двигаться вперед. Я чувствую, что должен использовать cv2.findContour, чтобы получить контур каждой сборки. Я думал, что выравнивание гистограммы может быть полезным здесь. Для обнаружения кругов я хочу использовать cv2.HoughCircles или, возможно, cv2.SimpleBloopDetector. Но я понятия не имею, как я могу проверить, сколько у меня есть брикетов в каждой области. Выход - это просто количество отверстий в конкретной сборке. Не могли бы вы дать мне несколько идей? Какая функция OpenCv может здесь применяться? Как бы вы решили эту проблему обработки изображений? Спасибо за ваши ответы.

1 Ответ

3 голосов
/ 04 февраля 2020

Это простое, но очень интересное упражнение цветовой сегментации . Эта топика c была широко освещена повсеместно с несколькими примерами, разбросанными по Stackoverflow . На многих сценариях ios цветовая сегментация лучше всего работает в цветовом пространстве HSV.

На левом изображении ниже вы можете увидеть результат сегментации желтого кирпича с отверстиями blue-i sh, просто чтобы показать, что они также были обнаружены этим подходом.

image image

В этом ответе я предоставлю общий обзор операций, необходимых для обнаружения желтых кирпичей и определения отверстий в них. Однако он не демонстрирует, как подсчитать количество отверстий внутри конкретного кирпича, чтобы не испортить домашнюю работу. Эта часть, которую я специально исключил из ответа, чтобы оставить для вас какую-то работу.

Вот основные этапы моего подхода :

  • Предварительная обработка изображение для улучшения сегментации: метод, используемый здесь, называется квантование цвета и , оно уменьшает количество цветов в изображении до ~ 42 цветов. Трудно представить результат на изображении ниже, но при увеличении он отображает меньше цветов, чем исходное изображение:

image

  • Преобразовать предварительно обработанное изображение в цветовом пространстве HSV для достижения лучшей сегментации по цвету.

  • Поскольку этот подход фокусируется только на сегментации желтого кирпича, алгоритм определяет низкие и высокие значения желтого (в HSV) для порогового изображения с использованием этого диапазона: любой цвет вне диапазона становится черными пикселями. Редактор изображений может помочь вам увеличить исходное изображение и проверить точные значения HSV пикселей. Вот результат сегментации:

image

  • Затем сегментированное изображение обрабатывается, и мы отбрасываем маленькие капли, чтобы сохранить только самые большие ( т.е. кирпичи). После этого механизма фильтрации можно подсчитать, сколько желтых кирпичей. Здесь есть хитрый трюк: если вы нарисуете контур кирпича, используя cv2.fillPoly(), и заполните его белым, вы сможете нарисовать весь кирпич без каких-либо отверстий в отдельном изображении, чтобы создать маску. Это пригодится очень скоро! Вот как выглядит желтая маска:

image

  • На этом этапе у нас уже есть расположение всех желтых кирпичей на изображении. Осталось только определить отверстия в каждом кирпиче. Вот тут и появляется маска: если вы обратите внимание на два изображения выше, разница между сегментированным изображением и маской состоит в основном из отверстий кирпичей:

image

  • Обработка контуров этого изображения позволяет отбросить все маленькие капли, которые не относятся к дырам, оставляя только дыры в кирпичах. Мы можем нарисовать расположение отверстий над сегментированным изображением или над исходным изображением, чтобы отобразить их:

image image

Таким образом, этот код предлагает список желтые кирпичи и другой список, который содержит отверстия в этих кирпичах. С этого момента это зависит от вас. Код может быть легко расширен для обработки кирпичей других цветов. Веселитесь:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...