Printed Digit Recognition via Camera Capture with OpenCV

This project implements optical character recognition for printed digits using OpenCV camera capture and template matching. The system processes video frames, isolates digit regions, compares them against stored templates, and transmits results via serial communication.

#include <opencv2/opencv.hpp>
#include "SerialInterface.hpp"

using namespace cv;

int main() {
    VideoCapture camera(2);
    if (!camera.isOpened()) return -1;

    SerialInterface serial("/dev/ttyUSB0");
    serial.configure(115200, 8, 'N', 1);

    Mat frame, processed, digitRegion;
    Rect boundingBox;
    bool running = true;

    while (running) {
        camera >> frame;
        cvtColor(frame, processed, COLOR_BGR2GRAY);
        threshold(processed, processed, 200, 255, THRESH_BINARY);

        vector<vector>> contours;
        vector<vec4i> hierarchy;
        findContours(processed, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE);
        
        for (auto& contour : contours) {
            boundingBox = boundingRect(contour);
            float aspect = (float)boundingBox.width / boundingBox.height;
            
            if (boundingBox.width >= 100 && boundingBox.height >= 100 &&
                boundingBox.width <= 300 && boundingBox.height <= 400 &&
                aspect > 0.75 && aspect < 0.8) {
                
                digitRegion = frame(boundingBox);
                Mat digitBinary;
                cvtColor(digitRegion, digitBinary, COLOR_BGR2GRAY);
                threshold(digitBinary, digitBinary, 200, 255, THRESH_BINARY_INV);
                resize(digitBinary, digitBinary, Size(182, 234));
            }
        }

        vector<mat> digitTemplates;
        for (int i = 1; i < 10; i++) {
            Mat templateImg = imread(format("%d.png", i), IMREAD_GRAYSCALE);
            threshold(templateImg, templateImg, 0, 255, THRESH_BINARY_INV);
            digitTemplates.push_back(templateImg);
        }

        int minDifference = INT_MAX;
        int identifiedDigit = 0;

        for (int i = 0; i < digitTemplates.size(); i++) {
            Mat differenceMap;
            absdiff(digitTemplates[i], digitBinary, differenceMap);
            int diffSum = sum(differenceMap)[0];
            
            if (diffSum < minDifference) {
                minDifference = diffSum;
                identifiedDigit = i + 1;
            }
        }

        if (identifiedDigit != 0) {
            serial.transmit(format("Detected: %d", identifiedDigit));
        }

        if (waitKey(30) == 'q') running = false;
    }
    return 0;
}</mat></vec4i></vector>

Camera Configuration

USB camera parameters can be inspecetd using v4l2-ctl:

v4l2-ctl -d /dev/video0 --all

Common parameters include:

Video Capture:
  Width/Height: 1280/720
  Pixel Format: 'MJPG'
  Frames per second: 30.000

Plaftorm-Specific Challenges

When porting to Jetson Nano, camera access issues may arise due to GStreamer pipeline requirements. Test camera functionality using:

gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,format=YUY2,width=640,height=480 ! autovideosink

Verify supported formats with:

v4l2-ctl -d /dev/video0 --list-formats

Alternative approaches include using VLC for camera access:

cvlc v4l2:///dev/video0

For development envirnoment setup on ARM platforms, consider:

sudo apt-get install qt5-default
sudo apt-get build-dep qt5-default

Tags: OpenCV TemplateMatching SerialCommunication JetsonNano GStreamer

Posted on Thu, 13 Aug 2026 16:50:16 +0000 by JoeBrewer