Python opencv sorting contours
<p>I am following this question:</p>

<p><a href="http://stackoverflow.com/questions/38654302/how-can-i-sort-contours-from-left-to-right-and-top-to-bottom">How can I sort contours from left to right and top to bottom?</a></p>

<p>to sort contours from left-to-right and top-to-bottom. However, my contours are found using this (OpenCV 3):</p>

<pre><code>im2, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
</code></pre>

<p>and they are formatted like this:</p>

<pre><code>   array([[[ 1,  1]],

   [[ 1, 36]],

   [[63, 36]],

   [[64, 35]],

   [[88, 35]],

   [[89, 34]],

   [[94, 34]],

   [[94,  1]]], dtype=int32)]
</code></pre>

<p>When I run the code </p>

<pre><code>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]))
</code></pre>

<p>I am getting the error </p>

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

<p>so I changed it to this:</p>

<pre><code>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]))
</code></pre>

<p>but now I am getting the error:</p>

<p><code>TypeError: only length-1 arrays can be converted to Python scalars</code></p>

<p><strong>EDIT:</strong></p>

<p>After reading the answer below I modified my code:</p>

<p><strong>EDIT 2</strong></p>

<p>This is the code that I use to "dilate" the characters and find the contours</p>

<pre><code>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)
</code></pre>

<p><strong>END OF EDIT 2</strong></p>

<pre><code>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
</code></pre>

<p>Contours before sorting:</p>

<pre><code>[(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)]
</code></pre>

<p>Contours after sorting:</p>

<p>(<strong>NOTE:</strong> This is not the order I want the contours to be sorted in. Refer to image at the bottom)</p>

<pre><code>[(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)]
</code></pre>

<p>Image I am working with</p>

<p><a href="http://i.stack.imgur.com/9VayB.png" rel="nofollow"><img src="http://i.stack.imgur.com/9VayB.png" alt="enter image description here"></a></p>

<p>I want to find the contours in the following order:
<a href="http://i.stack.imgur.com/s4jKm.png" rel="nofollow"><img src="http://i.stack.imgur.com/s4jKm.png" alt="enter image description here"></a></p>

<p>Dilation image used for finding contours
<a href="http://i.stack.imgur.com/sTyvW.png" rel="nofollow"><img src="http://i.stack.imgur.com/sTyvW.png" alt="enter image description here"></a></p>

<p>It appears the <a href="http://stackoverflow.com/questions/38654302/how-can-i-sort-contours-from-left-to-right-and-top-to-bottom">question</a> you linked works not with the raw contours but first obtains a bounding rectangle using <code>cv2.boundingRect</code>. Only then does it make sense to calculate <code>max_width</code> and <code>max_height</code>. The code you posted suggests that you are trying to sort the raw contours, not bounding rectangles. If that is not the case, can you provide a more complete piece of your code, including a list of multiple contours that you are trying to sort?</p>

python python-2.7 opencv lambda opencv3.0