Detecting Barcodes in Images with Python and OpenCV

Detecting Barcodes in Images with Python and OpenCV

UPDATE: The introduction to this post may seen a little “out there”. For some context, I had just finished watching the South Park Black Friday episodes prior to writing this post so I definitely had some inspiration regarding zombie shoppers, Black Friday chaos, and Game of Thrones.


Black Friday is coming.

Hordes of angry shoppers. Stampedes of middle-aged midwestern women, their toothless gums bloodthirsty for 75% off the latest season of Game of Thrones at the local Wal-Mart.

They’ll lineup outside the Wal-Mat doors on Thanksgiving at midnight. They’ll rally, beating at the locked doors with their hands and heads until their bodies are raw and bloody, like zombies from 28 Days Later. But instead of human flesh, they crave petty consumer sustenance. Their war cries of discounts and sales will reach the heavens. And their thunderous footsteps will cause earthquakes across the Great Plains.

Of course, the media won’t help — they will sensationalize every last little piece. From frostbitten families camping out all night in the blistering cold, to the little old lady trampled by raging bargain hunters as the doors open, akin to the Gallimimus stampede in Jurassic Park. All of this simply because she wanted to purchase the latest Halo game for Timmy, her little 9 year old grandson, who’s parents passed away this time last year. At a Wal-Mart. During Black Friday.

And I have to ask, is all this chaos and bedlam worth it?

Hell. No.

Any shopping I do this Black Friday will be from (safely) behind my laptop screen, likely nursing a hangover from the night before with a cup of coffee and a handful of Tylenol.

But if you decide you are going to venture out into the real-world and brave the bargain hunters, you’ll want to download the source code to this blog post first…

Imagine how silly you would feel, standing in line, waiting to checkout, only to scan the barcode on the latest season of Game of Thrones only to find out that Target has it for $5 cheaper?

In the rest of this blog post I’ll show you how to detect barcodes in images using nothing but Python and OpenCV.

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

Detecting Barcodes in Images using Python and OpenCV

The goal of this blog post is to demonstrate a basic implementation of barcode detection using computer vision and image processing techniques. My implementation of the algorithm is originally based loosely on this StackOverflow question. I have gone through the code and provided some updates and improvements to the original algorithm.

It’s important to note that this algorithm will not work for all barcodes, but it should give you the basic intuition as to what types of techniques you should be applying.

For this example, we will be detecting the barcode in the following image:

Figure 1: Example image containing a barcode that we want to detect.

Figure 1: Example image containing a barcode that we want to detect.

Let’s go ahead and start writing some code. Open up a new file, name it detect_barcode.py , and let’s get coding:

The first thing we’ll do is import the packages we’ll need. We’ll utilize NumPy for numeric processing, argparse  for parsing command line arguments, and cv2  for our OpenCV bindings.

Then we’ll setup our command line arguments. We need just a single switch here, --image , which is the path to our image that contains a barcode that we want to detect.

Now, time for some actual image processing:

On Lines 14 and 15 we load our image  off disk and convert it to grayscale.

Then, we use the Scharr operator (specified using ksize = -1 ) to construct the gradient magnitude representation of the grayscale image in the horizontal and vertical directions on Lines 19-21.

From there, we subtract the y-gradient of the Scharr operator from the x-gradient of the Scharr operator on Lines 24 and 25. By performing this subtraction we are left with regions of the image that have high horizontal gradients and low vertical gradients.

Our gradient  representation of our original image above looks like:

Figure 2: The gradient representation of our barcode image.

Figure 2: The gradient representation of our barcode image.

Notice how the barcoded region of the image has been detected by our gradient operations. The next steps will be to filter out the noise in the image and focus solely on the barcode region.

The first thing we’ll do is apply an average blur on Line 28 to the gradient image using a 9 x 9 kernel. This will help smooth out high frequency noise in the gradient representation of the image.

We’ll then threshold the blurred image on Line 29. Any pixel in the gradient image that is not greater than 225 is set to 0 (black). Otherwise, the pixel is set to 255 (white).

The output of the blurring and thresholding looks like this:

Figure 3: Thresholding the gradient image to obtain a rough approximation to the rectangular barcode region.

Figure 3: Thresholding the gradient image to obtain a rough approximation to the rectangular barcode region.

However, as you can see in the threshold image above, there are gaps between the vertical bars of the barcode. In order to close these gaps and make it easier for our algorithm to detect the “blob”-like region of the barcode, we’ll need to perform some basic morphological operations:

We’ll start by constructing a rectangular kernel using the cv2.getStructuringElement  on Line 32. This kernel has a width that is larger than the height, thus allowing us to close the gaps between vertical stripes of the barcode.

We then perform our morphological operation on Line 33 by applying our kernel to our thresholded image, thus attempting to close the the gaps between the bars.

You can now see that the gaps are substantially more closed, as compared to the thresholded image above:

Figure 4: Applying closing morphological operations to close the gap between barcode stripes.

