Measuring distance between objects in an image with OpenCV

distance_between_objects_result_01We have now reached the final installment in our three part series on measuring the size of objects in an image and computing the distance between objects.

Two weeks ago, we started this round of tutorials by learning how to (correctly) order coordinates in a clockwise manner using Python and OpenCV. Then, last week, we discussed how to measure the size of objects in an image using a reference object.

This reference object should have two important properties, including:

  1. We know the dimensions (in terms of inches, millimeters, etc.) of the object.
  2. It can be easily identifiable in our image (based on either location or appearances).

Given such a reference object, we can use it compute the size of objects in our image.

Today, we are going to combine the techniques used in the previous blog posts in this series and use these methods to compute the distance between objects.

Keep reading to find out how…

Looking for the source code to this post?
Jump right to the downloads section.

Measuring distance between objects in an image with OpenCV

Computing the distance between objects is very similar to computing the size of objects in an image — it all starts with the reference object.

As detailed in our previous blog post, our reference object should have two important properties:

  • Property #1: We know the dimensions of the object in some measurable unit (such as inches, millimeters, etc.).
  • Property #2: We can easily find and identify the reference object in our image.

Just as we did last week, we’ll be using a US quarter as our reference object which has a width of 0.955 inches (satisfying Property #1).

We’ll also ensure that our quarter is always the left-most object in our image, thereby satisfying Property #2:

Figure 1: We'll identify our reference object based on location, hence we'll always ensure our quarter is the left-most object in the image.

Figure 1: We’ll identify our reference object based on location, hence we’ll always ensure our quarter is the left-most object in the image.

Our goal in this image is to (1) find the quarter and then (2) use the dimensions of the quarter to measure the distance between the quarter and all other objects.

Defining our reference object and computing distances

Let’s go ahead and get this example started. Open up a new file, name it distance_between.py , and insert the following code:

Our code here is near identical to last week. We start by importing our required Python packages on Lines 2-8. If you don’t already have the imutils package installed, stop now to install it:

Otherwise, you should upgrade to the latest version ( 0.3.6  at the time of this writing) so you have the updated order_points function:

Lines 14-19 parse our command line arguments. We need two switches here: --image , which is the path to the input image containing the objects we want to measure, and --width , the width (in inches) of our reference object.

Next, we need to preprocess our image:

Lines 22-24 load our image from disk, convert it to grayscale, and then blur it using a Gaussian filter with a 7 x 7 kernel.

Once our image has been blurred, we apply the Canny edge detector to detect edges in the image — a dilation + erosion is then performed to close any gaps in the edge map (Lines 28-30).

A call to cv2.findContours  detects the outlines of the objects in the edge map (Lines 33-35) while Line 39 sorts our contours from left-to-right. Since we know that our US quarter (i.e., the reference object) will always be the left-most object in the image, sorting the contours from left-to-right ensures that the contour corresponding to the reference object will always be the first entry in the cnts  list.

We then initialize a list of colors  used to draw the distances along with the refObj  variable, which will store our bounding box, centroid, and pixels-per-metric value of the reference object.

On Line 45 we start looping over each of the contours in the cnts  list. If the contour is not sufficiently large (Lines 47 and 48), we ignore it.

Otherwise, Lines 51-53 compute the rotated bounding box of the current object (using cv2.cv.BoxPoints  for OpenCV 2.4 and cv2.boxPoints  for OpenCV 3).

A call to order_points  on Line 59 rearranges the bounding box (x, y)-coordinates in top-left, top-right, bottom-right, and bottom-left order, which as we’ll see, is important when we go to compute the distance between object corners.

Lines 62 and 63 compute the center (x, y)-coordinates of the rotated bounding box by taking the average of the bounding box in both the x and y direction.

The next step is to calibrate our refObj :

If our refObj  is None  (Line 68), then we need to initialize it.

We start by unpacking the (ordered) rotated bounding box coordinates and computing the midpoint between the top-left and bottom-left along with top-right and bottom-right points, respectively (Lines 73-75).

From there, we compute the Euclidean distance between the points, giving us our “pixels-per-metric”, allowing us to determine how many pixels fit into --width  inches.

Note: See last week’s post for a more detailed discussion of the “pixels-per-metric” variable.

Finally, we instantiate our refObj  as a 3-tuple consisting of:

  1. The sorted coordinates corresponding to the rotated bounding box reference object.
  2. The centroid of the reference object.
  3. The pixels-per-metric ratio that we’ll be using to determine the distance between objects.

Our next code block handles drawing the contours around our reference object and the object we are currently examining, followed by constructing refCoords  and objCoords  such that (1) the bounding box coordinates and (2) the (x, y)-coordinates of the of the centroid are included in the same arrays:

We are now ready to compute the distance between the respective corners and centroids of objects in our image:

On Line 94 we start looping over pairs of (x, y)-coordinates that correspond to our reference object and object of interest.

We then draw a circle representing the (x, y)-coordinates of the current points we are computing the distance between and draw a line to connect the points (Lines 97-110).

From there, Line 105 computes the Euclidean distance between the reference location and the object location, followed by dividing the distance by the “pixels-per-metric”, giving us the final distance in inches between the two objects. The computed distance is then drawn on our image (Lines 106-108).

Note: This distance computation is performed for each of the top-left, top-right, bottom-right, bottom-left, and centroid coordinates for a total of five distance comparisons.

Finally, Lines 111 and 112 display the output image to our screen.

Distance measurement results

To give our distance measurement script a try, download the source code and corresponding images to this post using the “Downloads” form at the bottom of this tutorial. Unarchive the .zip  file, change directory to the distance_between.py  script, and then execute the following command:

Below follows a GIF animation demonstrating the output of our script:

Figure 2: Computing the distance between objects in an image with OpenCV.

Figure 2: Computing the distance between objects in an image with OpenCV.

In each of these cases, our script matches the top-left (red), top-right (purple), bottom-right (orange), bottom-left (teal), and centroid (pink) coordinates, followed by computing the distance (in inches) between the reference object and the current object.

Notice how the two quarters in the image are perfectly parallel to each other, implying that the distance between all five control points is 6.1 inches.

Below follows a second example, this time computing the distance between our reference object and a set of pills:

Figure 3: Computing the distance between pills using OpenCV.

Figure 3: Computing the distance between pills using OpenCV.

This example could be used as input to a pill sorting robot that automatically takes a set of pills and organizes them according to their size and distance from a pill container.

Our last example computes the distance between our reference object (a 3.5in x 2in business card) and a set of 7″ vinyl records and an envelope:

Figure 4: A final example of computing the distance between objects using OpenCV and computer vision.

Figure 4: A final example of computing the distance between objects using OpenCV and computer vision.

As you can see, in each of these cases, we have successfully computed the distance (in actual, measurable units) between objects in an image.

Summary

In the third and final installment in our series on measuring object sizes, we learned how to take two different objects in an image and compute the distance between them in actual measurable units (such as inches, millimeters, etc.).

Just as we found out in last week’s post, before we can (1) compute the size of an object or (2) measure the distance between two objects, we first need to compute the “pixels-per-metric” ratio, used to determine how many pixels “fit” into a given unit of measurement.

Once we have this ratio, computing the distance between objects is almost trivially easy.

Anyway, I hope you enjoyed this series of blog posts! If you have any suggestions for a future series, please leave a comment on shoot me a message.

And before you go, be sure to signup for the PyImageSearch Newsletter by entering your email address in the form below!

Downloads:

If you would like to download the code and images used in this post, please enter your email address in the form below. Not only will you get a .zip of the code, I’ll also send you a FREE 11-page Resource Guide on Computer Vision and Image Search Engines, including exclusive techniques that I don’t post on this blog! Sound good? If so, enter your email address and I’ll send you the code immediately!

, , , ,

44 Responses to Measuring distance between objects in an image with OpenCV

  1. AJ April 4, 2016 at 5:46 pm #

    Thanks for the great tutorial, I have one question.

    if I don’t have a reference object but I know the distance from the left edge of the image to the right edge can I find the distance from any object to the center of the image ?

    Best Regards

    • Adrian Rosebrock April 6, 2016 at 9:15 am #

      Yep, you absolutely can! The same ratio test applies.

  2. ghanendra April 5, 2016 at 6:05 am #

    Hey Adrian Its a Great Tutorial, thanks a lot I used it in my project for determining distance between the two bright objects.

    What If the reference object dimensions are continuously varying?? How to determine distance between the two variable size objects in a live stream video??

    • Adrian Rosebrock April 6, 2016 at 9:14 am #

      Can you elaborate on what you mean by “continuously varying”? If you have different reference objects, you’ll need to identify which one you are looking at. This can be done using all sorts of methods including object detection, keypoint matching, template matching, etc.

      • ghanendra April 6, 2016 at 10:28 pm #

        In your tutorial about Ball Tracking with opencv, when we move the ball back and forth in front of camera, the size of the contour varies accordingly, So taking this as reference, how to find distance between two balls??
        I have to detect the distance between the two head lights of a car and distance from the camera when car is moving.

        • Adrian Rosebrock April 7, 2016 at 12:54 pm #

          You’ll need to combine two calibration methods. The first (this blog post) to measure the distance between objects in images. Then, you can use this blog post to measure the distance from the camera to the object.

          • ghanendra April 7, 2016 at 11:32 pm #

            Really thanks a lot Adrian!!!!!!!!

          • Adrian Rosebrock April 8, 2016 at 12:54 pm #

            No problem 🙂

  3. Mahed April 5, 2016 at 10:58 am #

    Well … you know what they, there really is no off-switch to genius !!!

    Cant wait to see what Adrian has got brilliant plans for PyImage Gurus bit 🙂

    • Adrian Rosebrock April 6, 2016 at 9:10 am #

      Thanks Mahed! I have some pretty special announcements related to PyImageSearch Gurus coming in the next 1-2 months, so be sure to keep an eye on the blog 🙂

  4. Jim April 9, 2016 at 7:05 pm #

    Hello Adrian,

    can you explain what this line does:
    cnts = cnts[0] if imutils.is_cv2() else cnts[1]

    Thanks
    Jim

    • Adrian Rosebrock April 13, 2016 at 7:11 pm #

      That line of code handles if you are using OpenCV 2.4 or OpenCV 3. There is a difference in the tuple returned by OpenCV between OpenCV 2.4 and OpenCV 3. You can read more about the change to cv2.findContours in this blog post.

  5. Marcus W. April 29, 2016 at 4:54 am #

    Hey, nice post.
    I guess its a stupid question, but how can i loop only over the center of the objects.

    Thanks for any help ^^

    • Adrian Rosebrock April 30, 2016 at 4:01 pm #

      The center of the coordinates are stored in cX and cY. You can just loop over those and ignore the other 🙂

  6. suresh June 7, 2016 at 10:44 am #

    great work bro . u r really awesome …

    can u plzz explain how to find distance between two tracked objects in a live video

    • Adrian Rosebrock June 7, 2016 at 3:11 pm #

      The same general algorithm as discussed in this blog post needs to be applied. You first need to “calibrate” the camera. From there, determining the distance between two objects in a video stream is the same as determining the distance between two objects in an image — you just need to access the video stream and then process every frame of the stream.

  7. vinaya June 16, 2016 at 5:00 am #

    how to measure eye to eye distance?? can this be done similar way?

    • Adrian Rosebrock June 18, 2016 at 8:22 am #

      If you can detect both eyes in an image, then yes, you can use this method to compute the distance between them.

  8. priyanka July 1, 2016 at 6:09 am #

    what values are stored in (xA, yA), (xB, yB) ..please explain

    • Adrian Rosebrock July 1, 2016 at 3:01 pm #

      (xA, yA) stores the (x, y)-coordinates of the reference image, meanwhile (xB, yB) store the (x, y)-coordinates of the object we are computing the distance to.

  9. Raycuz July 21, 2016 at 8:08 am #

    Is that possible if I want to draw all the lines of distances between objects and saved it in a single image..??

    • Raycuz July 21, 2016 at 8:40 am #

      Found it
      Thank you very much
      You gave an awesome guide for beginners

      • Jacki June 6, 2017 at 7:40 pm #

        Plz if you can explain for me
        How i can draw all rectangles in a single image?
        Thanks in advance

        • Adrian Rosebrock June 9, 2017 at 1:57 pm #

          Draw the lines on the original image loaded on Line 22 (rather than orig). Then save the image to disk once all lines are drawn via cv2.imwrite.

          • Jacki June 10, 2017 at 10:08 pm #

            Dear Dr. Adrian;
            Thanks in advance for your reply
            I do it. Now i can save all result in a single image, but i have a problem:
            When i delet line 111  [ cv2.imshow(“Image”, orig)] when i want to stop show result on the screen, for loop not work perfectly!! Just work for 3 object ((it save result just for 2 or 3 object )) not for all object
            Please if you can help me ?
            How i can cancel line 111 and run program with out error ??

          • Jacki June 11, 2017 at 5:38 pm #

            Thanks a lot dear Dr. Adrian i do it
            I removed line 112
            cv2.waitKey(0)
            And now works fine without problem
            Your blog post very awesome
            Thanks again

  10. Agnel Vishal November 20, 2016 at 8:09 am #

    I think some modifications are required if the distance between reference object and camera are different from other objects and camera. What should be done then?

  11. Abeer December 9, 2016 at 2:15 am #

    Hi,
    I see that the calculated distance is between the reference object and all other objects, what if I want to measure the distance between two objects that both are non reference objects?

    • Adrian Rosebrock December 10, 2016 at 7:13 am #

      You can certainly do that as well. The important part is that you find your reference object first. Your reference object allows you to compute the number of pixels per metric. As long as you have this, you can compute the distance between two non-reference objects.

  12. Sam March 9, 2017 at 3:48 am #

    HI Adrian. Is the distance between two objects affected by the viewpoint of camera or the camera lens angle?

    • Adrian Rosebrock March 10, 2017 at 3:52 pm #

      Yes, it absolutely is. In order to correct for this it’s common to calibrate our camera by computing the intrinsic properties of the camera. This allows us to help us correct for distortion. For these measurements to be correct you should have an (approximately) 90 degree, birds-eye-view of the objects.

  13. shahid March 28, 2017 at 7:57 am #

    hi adrian!
    Is this code suitable for android app development?

    • Adrian Rosebrock March 28, 2017 at 12:49 pm #

      You would need to convert the code from Python to Java + OpenCV for Android, but the same computer vision algorithms can be used.

  14. Ahmed May 7, 2017 at 3:44 am #

    Hi Adrian,

    Thanks a lot for your tutorials .. I an still a beginner in Opencv and I want to use the same approach but with camera .. how to determine the distance between two Pink boxes by Camera ?

    What is the simplest code for that ?

    Thx

    • Adrian Rosebrock May 8, 2017 at 12:27 pm #

      I would suggest starting with this blog post to learn how to measure the distance between a camera and an object. Once you’ve detected both objects you can apply the same triangle similarity technique to measure the distance between the objects.

  15. David L. May 28, 2017 at 5:30 am #

    Do you have code to convert a perspective image into a birds-eye-view?

  16. Faisal June 4, 2017 at 7:00 am #

    Hi,

    The tutorial is awesome, but i need to adapt it for a video. So it can detect distances in real time. Could you please help me with it?

    Regards

    • Adrian Rosebrock June 6, 2017 at 12:11 pm #

      The same techniques applied to single images can also be applied to video. I would suggest reading this blog post on accessing video streams. If you are new to OpenCV and Python, be sure to read through Practical Python and OpenCV as this book will give you the fundamentals you need to be successful porting the algorithm from single images to video.

  17. Anil June 19, 2017 at 10:44 am #

    Hi Adrian!!!!
    The tutorial was great. Thank you for that.
    I wanted to know if i have a set of parallel lines, then can i get the distance between two consecutive lines instead of with reference to just the first one???

    • Anil June 20, 2017 at 2:10 am #

      What would be the execution time for this code???
      If given an image, in how much time can it provide the answer on a raspberry pi based camera?

      • Adrian Rosebrock June 20, 2017 at 11:21 am #

        Regardless if your lines or parallel you would still need to be able to detect them both, otherwise how would you be able to know the distance between two arbitrary points on either line?

        As for the execution time, yes, you could certainly run this script on a Raspberry Pi.

  18. JD July 13, 2017 at 10:12 am #

    Hey, I was working on a project which required me to measure the diameter of holes and length and width of a plate using the image of the plate and a rasp pi cam and ofc rasp pi. I was wondering if this has the ability to be accurate to .001 in? Please let me know

    • Adrian Rosebrock July 14, 2017 at 7:26 am #

      For that level of accuracy I would recommend computing the intrinsic and extrinsic parameters of your camera and calibrating.

Leave a Reply