Opencv может обнаружить один из двух прямоугольников разных размеров в одной и той же бумаге - PullRequest
1 голос
/ 21 марта 2020

Я новичок в OpenCV и создаю систему OMR (Optical Mark Recognition) в Java, чтобы определить ответы на листе с несколькими вариантами ответов. Я создал форму, состоящую из одного большого прямоугольника, который используется для ответа на вопросы путем рисования правильного круга и одного меньшего прямоугольника, который предназначен для определения уникального числа, которое является идентификатором того, кто отвечает. Вот изображение формы: Multiple choice sheet

Теперь моя программа определяет верхний прямоугольник AM, но не может определить больший. Мое изображение проходит через 6 этапов 1-го расширения, 2-го серого, 3-го порога, 4-го размытия, 5-го канни и 6-го адаптивного порога. Здесь вы можете видеть, что

    dilated1 = new Mat(source1.size(), CV_8UC1);
    dilate(source1, dilated1, getStructuringElement(MORPH_RECT, new Size(3, 3)));

    gray1 = new Mat(dilated1.size(), CV_8UC1);
    cvtColor(dilated1, gray1, COLOR_BGR2GRAY);

    thresh1 = new Mat(gray1.rows(), gray1.cols(), gray1.type());
    threshold(gray1, thresh1, 0, 255, THRESH_BINARY + THRESH_OTSU );

    blur1 = new Mat(thresh1.size(), CV_8UC1);
    blur(gray1, blur1, new Size(5.,5.));

    canny1 = new Mat(blur1.size(), CV_8UC1);
    Canny(blur1, canny1,160, 80);

    adaptiveThresh1 = new Mat(canny1.rows(), gray1.cols(), gray1.type());
    adaptiveThreshold(canny1, adaptiveThresh1, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11,2);

Я также использую findContours как этот

findContours(adaptiveThresh1.clone(), contours1, hierarchy1, RETR_TREE, CHAIN_APPROX_SIMPLE);

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

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

1 Ответ

0 голосов
/ 22 марта 2020

Вы можете найти самый большой контур и второй по величине контур.

Предлагаемые этапы:

  • Преобразование изображения в оттенки серого (как вы сделали).
  • Нарисуйте толстый белый прямоугольник вокруг изображения - убедитесь, что вокруг нет черного контура изображение.
  • Применить порог и преобразовать в двоичный файл (как вы сделали).
    Код, который я разместил, также имеет обратную полярность, чтобы контуры были белыми.
  • Поиск контуров.
    Используйте RETR_EXTERNAL вместо RETR_TREE, поскольку вам не нужно находить контуры внутри контуров.
  • Выполните итерации контуров и найдите контур с самая большая область, и та, которая занимает вторую по величине область.
    Контуры с самой большой областью - это нижний прямоугольник.
    Контуры со второй по величине областью - это верхний прямоугольник.

Вот реализация Python (не JAVA, но достаточно близко):

import cv2

# Read input image
img = cv2.imread('image.png')

# Draw thick rectangle around the image - making sure there is not black contour around the image
cv2.rectangle(img, (0, 0), (img.shape[1], img.shape[0]), (255, 255, 255), thickness = 5)

# Convert from BGR to Grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Apply threshold on gray image - use automatic threshold algorithm (use THRESH_OTSU) and invert polarity.
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# Find contours
cnts, heir = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)


max_a = 0  # Maximum area
smax_a = 0 # Second maximum area

max_c = []  # Contour with maximum area
smax_c = [] # Contour with second maximum area (maximum excluding max_c)

# Iterate contours
for c in cnts:
    area = cv2.contourArea(c)
    if area > max_a:    # If area is grater than maximum, second max = max, and max = area
        smax_a = max_a
        smax_c = max_c  # Second max contour gets maximum contour
        max_a = area
        max_c = c       # Maximum contour gets c
    elif area > smax_a: # If area is grater than second maximum, replace second maximum
        smax_a = area
        smax_c = c

#Get bounding rectangle of contour with maximum area, and mark it with green rectangle
x, y, w, h = cv2.boundingRect(max_c)
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), thickness = 2)

#Get bounding rectangle of contour with second maximum area, and mark it with blue rectangle
x, y, w, h = cv2.boundingRect(smax_c)
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), thickness = 2)

# Show result (for testing).
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Результат:
enter image description here

...