Figure 4: Applying closing morphological operations to close the gap between barcode stripes.

Of course, now we have small blobs in the image that are not part of the actual barcode, but may interfere with our contour detection.

Let’s go ahead and try to remove these small blobs:

All we are doing here is performing 4 iterations of erosions, followed by 4 iterations of dilations. An erosion will “erode” the white pixels in the image, thus removing the small blobs, whereas a dilation will “dilate” the remaining white pixels and grow the white regions back out.

Provided that the small blobs were removed during the erosion, they will not reappear during the dilation.

After our series of erosions and dilations you can see that the small blobs have been successfully removed and we are left with the barcode region:

Figure 5: Removing small, irrelevant blobs by applying a series of erosions and dilations.

Figure 5: Removing small, irrelevant blobs by applying a series of erosions and dilations.

Finally, let’s find the contours of the barcoded region of the image:

Luckily, this is the easy part. On Lines 41-44 we simply find the largest contour in the image, which if we have done our image processing steps correctly, should correspond to the barcoded region.

We then determine the minimum bounding box for the largest contour on Lines 47-49 and finally display the detected barcode on Lines 53-55.

As you can see in the following image, we have successfully detected the barcode:

Figure 6: Successfully detecting the barcode in our example image.

Figure 6: Successfully detecting the barcode in our example image.

In the next section we’ll try a few more images.

Successful Barcode Detections

To follow along with these results, use the form at the bottom of this post to download the source code and accompanying images for this blog post.

Struggling with running the code in this section? Take a look at my command line arguments blog post.

Once you have the code and images, open up a terminal and execute the following command:

Figure 7: Using OpenCV to detect a barcode in an image.

Figure 7: Using OpenCV to detect a barcode in an image.

No problem detecting the barcode on that jar of coconut oil!

Let’s try another image:

Figure 8: Using computer vision to detect a barcode in an image.

Figure 8: Using computer vision to detect a barcode in an image.

We were able to find the barcode in that image too!

But enough of the food products, what about the barcode on a book:

Figure 9: Detecting a barcode on a book using Python and OpenCV.

Figure 9: Detecting a barcode on a book using Python and OpenCV.

Again, no problem!

How about the tracking code on a package?

Figure 10: Detecting the barcode on a package using computer vision and image processing.

Figure 10: Detecting the barcode on a package using computer vision and image processing.

Again, our algorithm is able to successfully detect the barcode.

Finally, let’s try one more image This one is of my favorite pasta sauce, Rao’s Homemade Vodka Sauce:

Figure 12: Barcode detection is easy using Python and OpenCV!

Figure 11: Barcode detection is easy using Python and OpenCV!

We were once again able to detect the barcode!

Summary

In this blog post we reviewed the steps necessary to detect barcodes in images using computer vision techniques. We implemented our algorithm using the Python programming language and the OpenCV library.

The general outline of the algorithm is to:

  1. Compute the Scharr gradient magnitude representations in both the and y direction.
  2. Subtract the y-gradient from the x-gradient to reveal the barcoded region.
  3. Blur and threshold the image.
  4. Apply a closing kernel to the thresholded image.
  5. Perform a series of dilations and erosions.
  6. Find the largest contour in the image, which is now presumably the barcode.

It is important to note that since this method makes assumptions regarding the gradient representations of the image, and thus will only work for horizontal barcodes.

If you wanted to implement a more robust barcode detection algorithm, you would need to take the orientation of the image into consideration, or better yet, apply machine learning techniques such as Haar cascades or HOG + Linear SVM to “scan” the image for barcoded regions.

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 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning. Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL! Sound good? If so, enter your email address and I’ll send you the code immediately!

, , , , , ,

