Работа с контурами и ограничивающим прямоугольником в OpenCV 2.4 – python 2.7

Я работаю с openCv и python, и я имею дело со структурным анализом и дескрипторами формы. Я нашел этот блог: http://opencvpython.blogspot.it/2012/06/contours-2-brotherhood.html это очень полезно, и я попытался с черно-белым изображением нарисовать ограничивающий прямоугольник, и это работает. Но теперь из изображения я извлекаю, например, желтый цвет, и на нем я хотел бы нарисовать ограничивающий прямоугольник. Проблема в том, что черно-белое изображение неоднородно, в нем есть шумы, и поэтому код не распознает всю форму.

оригинальное изображение

черно-белое изображение

финальное изображение

И это код:

import numpy as np
import cv2

im = cv2.imread('shot.bmp')
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
COLOR_MIN = np.array([20, 80, 80],np.uint8)
COLOR_MAX = np.array([40, 255, 255],np.uint8)
frame_threshed = cv2.inRange(hsv_img, COLOR_MIN, COLOR_MAX)
imgray = frame_threshed
ret,thresh = cv2.threshold(frame_threshed,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[0]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.waitKey()
cv2.destroyAllWindows()

person Gianfra    schedule 14.05.2013    source источник


Ответы (1)


Поскольку ваше исходное изображение довольно шумное, простое исправление состоит в том, чтобы удалить часть шума с помощью cv2.medianBlur(). Это удалит небольшие области шума в исходном изображении и оставит вам только один контур. Первые несколько строк вашего кода будут выглядеть так:

im = cv2.imread('shot.bmp')
im = cv2.medianBlur(im,5)    # 5 is a fairly small kernel size
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)

Однако этот метод не самый надежный, потому что вы должны вручную указать размер ядра, а строка cnt=contours[0] в вашем коде предполагает, что интересующий контур является первым в списке контуров, что верно только в том случае, если контур только один. . Более надежным методом является предположение, что вас интересует самый большой контур, который позволит вам компенсировать даже умеренный шум.

Для этого добавьте строки:

# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]

после строки:

contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

В результате получается этот код:

import numpy as np
import cv2

im = cv2.imread('shot.bmp')
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
COLOR_MIN = np.array([20, 80, 80],np.uint8)
COLOR_MAX = np.array([40, 255, 255],np.uint8)
frame_threshed = cv2.inRange(hsv_img, COLOR_MIN, COLOR_MAX)
imgray = frame_threshed
ret,thresh = cv2.threshold(frame_threshed,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]

x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.waitKey()
cv2.destroyAllWindows()

Оба этих метода дают результат с правильной ограничивающей рамкой:

Результат ограничивающей рамки

Примечание
Начиная с OpenCV 3.x метод findContours() возвращает 3 результата (как видно здесь), поэтому дополнительное возвращаемое значение должно быть получено следующим образом:

_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPL‌​E)
person Aurelius    schedule 06.07.2013
comment
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) должен быть новым синтаксисом на тот случай, если кто-то столкнется с сообщением об ошибке: too many values to unpack если вы используете opencv 3 и python 3. См. ссылку: stackoverflow.com/questions/25504964/ - person Puriney; 30.05.2017
comment
Я считаю комментарий @Puriney действительно важным, так как в SO есть несколько других вопросов, возникших из-за этой проблемы. Вопрос должен быть отредактирован, чтобы включить так - person DarkCygnus; 05.07.2017
comment
Проголосовал за этот ответ, потому что это была первая помощь, которую я нашел о cv2.boundingRect и возвращаемом им значении. В документации OpenCV отсутствуют многие важные мелкие детали, подобные этому... - person Przemek D; 26.06.2018
comment
Любая идея, как это можно изменить, чтобы найти повернутый ограничивающий прямоугольник? - person Austin; 16.03.2019