Найдите область с контентом и получите ее прямоугольник - PullRequest
2 голосов
/ 20 октября 2019

Я использую OpenCV 4 - python 3 - чтобы найти определенную область на черно-белом изображении.

Эта область не заполнена на 100%. Это может вызвать разрыв между белыми линиями.

Это базовое изображение, с которого я начинаю обработку: base

Это прямоугольник, который я ожидаю - сделанный с фотошопом -: expected

Результаты, полученные с грубыми линиями преобразования - не точные - wrong result

Итак, в основном я начинаю с первого изображения и ожидаю найти то, что вы видите во втором.

Есть идеи, как получить прямоугольник второго изображения?

Ответы [ 3 ]

3 голосов
/ 21 октября 2019

Я хотел бы представить подход, который может быть вычислительно менее затратным, чем решение в ответе fmw42 только с использованием функции nonzero NumPy. В основном, все ненулевые индексы для обеих осей найдены, а затем получены минимумы и максимумы. Поскольку здесь у нас есть двоичные изображения, этот подход работает довольно хорошо.

Давайте посмотрим на следующий код:

import cv2
import numpy as np

# Read image as grayscale; threshold to get rid of artifacts
_, img = cv2.threshold(cv2.imread('images/LXSsV.png', cv2.IMREAD_GRAYSCALE), 0, 255, cv2.THRESH_BINARY)

# Get indices of all non-zero elements
nz = np.nonzero(img)

# Find minimum and maximum x and y indices
y_min = np.min(nz[0])
y_max = np.max(nz[0])
x_min = np.min(nz[1])
x_max = np.max(nz[1])

# Create some output
output = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.rectangle(output, (x_min, y_min), (x_max, y_max), (0, 0, 255), 2)

# Show results
cv2.imshow('img', img)
cv2.imshow('output', output)
cv2.waitKey(0)
cv2.destroyAllWindows()

Я позаимствовал обрезанное изображение из ответа fmw42 в качестве ввода, и мойвывод должен быть одинаковым (или наиболее похожим):

Output

Надеюсь, что (также) помогает!

2 голосов
/ 20 октября 2019

В Python / OpenCV вы можете использовать морфологию, чтобы соединить все белые части вашего изображения, а затем получить внешний контур. Примечание. Я изменил ваше изображение, чтобы удалить части сверху и снизу из снимка экрана.

import cv2
import numpy as np

# read image as grayscale
img = cv2.imread('blackbox.png')

# convert to grayscale
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# threshold
_,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)

# apply close to connect the white areas
kernel = np.ones((75,75), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# get contours (presumably just one around the outside) 
result = img.copy()
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
    x,y,w,h = cv2.boundingRect(cntr)
    cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 2)

# show thresh and result    
cv2.imshow("thresh", thresh)
cv2.imshow("Bounding Box", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save resulting images
cv2.imwrite('blackbox_thresh.png',thresh)
cv2.imwrite('blackbox_result.png',result)


Ввод:

enter image description here

Изображение после морфологии:

enter image description here

Результат:

enter image description here

1 голос
/ 22 октября 2019

Вот небольшая модификация ответа @ fmw42 . Идея соединить нужные области в один контур очень похожа, однако вы можете найти ограничивающий прямоугольник напрямую, так как есть только один объект. Используя то же самое обрезанное входное изображение, вот результат.

enter image description here

Мы также можем извлечь ROI

enter image description here

import cv2

# Grayscale, threshold, and dilate
image = cv2.imread('3.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Connect into a single contour and find rect
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=1)
x,y,w,h = cv2.boundingRect(dilate)
ROI = original[y:y+h,x:x+w]
cv2.rectangle(image, (x, y), (x+w, y+h), (36, 255, 12), 2)

cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.waitKey()
...