2016-09-09 4 views
6

Я следую этому вопросу:Python OpenCV сортировки контуры

How can I sort contours from left to right and top to bottom?

для сортировки контуров слева направо и сверху-вниз. Тем не менее, мои контуры найдены с помощью этого (OpenCV 3):

im2, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 

и они отформатированы, как это:

array([[[ 1, 1]], 

    [[ 1, 36]], 

    [[63, 36]], 

    [[64, 35]], 

    [[88, 35]], 

    [[89, 34]], 

    [[94, 34]], 

    [[94, 1]]], dtype=int32)] 

Когда я запускаю код

max_width = max(contours, key=lambda r: r[0] + r[2])[0] 
max_height = max(contours, key=lambda r: r[3])[3] 
nearest = max_height * 1.4 
contours.sort(key=lambda r: (int(nearest * round(float(r[1])/nearest)) * max_width + r[0])) 

я набираюсь ошибка

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

поэтому я изменил это так:

max_width = max(contours, key=lambda r: np.max(r[0] + r[2]))[0] 
max_height = max(contours, key=lambda r: np.max(r[3]))[3] 
nearest = max_height * 1.4 
contours.sort(key=lambda r: (int(nearest * round(float(r[1])/nearest)) * max_width + r[0])) 

, но теперь я получаю сообщение об ошибке:

TypeError: only length-1 arrays can be converted to Python scalars

EDIT:

После прочтения ответа ниже я изменил мой код:

EDIT 2

Это код, который я использую, чтобы "растянуть" персонажей и найти контуры

kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(35,35)) 

# dilate the image to get text 
# binaryContour is just the black and white image shown below 
dilation = cv2.dilate(binaryContour,kernel,iterations = 2) 

КОНЕЦ EDIT 2

im2, contours, hierarchy = cv2.findContours(dilation,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 

myContours = [] 

# Process the raw contours to get bounding rectangles 
for cnt in reversed(contours): 

    epsilon = 0.1*cv2.arcLength(cnt,True) 
    approx = cv2.approxPolyDP(cnt,epsilon,True) 

    if len(approx == 4): 

     rectangle = cv2.boundingRect(cnt) 
     myContours.append(rectangle) 

max_width = max(myContours, key=lambda r: r[0] + r[2])[0] 
max_height = max(myContours, key=lambda r: r[3])[3] 
nearest = max_height * 1.4 
myContours.sort(key=lambda r: (int(nearest * round(float(r[1])/nearest)) * max_width + r[0])) 

i=0 
for x,y,w,h in myContours: 

    letter = binaryContour[y:y+h, x:x+w] 
    cv2.rectangle(binaryContour,(x,y),(x+w,y+h),(255,255,255),2) 
    cv2.imwrite("pictures/"+str(i)+'.png', letter) # save contour to file 
    i+=1 

Контуры перед сортировкой:

[(1, 1, 94, 36), (460, 223, 914, 427), (888, 722, 739, 239), (35,723, 522, 228), 
(889, 1027, 242, 417), (70, 1028, 693, 423), (1138, 1028, 567, 643),  
(781, 1030, 98, 413), (497, 1527, 303, 132), (892, 1527, 168, 130), 
(37, 1719, 592, 130), (676, 1721, 413, 129), (1181, 1723, 206, 128), 
(30, 1925, 997, 236), (1038, 1929, 170, 129), (140, 2232, 1285, 436)] 

Контуры после сортировки:

(ПРИМЕЧАНИЕ. Это не порядок, я хочу, чтобы контуры должны быть отсортированы в см изображения в нижней части)

[(1, 1, 94, 36), (460, 223, 914, 427), (35, 723, 522, 228), (70,1028, 693, 423), 
(781, 1030, 98, 413), (888, 722, 739, 239), (889, 1027, 242, 417), 
(1138, 1028, 567, 643), (30, 1925, 997, 236), (37, 1719, 592, 130), 
(140, 2232, 1285, 436), (497, 1527, 303, 132), (676, 1721, 413, 129), 
(892, 1527, 168, 130), (1038, 1929, 170, 129), (1181, 1723, 206, 128)] 

Image Я работаю с

enter image description here

I хотите найти контуры в следующем порядке: enter image description here

Dilation image используется для определения контуров enter image description here

+0

Можете ли вы объяснить вашу цель? Что вам нужно в финальном выпуске? На основании чего вы хотите найти контуры по площади, по месту происхождения или по каким-либо другим критериям? – ZdaR

+0

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

+0

Вы можете написать код для создания 'dilation' please? –

ответ

-1

Похоже question вы связаны работы не с исходными контурами, но сначала получает ограничивающий прямоугольник, используя cv2.boundingRect. Только тогда имеет смысл рассчитать max_width и max_height.Выведенный код подсказывает, что вы пытаетесь сортировать необработанные контуры, а не ограничивать прямоугольники. Если это не так, можете ли вы предоставить более полный фрагмент кода, включая список нескольких контуров, которые вы пытаетесь сортировать?

5

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

def get_contour_precedence(contour, cols): 
    origin = cv2.boundingRect(contour) 
    return origin[1] * cols + origin[0] 

Это дает ранг для каждого контура в зависимости от происхождения контура. Он изменяется в значительной степени, когда два последовательных контура лежат вертикально, но изменяется незначительно, когда контуры уложены горизонтально. Итак, таким образом, сначала контуры будут сгруппированы от вершины к нижней, а в случае Clash будет использоваться меньшее значение варианта среди горизонтальных отложенных контуров.

import cv2 

def get_contour_precedence(contour, cols): 
    tolerance_factor = 10 
    origin = cv2.boundingRect(contour) 
    return ((origin[1] // tolerance_factor) * tolerance_factor) * cols + origin[0] 

img = cv2.imread("/Users/anmoluppal/Downloads/9VayB.png", 0) 

_, img = cv2.threshold(img, 70, 255, cv2.THRESH_BINARY) 

im, contours, h = cv2.findContours(img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 

contours.sort(key=lambda x:get_contour_precedence(x, img.shape[1])) 

# For debugging purposes. 
for i in xrange(len(contours)): 
    img = cv2.putText(img, str(i), cv2.boundingRect(contours[i])[:2], cv2.FONT_HERSHEY_COMPLEX, 1, [125]) 

enter image description here

Если вы видите близко, третий ряд, где 3, 4, 5, 6 контуры размещены 6 приходит от 3 до 5, Причина в том, что 6 го контура немного ниже линии 3, 4, 5 контуров.

Скажите, пожалуйста, вы хотите, чтобы выход был другим способом, мы можем настроить get_contour_precedence, чтобы получить 3, 4, 5, 6 исправленные ряды контуров.

+0

Да, мне нужно, чтобы контуры были в 3,4,5,6. Сортировка должна быть способна «игнорировать» немного более высокий контур и все еще сортировать в этом порядке. Помогло бы также сделать некоторую предварительную обработку так, чтобы контуры, найденные в одной строке, имели одинаковую высоту? –

+0

Добавьте значение допуска, чтобы удовлетворить ваши потребности. – ZdaR

Смежные вопросы