What if I said that there’s a camera that:
- Is low cost at $65.
- Runs MicroPython.
- And can be expanded with shields just like an Arduino/RPi.
Meet OpenMV!
I met Kwabena Agyeman, the founder of OpenMV, during the PyImageSearch Gurus Kickstarter campaign in January 2015. At that time, Kwabena and the OpenMV team were running a Kickstarter of their own. Kwabena’s Kickstarter raised a lot more funds than mine, which really demonstrates (1) the value of the OpenMV product and (2) the eagerness of the embedded community to work with such a tool.
Since the OpenMV Kickstarter, the OpenMV team has been on a mission to provide a low cost, Python-ready, and easy to use camera system for developers and engineers working on embedded computer vision projects.
Given the success of OpenMV so far, perhaps it’s no surprise that there is an active community of developers. You’ll definitely have the support needed to make your project a success. When I started building the barcode scanning system for this post I was incredibly impressed by the responsiveness of their users and forums.
In today’s blog post, you’ll be introduced to OpenMV, their fancy IDE, and we’ll even build your own barcode scanning system.
To get started with the OpenMV cam and barcode decoding with computer vision, just keep reading.
Looking for the source code to this post?
Jump Right To The Downloads SectionReading barcodes with Python and OpenMV
There’s no way of getting around barcodes in today’s world.
Every grocery item or Amazon package you receive has them. Every time you board an airplane or rent a car, barcodes are used. And heaven forbid, the a barcode could be associated with your identity on a hospital wristband during an emergency visit!
But why?
Simply put, barcodes are an easy way for computers to associate an item with a database. It’s therefore important that barcodes are decoded properly so that databases can be updated.
Typical barcode readers use a photoelectric cell to “see” the code. Check out this post by Chris Woodford on Barcodes and barcode scanners.
Given the prominence of cameras in today’s age, we can actually use image processing to detect and decode barcodes.
In a previous post here on PyImageSearch, I demonstrated how to detect barcodes with Python and OpenCV.
Detecting is one piece of the puzzle.
The other piece is decoding the barcode into a useful string.
Unfortunately, OpenCV does not contain built-in barcode detection + reading functionality…
…but there are a few popular libraries for barcode detection, one of which is ZBar. Satya Mallick, a PyImageConf 2018 presenter, wrote a great post about ZBar last month on his blog.
Using ZBar and other similar barcode reading libraries is one method to accomplish the task.
The other option is to use embedded tools and libraries such as OpenMV.
In fact, OpenMV makes it so easy to detect and read barcodes that you could:
- Build your own barcode scanning device
- Create an automated part inspection system on an assembly line
- Utilize OpenMV in a hobby project to help you scan and organize components and peripherals in your workshop
- Use OpenMV to teach middle school or high schoolers about embedded programming
The OpenMV cam
Aimed at being the “Arduino of Machine Vision”, the OpenMV cam is embedded (no OS) and is expandable via several available shields (just like an Arduino).
It is also dead-simple to use — you write code with MicroPython (unlike an Arduino).
Python users and readers of this blog will feel at home when building embedded computer vision projects with MicroPython for the OpenMV.
The OpenMV camera is quite capable and would fit well in a small robotics project with servo motors or even in a automated part inspection assembly line.
You can easily interface the OpenMV with other hardware, sensors, microcontrollers, and SBCs over communication protocols such as SPI, I2C, WiFi, and USB.
OpenMV will typically work best if it just has one or two tasks to perform as it does have limited memory (31KB is allocated for scripts). If you need to record stills or video you may plug in a microSD.
Image processing capabilities of the OpenMV include:
- Haar cascades
- Thresholding
- Blob detection
- Drawing lines, circles, and rectangles
- Recording GIFs and MJPEGs
- Reading barcodes (this post)
- Template matching
- …and more!
For the full list, be sure to check out the docs.
Do you need a particular lens for your application? One differentiator is the Standard M12 Lens Mount. Now you can attach that telescopic zoom or fisheye lens for your project. I sure do wish that the Raspberry Pi PiCamera has a lens mount like the OpenMV does.
Barcode detection and decoding with OpenMV and Python
Once you’ve installed the OpenMV IDE, fire it up. We’ll be doing all of our coding in the OpenMV IDE.
Let’s begin by creating a file called openmv_barcode.py
:
# import necessary packages import sensor import time import image # import the lcd optionally # to use the LCD, uncomment Lines 9, 24, 33, and 100 # and comment Lines 19 and 20 #import lcd
On Lines 2-4 we import our required MicroPython/OpenMV packages.
Optionally, on Line 9, you can import the lcd
package which is required if you want to use the LCD shield.
Next, let’s set up the camera sensor:
# reset the camera sensor.reset() # sensor settings sensor.set_pixformat(sensor.GRAYSCALE) # non LCD settings # comment the following lines if you are using the LCD sensor.set_framesize(sensor.VGA) sensor.set_windowing((640, 240)) # LCD settings # uncomment this line to use the LCD with valid resolution #sensor.set_framesize(sensor.QQVGA2) # additional sensor settings sensor.skip_frames(2000) sensor.set_auto_gain(False) sensor.set_auto_whitebal(False)
The settings on Lines 12-29 are self explanatory, so please read the code and comments.
I do want to point out that the LCD requires a resolution that fits the screen (sensor.QQVGA2
).
Note: I tried and tried to figure out how to use the full resolution and then make a scaled image which would fit on the LCD, but was unable. Because of this, if you do elect to use the LCD, you’ll be trying to decode barcodes at a lower resolution (which isn’t optimal for traditional 1D barcodes). Needless to say, the LCD is still a good debugging tool, and I wanted to include it so that you can see that it’s very easy to use. As always, if you are able to solve this problem, then I encourage you to leave me a comment below the post to share with me and the community.
I’d also like to point out Line 27. In the “hello world” example you’ll see a keyword argument time=2000
to sensor.skip_frames
. Keyword arguments aren’t supported in this context, so be sure to use this syntax shown on Line 27 (especially if you are working through the “hello world”).
Next, let’s perform initializations:
# initialize the LCD # uncomment if you are using the LCD #lcd.init() # initialize the clock clock = time.clock()
You’ll want to uncomment Line 33 if you are using the LCD (see the previous code block).
Line 36 initialize our clock for FPS calculations
From there we’ll create (1) a lookup table and (2) a convenience function for determining the type of barcode:
# barcode type lookup table barcode_type = { image.EAN2: "EAN2", image.EAN5: "EAN5", image.EAN8: "EAN8", image.UPCE: "UPCE", image.ISBN10: "ISBN10", image.EAN13: "EAN13", image.ISBN13: "ISBN13", image.I25: "I25", image.DATABAR: "DATABAR", image.DATABAR_EXP: "DATABAR_EXP", image.CODABAR: "CODABAR", image.CODE39: "CODE39", image.PDF417: "PDF417", image.CODE93: "CODE93", image.CODE128: "CODE128" } def barcode_name(code): # if the code type is in the dictionary, return the value string if code.type() in barcode_type.keys(): return barcode_type[code.type()] # otherwise return a "not defined" string return "NOT DEFINED"
As you can see on Lines 39, where I defined a barcode_type
dictionary, the OpenMV can detect and decode quite a few different barcode styles.
That being said, I didn’t have luck with all of them, so the PDF included with the “Downloads” section of this blog post doesn’t include every type of barcode.
Lines 57-63 define a convenience function for grabbing the barcode type without risk of throwing a Python key exception (the OpenMV does not handle exceptions well).
From there, let’s get down to business and start capturing and processing frames! We’ll begin by starting a while
loop:
# loop over frames and detect + decode barcodes while True: # tick the clock for our FPS counter clock.tick() # grab a frame img = sensor.snapshot()
The first step is to tick the clock for our FPS counter (Line 68).
From there you should grab a frame with sensor.snapshot
(Line 71).
Now, let the fun begin!
We’ve got an image, so let’s see what we can do with it:
# loop over standard barcodes that are detected in the image for code in img.find_barcodes(): # draw a rectangle around the barcode img.draw_rectangle(code.rect(), color=127) # print information in the IDE terminal print("type: {}, quality: {}, payload: {}".format( barcode_name(code), code.quality(), code.payload())) # draw the barcode string on the screen similar to cv2.putText img.draw_string(10, 10, code.payload(), color=127)
Here we’re finding standard, non-QR codes. All we need to do is call img.find_barcodes
(which encapsulates all barcode detection + reading functionality) and loop over the results (Line 74).
Given the detected barcodes we can:
- Draw a bounding box rectangle around the detected barcode (Line 76).
- Print the type, quality, and payload (Lines 79-82).
- Draw the string on the screen (Line 85). Unfortunately (according to the docs) there is no current way to draw the string in a larger font.
That’s really all there is to it!
QR code decoding is done in a similar fashion:
# loop over QR codes that are detected in the image for code in img.find_qrcodes(): # draw a rectangle around the barcode img.draw_rectangle(code.rect(), color=127) # print information in the IDE terminal print("type: QR, payload: {}".format(code.payload())) # draw the barcode string on the screen similar to cv2.putText img.draw_string(10, 10, code.payload(), color=127) # display the image on the LCD # uncomment if you are using the LCD #lcd.display(img) # print the frames per second for debugging print("FPS: {}".format(clock.fps()))
This loop mimics the standard barcode loop, so be sure to review it for details.
Outside of the loop, if you’re using the LCD, you’ll want to display on it (Line 100).
Lastly, we can easily print the FPS (frames per second) in the terminal on Line 103.
OpenMV Barcode Decoding Results.
First, connect your OpenMV cam via USB to your computer.
Then Fire up the IDE as shown in Figure 3.
From there, click the connect button in the lower left.
The IDE may prompt you to update your firmware (which I did without a hitch by clicking the button and waiting about 3-5 minutes).
When you’re ready with your program loaded in the editor, click the green play/program button also in the lower left. This button will set up the OpenMV with your code.
Be patient. It takes about 45-90 seconds for the MicroPython code to compile to machine code and get flashed on the processor. There isn’t a status indicator, so you just need to be patient.
Before long, if you’re printing to the terminal, you’ll see the data such as FPS or barcode information — that’s your queue that everything is working. You’ll also see a live view from the camera sensor in the top right viewfinder.
Now let’s try some barcodes!
In the “Downloads” section, I’ve included a PDF of barcodes for you to print and scan. Here’s what we’re working with:
You can see the results here from the IDE’s built in terminal:
FPS: 2.793296 type: QR, payload: https://hcl.pyimagesearch.com/ FPS: 2.816901 type: QR, payload: https://openmv.io/ FPS: 2.941176 type: QR, payload: http://pyimg.co/dl4cv FPS: 3.831418 type: CODE128, quality: 48, payload: guru FPS: 4.484305 ype: CODE93, quality: 15, payload: OpenMV FPS: 3.849856 type: CODE39, quality: 68, payload: DL4CV FPS: 3.820961 type: DATABAR, quality: 83, payload: 0100000000020183 FPS: 4.191617
Screenshots of each code and the terminal are below:
And finally, here’s a picture of the IDE in action. Notice how it is reading multiple codes, drawing boxes around the barcodes, and also contains a nice color histogram.
Here’s a video of the system in action using the IDE:
The IDE is great for debugging. For a deployable project however, you wouldn’t use the IDE. Instead you’d send the barcode payloads out to an actuator via I2C, SPI, or maybe WiFi to be processed in a database.
The LCD tool is also great for debugging although I found that the required resolution didn’t work for all the barcodes on the barcodes.pdf
file included in the “Downloads”.
Nevertheless, here’s the LCD in action:
Does the OpenMV run OpenCV?
In short, no — the OpenMV does not run OpenCV. The processor wouldn’t be able to handle it.
There are a number of capabilities of the OpenMV, but don’t think of it as a replacement for a Raspberry Pi which can run an OS and OpenCV.
But don’t let that deter you from considering the OpenMV for your project!
There’s plenty of OpenCV-like functionality built in.
You’ll feel at home working with the OpenMV examples and turning one into a solution that works in your project, but don’t expect to paste some OpenCV code into the OpenMV IDE and expect it to work.
Oh, and the best part?
You don’t need to worry about a complex install! If the OpenMV firmware needs to be updated, just click the button in the IDE and it will update over USB in a matter of minutes.
The easy install, and basic image processing capabilities make it a great teaching tool to get someone interested in CV.
It also would do well in specific projects, provided the project aligns with one of the image processing capabilities of OpenMV — just be sure that you don’t need something more powerful before you go down this path.
Can I connect the OpenMV to my Raspberry Pi?
Of course you can but there are more reasons against doing so.
The first reason is: the Raspberry Pi can do (mostly) everything the OpenMV can do, and then some. I2C? Check. SPI? Check. PWM? Check. WiFi? Check.
That said, the Raspberry Pi doesn’t have a high powered RGB LED and two high power IR LEDs like the OpenMV does.
But back to the point: Why would you need duplicate capabilities?
You most-likely don’t.
Instead, you should not think of the OpenMV as a general purpose SBC — it’s not.
The OpenMV is particularly great for specific embedded use cases. Another great use case for the OpenMV might be one where you’re concerned about power draw such as on a battery powered drone.
The second reason is that compiling the QT GUI for the Raspberry Pi would take 2-3 days. This isn’t practical. Sure you could do it once, and keep a handy .img lying around so you don’t have to do it again, but it just doesn’t seem practical to me.
So yes — you can definitely plug in the OpenMV via USB or via a custom header/wires to a Raspberry Pi. I just don’t think it is the wise thing to do.
If I’m wrong, let’s discuss in the comments section.
Where can I get an OpenMV camera as well as accessories?
The OpenMV is very affordable at $65. Think of it as getting a powerful Arduino and a camera all on one board (that runs MicroPython).
You can pick up an OpenMV Cam at the retailers listed on the sales page, and many of the retailers offer free shipping.
Notable retailers include
- SparkFun (for $65, it comes with plastic case and headers)
- Seed Studio
- Robot Shop
There are a few Chinese retailers serving Asia as well as a number of European and UK retailers.
Looking to buy in bulk for your classroom or for a deployment?
If that’s the case, then you can take advantage of the bulk discounts by ordering direct from OpenMV.io. There’s a piecewise function where you can get 10%, 20%, or even 30% off by buying in bulk.
Shields, shields, shields!
There are a number of expansion shields available, so be sure to check the retailers as well as OpenMV direct for purchasing options.
The official shields include:
- WiFi Shield (supports streaming video at 48 Mbps)
- LCD Shield (color!)
- Servo Shield (supports up to 8 servos!)
- Motor Shield (motors, solenoids, or other electromechanicals up to 2A)
- Proto Shield (connect I/O such as a sensor to your OpenMV processor)
- Thermopile Shield (thermal camera shield — it’s no longer sold, but still supported if you can find one)
You’ll need to use your soldering skills in order to attach shields — the headers do not come pre-populated. This is a minor inconvenience, but if you have a soldering iron, you can be up and running in 10 minutes.
It’s also worth noting that all hardware is open source. So if you have electronics skills and need a custom shield and are proficient in Eagle CAD, then you can visit the OpenMV Shield GitHub Repo to select a shield as a starting point to customize for your application.
Do you want a value kit that includes most accessories so you can get started tinkering?
If you order the “Full Set” kit direct from OpenMV.io, you get about 10% off the combined price.
The “Full Set” kit includes 7 pieces:
- 1 – OpenMV Cam M7
- 3 – Shields (Proto Shield, LCD Shield, WiFi Shield)
- 3 – Lenses (IR Lens, Telephoto Lens, Ultra Wide Angle Lens)
What's next? I recommend PyImageSearch University.
30+ total classes • 39h 44m video • Last updated: 12/2021
★★★★★ 4.84 (128 Ratings) • 3,000+ Students Enrolled
I strongly believe that if you had the right teacher you could master computer vision and deep learning.
Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?
That’s not the case.
All you need to master computer vision and deep learning is for someone to explain things to you in simple, intuitive terms. And that’s exactly what I do. My mission is to change education and how complex Artificial Intelligence topics are taught.
If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to successfully and confidently apply computer vision to your work, research, and projects. Join me in computer vision mastery.
Inside PyImageSearch University you'll find:
- ✓ 30+ courses on essential computer vision, deep learning, and OpenCV topics
- ✓ 30+ Certificates of Completion
- ✓ 39h 44m on-demand video
- ✓ Brand new courses released every month, ensuring you can keep up with state-of-the-art techniques
- ✓ Pre-configured Jupyter Notebooks in Google Colab
- ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
- ✓ Access to centralized code repos for all 500+ tutorials on PyImageSearch
- ✓ Easy one-click downloads for code, datasets, pre-trained models, etc.
- ✓ Access on mobile, laptop, desktop, etc.
Summary
In today’s blog post we used the OpenMV to perform barcode decoding.
Aimed at being the “Arduino of Machine Vision”, the OpenMV cam is embedded (no OS) and is expandable via several available shields. It’s also extremely easy to use. You can write code on the OpenMV using MicroPython.
However, it’s important to understand that the OpenMV does not run OpenCV — the processor simply would not be able to handle it. That said, there’s plenty of OpenCV-like functionality built in. Using the OpenMV IDE you can put together your own computer vision applications.
Next week I’ll be interviewing Kwabena Agyeman, the creator of OpenMV.
To be notified when next week’s interview with Kwabena goes live, just enter your email address in the form below!
Download the Source Code and FREE 17-page Resource Guide
Enter your email address below to get a .zip of the code and 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!