120 Responses to Detecting Barcodes in Images with Python and OpenCV

  1. Brandon November 24, 2014 at 12:32 pm #

    Hi, nice article. I’d be interested to see a follow-up on actually deciphering the barcode value from the image. One tiny improvement I saw:

    c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]

    could simply be a min operation to avoid creating a second sorted array, only to take the first element:

    c = min(cnts, key = cv2.contourArea)

    • Adrian Rosebrock November 24, 2014 at 12:59 pm #

      Hi Brandon, thanks for the reply! I’ll definitely consider doing a followup post on deciphering barcode values.

      As for the code, I’m actually trying to find the largest contour, not the smallest one, which I think is what the code you presented is doing. Did you mean:

      c = max(cnts, key = cv2.contourArea)

      If so, I’ll definitely give that a shot next time!

  2. NHAS November 24, 2014 at 12:48 pm #

    Hello, good job on making the article I think its quite useful. Only thing is your zombie reference is a bit out. Its 28 days later 😛 not 24 days later.

    Other than that its a brilliant article.

    • Adrian Rosebrock November 24, 2014 at 12:57 pm #

      Whoops! My mistake — can’t believe I messed that one up. It’s fixed now!

  3. Bob November 24, 2014 at 5:25 pm #

    Nice article. But please don’t combine alcohol and tylenol (paracetamol). Even when you’re hungover it’s really very bad for your liver. Sorry for being off-topic.

    • Adrian Rosebrock November 24, 2014 at 7:18 pm #

      Hi Bob, thanks for the comment! You’re very right, never mix alcohol and Tylenol. 🙂

      • fran March 2, 2018 at 8:02 pm #

        Hi Adrian,

        Terrific post, thank you. I am trying to adapt your code for use with pdf417 barcodes and then decipher the actual codes. Any ideas on what modules / commands to use?

        thanks for your help

        fran

        • Adrian Rosebrock March 7, 2018 at 9:46 am #

          Hi Fran — I’m not familiar with PDF147 barcodes but I’ll try to do a barcode reader tutorial in the near future.

          • Oscar December 12, 2018 at 10:24 am #

            This will be great. PDF147 barcodes are in passports and identification cards. Can you make this possible?

  4. Jason November 26, 2014 at 12:25 am #

    Would be cool to see this done with streaming video.

    • Adrian Rosebrock November 26, 2014 at 7:13 am #

      Hi Jason, damn, that’s a great idea. I see a followup post coming!

  5. dolaameng November 27, 2014 at 7:57 am #

    Hi, thanks for the article. Two questions here:
    (1) Is using a scharr operator than a sobel crucial to this problem?
    (2) In your explanation “By performing this subtraction we are left with regions of the image that have high horizontal gradients and low vertical gradients.”, do you mean LOW horizontal gradients and HIGH vertical gradients? Because that’s how they named vscharr and hscharr in skimage.

    • Adrian Rosebrock November 27, 2014 at 10:04 am #

      (1) I don’t think it’s crucial. But the Scharr operator is more accurate for a 3×3 kernel, that’s the reason I used it. Realistically you could use the Sobel operator as well, I don’t think it would make an impact.
      (2) Interesting. I’ll have to take a look at that.

  6. Niv November 28, 2014 at 1:45 am #

    Hi, nice article.
    When you subtract the y-gradient from the x-gradient, you end up with:
    1. high positive values (i.e. +255) for: {high horizontal gradients and low vertical gradients} and
    2. Low negative values (i.e. -255) for: {high vertical gradients and low horizontal gradients},

    and since you are further making “convertScaleAbs” then all the high negatives will become high positives, so you end up with an image in which high vertical and low horizontal gradients are also emphasized. Which isn’t what you say you want (you want only the high horizontal and low vertical gradients).

    What do I miss here?

    Another remark related to the above is that in figure 2 (for example the finger) we can see that he image contains all combinations of high gradients- high horizontals, high verticals, and also gradients in 45 [deg].

    Thanks,

    • Adrian Rosebrock November 28, 2014 at 8:17 am #

      Hi Niv, shoot me an email and we can chat more about your question. Thanks!

  7. Matt McDonnell November 30, 2014 at 7:48 am #

    Thanks for the article! I’ve been playing with OpenCV in Google Chrome Native Client, and put together a version of this post that works in (Chrome) browser.
    Demo: http://www.matt-mcdonnell.com/code/NaCl/ImageProc/
    Code (BSD): https://github.com/mattmcd/NaCl/tree/master/ImageProc

  8. mastsolis December 13, 2014 at 11:22 pm #

    Hi,

    Wow, thank you for posting this tutorial. I was wondering, if it’s possible to somehow save the coordinate location and barcode image size?

    • Adrian Rosebrock December 14, 2014 at 7:21 am #

      Sure, absolutely. The line box = np.int0(cv2.cv.BoxPoints(rect)) will give you the (x, y)-coordinates of the location of the barcode and the barcode size. From there, you can store the coordinates on disk, in a database, etc.

  9. Tony January 30, 2015 at 4:36 am #

    Hi,

    Your articles are good and informative. However, I would like to mention what I perceive as a shortcoming, and this applies to many of your articles. And that is, instead of diving right into code which you seem to have a tendency of doing, I think it is much better to describe in words the algorithm and what you are trying to do. In this case, it would be the characteristics of the barcode region you’re trying to detect. You have something which is almost similar in the summary, but it should be even more general and at the beginning. As an example, the article link you provided about how QuaggaJS works is much clearer in this regard, I find. Right in the beginning introduction, the author says we are looking for a barcode region with “lines which are close to each other and have a similar angle”, and then proceeds to describe steps and details. It’s much clearer that way. Diving into the code without knowing what you’re looking for is confusing. Again, this is meant as constructive criticism. Thanks.

    • Adrian Rosebrock January 30, 2015 at 6:28 am #

      Thanks for the feedback Tony.

  10. Arron March 26, 2015 at 8:55 am #

    Your job is very good and significant,but it can only detect barcode,if it can recognize the barcode in the picture,it will be better.

  11. Richie April 25, 2015 at 12:23 am #

    Great article Adrian. I’d knew cv was the way to do this but didn’t know where to start. I have got this working in c#, you can see the gist here:
    https://gist.github.com/richardsawyer/62596e14d1ec4d148b28

    Changes I made: optimized for vertical barcode; added centring offset to the restructuring element as the final box was shifted up and to the left; experimented with the thresholding to get reliable results in my images; extracted the actual barcode as a bitmap to make reading easy.

    Thanks for sharing.

    • Adrian Rosebrock May 1, 2015 at 7:10 pm #

      Very nice Richie, thanks for sharing! 🙂

  12. John May 30, 2015 at 3:21 pm #

    This is cool. Have you come up with how to extract the barcode value yet?

    • Adrian Rosebrock May 30, 2015 at 6:15 pm #

      Hi John, using the code above you can most certainly extract the barcode from the image. Do you mean actually recognize the barcode? If so, I probably won’t be covering that directly on the PyImageSearch blog. There are a lot of other resources online that cover the encoding schemes of barcodes far better than I could.

  13. dhruv June 12, 2015 at 6:47 am #

    Hi thx for program…….I’m New in this……I’m having an error that..usage: detect_barcode.py
    [-h] -I IMAGE
    detect _barcode.py: error: argument -i/–image is required…so plz say how to solve it

    • Adrian Rosebrock June 12, 2015 at 9:41 am #

      Please look at the Successful Barcode Detections section where I detail how to run the Python script. Here is an example:

      python detect_barcode.py --image images/barcode_02.jpg

      Notice how the --image switch points to the barcode_02.jpg file in the images directory.

      • zee December 8, 2017 at 6:06 am #

        usage: detect_barcode.py [-h] -i IMAGE
        detect_barcode.py: error: argument -i/–image is required
        can you plz briefly expalin how to solve this issue in windows

        • Adrian Rosebrock December 8, 2017 at 4:39 pm #

          Please read up on command line arguments and you will be able to resolve the issue.

          • zee December 9, 2017 at 6:51 am #

            sir iam struck with this error i have already checked the size of image its fine

            detect_barcode.py –image images/barcode_01.jpg
            OpenCV Error: Assertion failed (scn == 3 || scn == 4) in cv::cvtColor, file ..\
            .\..\..\opencv\modules\imgproc\src\color.cpp, line 3737
            Traceback (most recent call last):
            File “C:\Users\zee\detect_barcode.py”, line 17, in
            gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            cv2.error: ..\..\..\..\opencv\modules\imgproc\src\color.cpp:3737: error: (-215)
            scn == 3 || scn == 4 in function cv::cvtColor

          • Adrian Rosebrock December 9, 2017 at 7:22 am #

            Your path to your input image is incorrect. The cv2.imread function will return None if the image path is incorrect. Since you are using Windows you need to update your --image path since Windows uses the “\” path separator rather than “/”:

            $ detector_barcode.py --image images\barcode_01.jpg

            Notice how the path separator has been changed.

          • zee December 9, 2017 at 8:25 am #

            sir even after trying the \ same error persists assertion failed

          • zee December 9, 2017 at 8:26 am #

            i tried with both ways / and \ both are giving the same error

  14. SayeedM June 24, 2015 at 1:09 am #

    Hello, great article. Btw is the procedure to detect 2D barcodes (PDF417) similiar ? I mean for 2D barcodes horizontal gradients wont be comparatively high to vertical gradients, right ? Can you do a followup on this ?

  15. al July 10, 2015 at 5:18 am #

    I’ve followed the instructions on installing OpenCV on Ubuntu and I can run the example on that page. I get the following error while trying this example however:

    gradX = cv2.Sobel(gray, ddepth=cv2.cv.CV_32F, dx=1, dy=0, ksize=-1)
    AttributeError: ‘module’ object has no attribute ‘cv’

    Any idea why that might be the case?

    • Adrian Rosebrock July 10, 2015 at 6:22 am #

      Hey Al, it sounds like you are using OpenCV 3.0. This code was developed using OpenCV 2.4.

      Change ddepth=cv2.cv.CV_32F to ddepth=cv2.CV_32F (along with the following line for the y gradient) and you’ll get ride of the pesky error.

      You’ll also need to change the cv2.findContours call to:

      (_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

  16. al July 11, 2015 at 1:52 am #

    They seem to have updated so now instead of cv2.cv.CV_32F it’s just cv2.CV_32F.

    also cv2.cv.BoxPoints is now cv2.boxPoints

    • Adrian Rosebrock July 11, 2015 at 6:30 am #

      Thanks Al!

  17. Nicolas August 19, 2015 at 8:29 am #

    Thanks for the great post! I tried it and it worked from the first time, but i was wondering is there a way to get the value of the barcode?

    • Adrian Rosebrock August 20, 2015 at 7:02 am #

      Great question. There are a lot of barcode reading packages out there. I would start by looking into zbar.

  18. Chris October 27, 2015 at 9:52 pm #

    Excellent post and enjoying the e-books too! Just a quick (and I’m sure, easy) question. How difficult would it be to extend this to include multiple barcodes in a single image? Like if you have to catalog a monotonous amount of barcodes but don’t really want to scan each one at a time but would rather line up about 5-10 barcodes and extract those contours?

    Thanks!

    • Adrian Rosebrock November 3, 2015 at 10:42 am #

      It wouldn’t be too challenging to extend to multiple barcodes. Instead of taking the largest contour as I do on Line 40, just loop over them individually, ensure they have sufficiently large size, and continue to process them.

  19. Inês Martins December 2, 2015 at 11:44 am #

    How to crop the barcode region out of image?

    using box points??

    • Adrian Rosebrock December 2, 2015 at 3:04 pm #

      Hey Ines — I would use:

      (x, y, w, h) = cv2.boundingRect(c) on the contour to grab the bounding box of the barcode. From there, you can extract the region from the image.

      • Shoo October 24, 2017 at 10:17 pm #

        Hi can you explain further on this? “How to crop the barcode region out of image?”

  20. Vinoth May 9, 2016 at 1:02 pm #

    Is there a way to compare two different bar codes to check if they are similar?

    • Adrian Rosebrock May 9, 2016 at 6:44 pm #

      Sure, there are multiple ways to do this. I would suggest starting with MSE and SSIM.

  21. Scott May 10, 2016 at 12:17 am #

    do you have something similar for detecting QRCodes?

    • Adrian Rosebrock May 10, 2016 at 8:07 am #

      I don’t have any tutorials related to detecting QRCodes, but it’s certainly something I’ll consider in the future!

  22. prasiddha May 22, 2016 at 8:57 am #

    I m a beginner in image processing and opencv both, i applied almost same algorithm and segmented the barcode from image now i’m lost trying to decode it. can you help me converting those bars into numbers? may be binary?(using opencv)

    • Adrian Rosebrock May 23, 2016 at 7:25 pm #

      I personally haven’t tried decoding the barcodes themselves, but I would recommend using a library such as zbar.

    • vaishali masal June 21, 2016 at 3:15 am #

      I also trying to decode Barcode in opencv and python.But didn’t get any idea how to do it. Can you tell me if you get it.

      • Kevin September 9, 2016 at 2:01 am #

        Coming in late but I would recommend to use ZXing. Been using for some time now and my colleagues and I are very happy with it.

        @Adrian, great post! Really useful.

        • Adrian Rosebrock September 9, 2016 at 10:51 am #

          Thanks Kevin, I’m glad it helped! And thanks for the recommending on ZXing.

  23. Em June 22, 2016 at 12:49 pm #

    Hello!!!! You’re the very best Adrian.

    I’m getting this error on box points:

    Do you know what I can do to fix it? Thank you

    • Adrian Rosebrock June 23, 2016 at 1:17 pm #

      It sounds like you’re using OpenCV 3 (this blog post assumes you’re using OpenCV 2.4). You can resolve the issue by using:

      box = cv2.boxPoints(rect)

  24. Mithun S August 9, 2016 at 3:15 am #

    Is it possible to the same steps in C# .net?

    • Adrian Rosebrock August 10, 2016 at 9:32 am #

      Yes, but you would need to convert the code from Python + OpenCV to C# + OpenCV.

  25. Rafi Fadlianto December 5, 2016 at 6:01 pm #

    Thanks for the Tutorial 😀 I will try it 🙂
    So we cant use for OpenCV 3 ?

    *note = I dont have any website right now

    • Adrian Rosebrock December 7, 2016 at 9:51 am #

      This blog post was written before OpenCV 3 was released. That said, change cv2.cv.CV_32F to cv2.CV_32F and (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) to (_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) and the script should work just fine.

  26. esconda January 18, 2017 at 3:43 am #

    Is there anyway convert it to c++ code.I just would like to test performance of opencv in c++.I already applied all filtration until this code;

    box = np.int0(cv2.cv.BoxPoints(rect))

    How can I convert it to c/c++ “np.int0” what is equavalent of this code in c?

    • Carsten August 7, 2018 at 4:11 pm #

      I also converted the python-code to C++ a few days ago. Hopefully correctt cause I don’t know python. However the barcode detection with the 6 Test-Images seems to work fine.

      To your Question: In C++ it is possible to avoid the function-call “cv2.cv.BoxPoints(rect)” nad to use the cv::RotatedRect-Method points() instead. The Result of that method call is a cv::Point2d-array which has to be casted into a cv::Point-Vector. That cast-operation is what “np.int0()” apparently does.
      I’ve done that cast-operation in a simple for-loop – line 146 in the below link.

      https://gist.github.com/funart23/3f8708c6119f70539be7de941717e1a4

      If you find any problems with the code, please let me know.

  27. Varun February 16, 2017 at 5:28 am #

    Great work!
    Can you provide a source where I could find the tutorial to decipher the bar code? That would be great!

    • Adrian Rosebrock February 16, 2017 at 9:47 am #

      I don’t have any tutorials covering barcode decoding (yet), but I would suggest using zbar.

  28. Osama Arif February 19, 2017 at 1:41 pm #

    the program shows this error:

    usage: detect_barcode.py [-h] -i IMAGE
    detect_barcode.py: error: argument -i/–image is required

    Please respond asap

  29. Ráfagan Abreu April 3, 2017 at 3:25 am #

    I built a version of this algorithm using Python 3, OpenCV 3.2 and MatPlot. Follow the code:\

    https://gist.github.com/rafagan/5e73867958712eaeeb6d781e868559e6

  30. Thorsten May 26, 2017 at 7:57 am #

    Hi Adrian,

    here again. I changed your code accordingly to your instructions to fit to opencv-3.0.0. The detection itself works and returns following box

    [[ 340. 140.]
    [ 311. 140.]
    [ 311. 121.]
    [ 340. 121.]].

    But if this box is taken as input to
    cv2.drawContours(frame, [box], -1, (0, 255, 0), 2), it fails with a exception.

    cv2.error: /home/pi/opencv-3.0.0/modules/imgproc/src/drawing.cpp:2310:
    error: (-215) npoints > 0 in function drawContours.

    As I understand the box must be a array of arrays. Even if I exchange ‘[box]‘ with ‘box’ in function call, it fails with same exception.

    What’s wrong?

    Thanks in advance

    • Adrian Rosebrock May 28, 2017 at 1:12 am #

      So if I understand correctly, you computed the bounding box and now you are trying to draw the rotated bounding box on the image?

      Make sure you do:

  31. Amrit Kumbhakar August 30, 2017 at 12:20 am #

    Amazing tutorial. Thanks .
    I successfully completed the steps. Now i want to get the numbers from the barcode. What to get that?

    • Adrian Rosebrock August 31, 2017 at 8:35 am #

      Take a look at the zbar library. I personally haven’t used it but I know other PyImageSearch readers have liked it.

      • Amrit Kumbhakar September 7, 2017 at 1:38 am #

        Thanks. Can you suggest some?

  32. uti September 3, 2017 at 5:32 am #

    Nice tutorial. I compiled it with python 3.6 and opencv 3.3.0 using the mentioned changes to get it up and running. Sadly it’s only working for the first barcode in the zip.. The others are not found. Either only parts are detected or some text is marked 🙁

    Whats interesting is that the results (the rectangle marking the barcode) differ from opencv 3.2.0 to 3.3.0 with opencv 3.2.0 also not finding the barcode. I tested python 2.7 and 3.6 with both opencv 3.2.0 and 3.3.0. Maybe you could revise this tutorial given you have time to spare.

    • Adrian Rosebrock September 5, 2017 at 9:28 am #

      Thanks for sharing, Uti!

  33. Atharva Saraf September 20, 2017 at 2:11 am #

    Hi! I am a python beginner.I tried implementing your code. Ran into a error at c=sorted(…). The index list is growing out of bound. How can this be corrected? Thank you!

  34. Dmytro September 25, 2017 at 12:43 pm #

    HI Adrian,
    Thanks for this article, it is really helps me to solve my solution.
    But I have problem while detecting barcode with black background. In this case it works a little bi incorrect. So when I change thresh parameter from 225 to 175, 150 or even 100 , it recognize barcode with black background, but with this parameters it works incorrectly for others images.
    Could you please recommend some advise how to solve this issue?

    Thanks,
    Dmytro

    • Adrian Rosebrock September 26, 2017 at 8:19 am #

      Have you considered applying adaptive thresholding or Otsu’s automatic thresholding? This would be my first suggestion.

  35. Vinay September 28, 2017 at 2:31 pm #

    hi i am using python3 and opencv 3 . As you posted in comments i made necessary changes in code but i am getting error as

    Traceback (most recent call last):
    File “barcoded.py”, line 47, in
    box = np.int0(cv2.cv.BoxPoints(rect))
    AttributeError: module ‘cv2’ has no attribute ‘cv’

    how to resolve this error ?

    • Adrian Rosebrock September 28, 2017 at 6:03 pm #

      Always check the comments for your error. Please see my reply to “Em” on June 22nd.

  36. Saldor October 26, 2017 at 9:58 pm #

    HI! Where in this code, that part of it, where it is determined that we should write down the area where the barcode is found (strips and digits)?

    • Adrian Rosebrock October 27, 2017 at 11:11 am #

      Hi Saldor– Line 44 gets the coordinates for the box. Let me know if this helps.

  37. hoda December 6, 2017 at 2:39 pm #

    this code is’nt working. there is not any kind of error but it does’nt open me any images let alone detecting barcodes. i do not know how to fix it can you help me please

    • Adrian Rosebrock December 8, 2017 at 5:04 pm #

      Hey Hoda — are you testing on your own images or the images included with the download of the blog post? Make sure you use the “Downloads” section of the post and test with the original images to obtain a baseline first. It sounds like no barcodes are being detected in your input images and thus the script automatically exits.

  38. rushabh December 8, 2017 at 9:31 am #

    Hey adrian i changed code as you said in comment to EM on 22 june but it still giving samr error

    File “detect_barcode.py”, line 47, in
    box = cv2.BoxPoints(rect)
    AttributeError: ‘module’ object has no attribute ‘BoxPoints’

    • Adrian Rosebrock December 8, 2017 at 4:37 pm #

      The code is still incorrect — your “B” is capitalized when it should be a lowercase “b”:

      cv2.boxPoints(rect)

      • rushabh December 9, 2017 at 1:09 am #

        oh sorry again but now it giving this problem

        it does not showing the right barcode it just showing half part of 4,5 barcode image file.

  39. rushabh December 9, 2017 at 1:10 am #

    and also i need to make an application to make the for droesiness detection but i cannot having dlib oin windoes so can you help me please.

    • Adrian Rosebrock December 9, 2017 at 7:27 am #

      I would suggest doing research on facial landmark detection libraries that can be used on Windows. For what it’s worth, dlib can be installed on Windows.

  40. Surabhi January 13, 2018 at 10:11 pm #

    This article is really nice. However, I had a question.
    How would you justify that the barcode region will have the highest x gradient value? What about the background words in the sentences, even they’ll have a high gradient in the x-direction right?

    • Adrian Rosebrock January 15, 2018 at 9:17 am #

      We subtract the y-gradient output from the x-gradient output. This subtraction leaves us with regions of the image that have high horizontal gradients and low vertical gradients. A barcode will exhibit lots of changes in the horizontal direction.

  41. Alex January 21, 2018 at 5:51 pm #

    Hello! Nice article and very informative. However I have a question.

    Why did you put [0] on this? c = sorted(cnts, key = cv2.contourArea, reverse = True)[0]

    Thanks a lot.

    • Adrian Rosebrock January 22, 2018 at 6:19 pm #

      The “[0]” returns the element at the front of the list which will be the contour with the largest area. Alternatively we could write:

      c = max(cnts, key=cv2.contourArea

  42. Prakash March 10, 2018 at 3:01 am #

    Hey Adrian,

    Thank you for all the posts. I have a few doubts.
    1. Could you tell the difference between cv2. MORPH_CLOSE and cv2.MORPH_OPEN arguments. Exactly why do you use the MORPH_CLOSE argument here and what would happen if instead MORPH_OPEN is used?

    2. Could you elaborate a little more on Lines 17 and 18 as to what they do with the image?

    • Adrian Rosebrock March 14, 2018 at 1:26 pm #

      1. These are morphological operations. A close will “close” the gap between foreground objects while an “open” will expand the gap between foreground objects. I cover morphological operations inside my book, Practical Python and OpenCV as well as the PyImageSearch Gurus course.

      2. These lines compute the Sobel gradient magnitude representation of the image. Again, see Practical Python and OpenCV or the PyImageSearch Gurus course.

  43. Jerry April 17, 2018 at 8:17 am #

    Hey Adrian,
    When I execute other cases with code, the result of cv2.boxPoints output is negative. I don’t know why.output result is like:
    [[142 219]
    [ 49 69]
    [174 -7]
    [267 142]]

    • Adrian Rosebrock April 17, 2018 at 9:16 am #

      This can happen when the barcodes are near the boundaries of the image. We’re converting a contour region to a bounding box and if the barcode is near the boundaries of the image you can have a negative value.

  44. Koustav Dutta May 13, 2018 at 5:08 am #

    # construct the argument parse and parse the arguments
    ap = argparse.ArgumentParser()
    ap.add_argument(“-i”, “–image”, required = True, help = “C:/Users/nEW u/Desktop/image processing 123 with python opencv/barcode_01.jpg”)
    args = vars(ap.parse_args())

    sir, after running the full code am getting errors continously, like-
    1.usage: BARCODE_DETECTION_IN_IMAGES.py [-h] -i IMAGE
    BARCODE_DETECTION_IN_IMAGES.py: error: the following arguments are required: -i/–image
    sometimes instead of ‘\’ if I write ‘/’. it gives errors
    please help me out

  45. haili May 21, 2018 at 3:51 am #

    .. python3.6

    (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    ValueError: too many values to unpack (expected 2)

  46. Sam May 24, 2018 at 12:18 pm #

    When I run this on python 3.6 I’m getting a ValueError on the cv2.findContours line. I know this may not have been written for python 3, but do you have any tips on how to get it working? This is my first time using cv2 so I’m not sure what/how many values findContours returns.

    Error:
    ValueError: too many values to unpack (expected 2)
    When calling:
    (cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    • Adrian Rosebrock May 25, 2018 at 5:56 am #

      In OpenCV 3 the return signature of the “cv2.findContours” function changed to return a 3-tuple. You can update the function call to be:

      (_, cnts, _) = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

      I’ll also be updating this blog post to support both OpenCV 2.4 and OpenCV 3 in the next couple of weeks.

  47. BitHead July 29, 2018 at 12:55 pm #

    As to requests for “Just the bar code, please.”…

    I added this to the bottom of your wonderful script…

    ([x1,y1],[x2,y2],[x3,y3],[x4,y4])=box
    crop_img = image[y2:y2+(y1-y2-20), x1-10:(x1+(x4-x1)+10)]
    cv2.imshow(“cropped”, crop_img)
    cv2.imwrite(“cropped.png”, crop_img)
    cv2.waitKey(0)

    … and was quite pleased. 🙂

    PS. Don’t know why, but a blur gradient of (6,9) worked better for me – otherwise it was picking out just two bars – might be because it was a short-wide label with rounded corners?

    Thank you for your efforts – keep ’em coming!

    • Adrian Rosebrock July 31, 2018 at 10:00 am #

      Awesome, thanks for sharing!

  48. subeesh kumar August 23, 2018 at 3:26 am #

    hi Adrian if i run the code its just scanning the barcode. what iam asking is if i scan the barcode it should detect and print it on the terminal can u tell me how to do this?

    • Adrian Rosebrock August 24, 2018 at 8:43 am #

      This tutorial will solve your exact problem.

  49. Joseph November 11, 2018 at 8:57 pm #

    Hi, Adrian.
    Thank you for your useful article. I did it successfully, but I want each barcode returns a real value in order to save as a product. Whenever I read a barcode, I can know what the product is.
    Could you pleased to guide me how to do it?

  50. Danielw November 16, 2018 at 8:12 am #

    Hi, Adrian. Great job for the barcode detection. Do you have any idea of the name of algorithm you used? or the author? Thank You.

    • Adrian Rosebrock November 19, 2018 at 12:50 pm #

      There isn’t really a name for this algorithm. It’s something I created for the sake of this tutorial.

  51. Lucas December 5, 2018 at 6:33 am #

    Hi Adrian,
    the images must have a especific resolution? What it is the resolution of the images that you used?
    And about the ambient ilumination, is there any especification?

    • Adrian Rosebrock December 6, 2018 at 9:41 am #

      For a more robust barcode detection you may want to use the Zbar library. See this tutorial for more information.

  52. JasonW December 21, 2018 at 2:43 am #

    Hey Adrian,

    I’m doing a project for blind peoples so they can use they smartphone to scan barcode realtime and transform it into sound via text to speech. The challenge for blind peoples is they can’t see where exactly the barcode location. I’m using your algorithm and the result is good, but whenever there is the nutrition fact, it’s detect the nutrition fact as barcode too. Do you have any idea how to fix it? Thank You.

    • Adrian Rosebrock December 27, 2018 at 11:02 am #

      What a great project! Have you tried using this tutorial which leverages the ZBar library? That will likely work better.

  53. Yilong March 19, 2019 at 4:02 am #

    Hello, sir.
    I am going to detect LP code(Lots perception Matrix code) in scanned image.
    The images was damaged. How can I do?
    Could you help me, please?
    Kind regards

Trackbacks/Pingbacks

  1. Real-time barcode detection in video with Python and OpenCV - PyImageSearch - December 15, 2014

    […] Today’s post is a followup to a previous (extremely popular) article on detecting barcodes in images using Python and OpenCV. […]

  2. Sorting Contours using Python and OpenCV - PyImageSearch - April 20, 2015

    […] Contours enabled us detect barcodes in images. […]

  3. Reading barcodes with Python and OpenMV - PyImageSearch - March 19, 2018

    […] In a previous post here on PyImageSearch, I demonstrated how to detect barcodes with Python and OpenCV. […]

Before you leave a comment...

Hey, Adrian here, author of the PyImageSearch blog. I'd love to hear from you, but before you submit a comment, please follow these guidelines:

  1. If you have a question, read the comments first. You should also search this page (i.e., ctrl + f) for keywords related to your question. It's likely that I have already addressed your question in the comments.
  2. If you are copying and pasting code/terminal output, please don't. Reviewing another programmers’ code is a very time consuming and tedious task, and due to the volume of emails and contact requests I receive, I simply cannot do it.
  3. Be respectful of the space. I put a lot of my own personal time into creating these free weekly tutorials. On average, each tutorial takes me 15-20 hours to put together. I love offering these guides to you and I take pride in the content I create. Therefore, I will not approve comments that include large code blocks/terminal output as it destroys the formatting of the page. Kindly be respectful of this space.
  4. Be patient. I receive 200+ comments and emails per day. Due to spam, and my desire to personally answer as many questions as I can, I hand moderate all new comments (typically once per week). I try to answer as many questions as I can, but I'm only one person. Please don't be offended if I cannot get to your question
  5. Do you need priority support? Consider purchasing one of my books and courses. I place customer questions and emails in a separate, special priority queue and answer them first. If you are a customer of mine you will receive a guaranteed response from me. If there's any time left over, I focus on the community at large and attempt to answer as many of those questions as I possibly can.

Thank you for keeping these guidelines in mind before submitting your comment.

Leave a Reply

[email]
[email]