× {{alert.msg}} Never ask again
Get notified about new tutorials RECEIVE NEW TUTORIALS
Ray Phan
Feb 23, 2015
<p>First off, that example only shows you how to draw contours with the simple approximation. If you were to show that image now, you will only get what you see on the right hand side of that figure. If you want to get the image on the left hand side, you need to detect the <strong>full</strong> contour. Specifically, you need to replace the <code>cv2.CHAIN_APPROX_SIMPLE</code> flag with <code>cv2.CHAIN_APPROX_NONE</code>. Take a look at the OpenCV doc on <code>findContours</code> for more details: <a href="http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#findcontours" rel="nofollow">http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#findcontours</a></p> <p>In addition, your code draws the contours onto the image, but it doesn't display the results. You'll need to call <a href="http://docs.opencv.org/modules/highgui/doc/user_interface.html#imshow" rel="nofollow"><code>cv2.imshow</code></a> for that. </p> <p>As such, create two images like so:</p> <pre><code># Your code import numpy as np import cv2 im = cv2.imread('test.jpg') imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(imgray,127,255,0) # Detect contours using both methods on the same image contours1, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) contours2, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) # Copy over the original image to separate variables img1 = im.copy() img2 = im.copy() # Draw both contours onto the separate images cv2.drawContours(img1, contours1, -1, (255,0,0), 3) cv2.drawContours(img2, contours2, -1, (255,0,0), 3) </code></pre> <hr> <p>Now, to get the figure you see above, there are two ways you can do this:</p> <ol> <li>Create an image that stores both of these results together side by side, then show this combined image.</li> <li>Use <a href="http://matplotlib.org/" rel="nofollow"><code>matplotlib</code></a>, combined with <code>subplot</code> and <code>imshow</code> so that you can display two images in one window. </li> </ol> <p>I'll show you how to do it using both methods:</p> <h1>Method #1</h1> <p>Simply stack the two images side by side, then show the image after:</p> <pre><code>out = np.hstack([img1, img2]) # Now show the image cv2.imshow('Output', out) cv2.waitKey(0) cv2.destroyAllWindows() </code></pre> <p>I stack them horizontally so that they are a combined image, then show this with <code>cv2.imshow</code>.</p> <h1>Method #2</h1> <p>You can use <a href="http://matplotlib.org/" rel="nofollow"><code>matplotlib</code></a>:</p> <pre><code>import matplotlib.pyplot as plt # Spawn a new figure plt.figure() # Show the first image on the left column plt.subplot(1,2,1) plt.imshow(img1[:,:,::-1]) # Turn off axis numbering plt.axis('off') # Show the second image on the right column plt.subplot(1,2,2) plt.imshow(img2[:,:,::-1]) # Turn off the axis numbering plt.axis('off') # Show the figure plt.show() </code></pre> <p>This should display both images in separate subfigures within an overall figure window. If you take a look at how I'm calling <code>imshow</code> here, you'll see that I am swapping the RGB channels because OpenCV reads in images in BGR format. If you want to display images with <code>matplotlib</code>, you'll need to reverse the channels as the images are in RGB format (as they should be).</p> <hr> <p>To address your question in your comments, you would take which contour structure you want (<code>contours1</code> or <code>contours2</code>) and search the contour points. <code>contours</code> is a list of all possible contours, and within each contour is a 3D matrix that is shaped in a <code>N x 1 x 2</code> format. <code>N</code> would be the total number of points that represent the contour. I'm going to remove the singleton second dimension so we can get this to be a <code>N x 2</code> matrix. Also, let's use the full representation of the contours for now:</p> <pre><code>points = contours1[0].ravel().reshape((len(contours1[0]),2)) </code></pre> <p>I am going to assume that your image only has <strong>one</strong> object, hence my indexing into <code>contours1</code> with index 0. I unravel the matrix so that it becomes a single row vector, then reshape the matrix so that it becomes <code>N x 2</code>. Next, we can find the minimum point by:</p> <pre><code>min_x = np.argmin(points[:,0]) min_point = points[min_x,:] </code></pre> <p><code>np.argmin</code> finds the <strong>location</strong> of the smallest value in an array that you supply. In this case, we want to operate along the <code>x</code> coordinate, or the columns. Once we find this location, we simply index into our 2D contour point array and extract out the contour point.</p> <p>This tip was originally posted on <a href="http://stackoverflow.com/questions/28677544/Opencv:%20display%20contours/28677782">Stack Overflow</a>.</p>
comments powered by Disqus