Обнаружение нескольких цветных областей на изображении и производство отдельных культур для каждого - PullRequest
4 голосов
/ 25 октября 2019

У меня есть изображение , например:

enter image description here

И я хочу обрезать изображениевезде есть красный .

Итак, с этим изображением я бы хотел произвести 4 урожая :

enter image description here

Очевидно, мне сначала нужно определить, где на изображении есть красный . Я могу сделать следующее:

import cv2
import numpy as np
from google.colab.patches import cv2_imshow

## (1) Read and convert to HSV
img = cv2.imread("my_image_with_red.png")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

## (2) Find the target red region in HSV
hsv_lower = np.array([0,50,50])
hsv_upper = np.array([10,255,255])
mask = cv2.inRange(hsv, hsv_lower, hsv_upper)

## (3) morph-op to remove horizone lines
kernel = np.ones((5,1), np.uint8)
mask2 = cv2.morphologyEx(mask, cv2.MORPH_OPEN,  kernel)


## (4) crop the region
ys, xs = np.nonzero(mask2)
ymin, ymax = ys.min(), ys.max()
xmin, xmax = xs.min(), xs.max()

croped = img[ymin:ymax, xmin:xmax]

pts = np.int32([[xmin, ymin],[xmin,ymax],[xmax,ymax],[xmax,ymin]])
cv2.drawContours(img, [pts], -1, (0,255,0), 1, cv2.LINE_AA)


cv2_imshow(croped)
cv2_imshow(img)
cv2.waitKey()

Что дает следующий результат :

enter image description here

Ограничениекоробка покрывает всю область, содержащую красный.

Как я могу получить ограничивающие рамки вокруг каждого красного фрагмента изображения? Я посмотрел на несколько масок , но это не похоже на работу.

Я ищу:

  • обнаружение каждое красное пятно на изображении;
  • вернуть границы на каждую красную точку;
  • использовать эти границы для получения 4 отдельных культур в качестве новых изображений.

1 Ответ

7 голосов
/ 25 октября 2019

В настоящее время существует несколько проблем:

  1. Если вы посмотрите на свое изображение маски, вы увидите, что все следы красного цвета зафиксированы на маске, включая небольшой шум. В настоящее время вы используете np.nonzero(), который захватывает все белые пиксели. Это то, что заставляет ограничивающий прямоугольник покрывать всю область. Чтобы исправить это, мы можем увеличить нижний порог hsv, чтобы получить результирующую маску:

enter image description here

Обратите внимание, что все еще много мелкихсгустки. Ваш вопрос должен быть перефразирован в

Как обрезать большие красные области?

Если вы хотите захватить все красных областей, вы будетеполучить гораздо больше, чем 4 урожая. Таким образом, чтобы исправить это, мы выполним морфологические операции, чтобы удалить небольшой шум и оставить только большие ярко выраженные красные области. Это приводит к маске изображения, которое содержит большие области

enter image description here

Вам не нужно использовать несколько масок

Как получить ограничивающие рамки вокруг каждого красного фрагмента изображения?

Это можно сделать с помощью cv2.findContours() на изображении маски для возврата ограничивающих прямоугольников каждой красной точки.

enter image description here

О? Это не ваш желаемый результат. Поскольку желаемый результат имеет пространство вокруг каждой красной точки, мы также должны добавить offset к ограничивающему прямоугольнику. После добавления смещения, вот наш результат

enter image description here

Поскольку у нас есть ограничивающие прямоугольники, мы можем просто использовать срез Numpy для извлечения и сохранения каждого ROI. Вот сохраненные области интереса

enter image description here


Итак, подведем итог, чтобы обнаружить каждое красное пятно на изображении, мы можем использовать пороговое определение цвета HSV. Обратите внимание, что это вернет всех пикселей, которые соответствуют этому пороговому значению, которое может отличаться от ожидаемого, поэтому необходимо выполнить морфологические операции для фильтрации полученной маски. Чтобы получить ограничивающие прямоугольники на каждом красном шарике, мы можем использовать cv2.findContours(), который даст нам ROI с использованием cv2.boundingRect(). Как только мы получим ROI, мы добавим смещение и извлечем ROI, используя срез Numpy.

import cv2
import numpy as np

image = cv2.imread("1.png")
original = image.copy()
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

hsv_lower = np.array([0,150,50])
hsv_upper = np.array([10,255,255])
mask = cv2.inRange(hsv, hsv_lower, hsv_upper)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=1)

cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
offset = 20
ROI_number = 0
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(image, (x - offset, y - offset), (x + w + offset, y + h + offset), (36,255,12), 2)
    ROI = original[y-offset:y+h+offset, x-offset:x+w+offset]

    cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)
    ROI_number += 1

cv2.imshow('mask', mask)
cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.waitKey()
...