OpenCV обнаруживает один символ с несколькими ограничивающими прямоугольниками - PullRequest
0 голосов
/ 13 мая 2019

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

    img = cv2.imread(imgpath)

    morph = img.copy()
    morph = cv2.fastNlMeansDenoising(img)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
    morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
    morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 15))

    # take morphological gradient
    gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel)

    gray = cv2.cvtColor(gradient_image, cv2.COLOR_BGR2GRAY)

    img_grey = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel)

    blur = cv2.medianBlur(img_grey,3)


    ret, thing = cv2.threshold(blur, 0.0, 255.0, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

    img_dilation = cv2.dilate(thing, kernel, iterations=3)


    conturs_lst = cv2.findContours(img_dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

Пример реального результата:

enter image description here

OG Изображение:

enter image description here

1 Ответ

4 голосов
/ 13 мая 2019

У вас правильная идея, но я думаю, что вы злоупотребляете cv2.morphologyEx, чтобы постоянно разрушать и расширять изображение.Вы упоминаете о своей проблеме:

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

Когда вы используете cv2.findContours, он работает правильно, но так как ваши контуры на самом деле являются каплями, а не одним взаимосвязанным единичным изображением, он создает несколько ограничивающих рамок.Чтобы устранить эту проблему, вы можете расширить изображение, чтобы соединить капли вместе.

Я переписал ваш код без лишних cv2.morphologyEx повторений.Основная идея заключается в следующем:

  • Преобразование изображения в оттенки серого
  • Размытие изображения
  • Пороговое изображение для отделения фона от нужного объекта
  • РасширениеИзображение для подключения больших двоичных объектов для формирования единственного изображения
  • Поиск контуров и контуров фильтров с использованием минимальной / максимальной области порога

Пороговое изображение для выделения нужных участков.Обратите внимание, что некоторые контуры имеют разорванные соединения.Чтобы исправить это, мы расширяем изображение, чтобы соединить капли.

enter image description here

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

enter image description here

Результаты

enter image description here

enter image description here

import numpy as np
import cv2

original_image = cv2.imread("1.jpg")
image = original_image.copy()

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
thresh = cv2.threshold(blurred, 160, 255, cv2.THRESH_BINARY_INV)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
dilate = cv2.dilate(thresh, kernel , iterations=4)

cv2.imshow("thresh", thresh)
cv2.imshow("dilate", dilate)

# Find contours in the image
cnts = cv2.findContours(dilate.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

contours = []

threshold_min_area = 400
threshold_max_area = 3000

for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    area = cv2.contourArea(c)
    if area > threshold_min_area and area < threshold_max_area:
        # cv2.drawContours(original_image,[c], 0, (0,255,0), 3)
        cv2.rectangle(original_image, (x,y), (x+w, y+h), (0,255,0),1)
        contours.append(c)

cv2.imshow("detected", original_image) 
print('contours detected: {}'.format(len(contours)))
cv2.waitKey(0)
...