Tatsächlicher Kampf | Demonstration der eindimensionalen Codeerkennung und -dekodierung von OpenCV4.8 (Schritte + Quellcode)

Führung

    In diesem Artikel wird hauptsächlich die Demo der eindimensionalen Codeerkennung und -dekodierung in OpenCV4.8 vorgestellt (Schritte + Quellcode).

Hintergrundeinführung

Bild

    Barcode (1D-Barcode) ist die wichtigste Technologie zur Identifizierung von Waren im realen Leben. Gängige Barcodes bestehen aus einem Muster paralleler Linien, die mit schwarzen und weißen Balken mit stark unterschiedlichem Reflexionsvermögen angeordnet sind. Bei der Barcode-Erkennung wird der Barcode in horizontaler Richtung gescannt, um eine Folge binärer Codes zu erhalten, die aus Balken unterschiedlicher Breite und Farbe bestehen, dh die Codeinformationen des Barcodes. Durch die Abstimmung verschiedener Barcode-Kodierungsmethoden kann der Inhalt des Barcodes dekodiert werden. Derzeit unterstützt OpenCV4.8 die Barcodetypen EAN-8, EAN-13, UPC-A und UPC-E.

    Referenzlink:

https://docs.opencv.org/4.8.0/d6/d25/tutorial_barcode_detect_and_decode.html

      

Schritte zur Verwendung

    Der Inhalt dieses Artikels wird mit OpenCV4.8.0 demonstriert. Die spezifischen Schritte sind wie folgt:

【1】Laden Sie OpenCV4.8.0 Release herunter und installieren Sie es

    Adresse: https://opencv.org/releases/

Bild

Bild

【2】Laden Sie das Modell des hochauflösenden Barcode-Detektors herunter

Bild

 Download-Link:

https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode

Legen Sie nach der Dekomprimierung die folgenden zwei Dateien im angegebenen Verzeichnis ab:

Bild

【3】Testcode:

// Barcode_1D_Decoder.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include "pch.h"#include <iostream>#include <opencv2/opencv.hpp>
#define Mode 1  // 0-img_test, 1-cam_test
using namespace std;using namespace cv;
static const Scalar greenColor(0, 255, 0);static const Scalar redColor(0, 0, 255);static const Scalar yellowColor(0, 255, 255);static Scalar randColor(){
   
     RNG &rng = theRNG();  return Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));}
struct TheApp{
   
     Ptr<barcode::BarcodeDetector> bardet;  //! [output]  vector<Point> corners;  vector<string> decode_info;  vector<string> decode_type;  //! [output]  bool detectOnly;
  void cleanup(){
   
       corners.clear();    decode_info.clear();    decode_type.clear();  }
  inline string modeString() const{
   
       return detectOnly ? "<detect>" : "<detectAndDecode>";  }
  void drawResults(Mat &frame) const{
   
       //! [visualize]    for (size_t i = 0; i < corners.size(); i += 4)    {
   
         const size_t idx = i / 4;      const bool isDecodable = idx < decode_info.size()        && idx < decode_type.size()        && !decode_type[idx].empty();      const Scalar lineColor = isDecodable ? greenColor : redColor;      // draw barcode rectangle      vector<Point> contour(corners.begin() + i, corners.begin() + i + 4);      const vector< vector<Point> > contours{ contour };      drawContours(frame, contours, 0, lineColor, 1);      // draw vertices      for (size_t j = 0; j < 4; j++)        circle(frame, contour[j], 2, randColor(), -1);      // write decoded text      if (isDecodable)      {
   
           ostringstream buf;        buf << "[" << decode_type[idx] << "] " << decode_info[idx];        putText(frame, buf.str(), contour[1], FONT_HERSHEY_COMPLEX, 0.8, yellowColor, 1);      }    }    //! [visualize]  }
  void drawFPS(Mat &frame, double fps) const{
   
       ostringstream buf;    buf << modeString()      << " (" << corners.size() / 4 << "/" << decode_type.size() << "/" << decode_info.size() << ") "      << cv::format("%.2f", fps) << " FPS ";    putText(frame, buf.str(), Point(25, 25), FONT_HERSHEY_COMPLEX, 0.8, redColor, 2);  }
  inline void call_decode(Mat &frame){
   
       cleanup();    if (detectOnly)    {
   
         //! [detect]      bardet->detectMulti(frame, corners);      //! [detect]    }    else    {
   
         //! [detectAndDecode]      bardet->detectAndDecodeWithType(frame, decode_info, decode_type, corners);      //! [detectAndDecode]    }  }
  int liveBarCodeDetect(){
   
       VideoCapture cap(0);    if (!cap.isOpened())    {
   
         cout << "Cannot open a camera" << endl;      return 2;    }    Mat frame;    Mat result;    cap >> frame;    cout << "Image size: " << frame.size() << endl;    cout << "Press 'd' to switch between <detect> and <detectAndDecode> modes" << endl;    cout << "Press 'ESC' to exit" << endl;    for (;;)    {
   
         cap >> frame;      if (frame.empty())      {
   
           cout << "End of video stream" << endl;        break;      }      if (frame.channels() == 1)        cvtColor(frame, frame, COLOR_GRAY2BGR);      TickMeter timer;      timer.start();      call_decode(frame);      timer.stop();      drawResults(frame);      drawFPS(frame, timer.getFPS());      imshow("barcode", frame);      const char c = (char)waitKey(1);      if (c == 'd')      {
   
           detectOnly = !detectOnly;        cout << "Mode switched to " << modeString() << endl;      }      else if (c == 27)      {
   
           cout << "'ESC' is pressed. Exiting..." << endl;        break;      }    }    return 0;  }
  int imageBarCodeDetect(const string &in_file, const string &out_file){
   
       Mat frame = imread(in_file, IMREAD_COLOR);    cout << "Image size: " << frame.size() << endl;    cout << "Mode is " << modeString() << endl;    const int count_experiments = 100;    TickMeter timer;    for (size_t i = 0; i < count_experiments; i++)    {
   
         timer.start();      call_decode(frame);      timer.stop();    }    cout << "FPS: " << timer.getFPS() << endl;    drawResults(frame);    if (!out_file.empty())    {
   
         cout << "Saving result: " << out_file << endl;      imwrite(out_file, frame);    }    imshow("barcode", frame);    cout << "Press any key to exit ..." << endl;    waitKey(0);    return 0;  }};

int main(){
   
     string sr_prototxt = "./model/sr.prototxt";  string sr_model = "./model/sr.caffemodel";
  TheApp app;  app.detectOnly = false;  //! [initialize]  try  {
   
       app.bardet = makePtr<barcode::BarcodeDetector>(sr_prototxt, sr_model);  }  catch (const std::exception& e)  {
   
       cout <<"read sr_model failed!" << endl;    cout << e.what() << endl;    return -1;  }  //! [initialize]
  if(Mode)    app.liveBarCodeDetect();  else  {
   
       string inPath = "./imgs/t6.jpg";    string outPath = "./res.jpg";    Mat img = imread(inPath);    app.call_decode(img);    app.drawResults(img);
    imshow("barcode", img);    waitKey();  }  return 0;} 

【4】Bildtest:

Bild

Bild

Bild

Bild

Bild

【5】Videotest:

, Dauer 00:25

      

Eine kurze Beschreibung

    Das Modul stellt verschiedene Barcode-Erkennungsalgorithmen vor.

    Beim Codieren müssen wir zunächst ein cv::barcode::BarcodeDetector-Objekt erstellen. Es verfügt hauptsächlich über drei Mitgliedsfunktionen, die im Folgenden separat vorgestellt werden.

【1】Initialisierung

try {
   
    app.bardet = makePtr<barcode::BarcodeDetector>(sr_prototxt, sr_model); } catch (const std::exception& e) {
   
    cout << "\n---------------------------------------------------------------\n" "Failed to initialize super resolution.\n" "Please, download 'sr.*' from\n" "https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n" "and put them into the current directory.\n" "Or you can leave sr_prototxt and sr_model unspecified.\n" "---------------------------------------------------------------\n"; cout << e.what() << endl; return -1; }

    Wir müssen Variablen erstellen, um die Ausgabe zu speichern. ​​​​​​​​

 vector<Point> corners; vector<string> decode_info; vector<string> decode_type;

【2】Barcode-Erkennung

    Die Methode cv::barcode::BarcodeDetector::detect verwendet einen Algorithmus, der auf Richtungskohärenz basiert. Zuerst berechnen wir den durchschnittlichen quadratischen Gradienten für jedes Pixel. Dann teilen wir das Bild in quadratische Blöcke auf und berechnen die Konsistenz der Gradientenrichtung und die mittlere Gradientenrichtung für jeden Block. Anschließend verketten wir alle Patches mit hoher Konsistenz der Gradientenrichtung und ähnlichen Gradientenrichtungen. In dieser Phase verwenden wir Patches mit mehreren Maßstäben, um die Gradientenverteilung von Barcodes mit mehreren Größen zu erfassen, und wenden eine nicht maximale Unterdrückung an, um doppelte Vorschläge herauszufiltern. Schließlich verwenden wir cv::minAreaRect, um den ROI zu begrenzen und die Ecken des Rechtecks ​​auszugeben.

    Code, der ein Eingabebild erkennt und die Ecken des erkannten Rechtecks ​​ausgibt:

bardet->detectMulti(frame, corners);

[3] Dekodierung

    Die cv::barcode::BarcodeDetector::decode-Methode überskaliert zunächst ( optional ) das Bild (wenn das Bild kleiner als der Schwellenwert ist), schärft das Bild und binarisiert es dann über OTSU oder lokale Binarisierung. Anschließend liest es den Inhalt des Barcodes, indem es die Ähnlichkeit des angegebenen Barcodemusters abgleicht.

    cv::barcode::BarcodeDetector::detectAndDecodedetect kombiniert Dekodierung und Dekodierung in einem Aufruf. Das folgende einfache Beispiel zeigt, wie diese Funktion verwendet wird:

bardet->detectAndDecodeWithType(frame,decode_info,decode_type,corners);

Visualisierungsergebnisse:

for (size_t i = 0; i < corners.size(); i += 4) {
   
    const size_t idx = i / 4; const bool isDecodable = idx < decode_info.size() && idx < decode_type.size() && !decode_type[idx].empty(); const Scalar lineColor = isDecodable ? greenColor : redColor; // draw barcode rectangle vector<Point> contour(corners.begin() + i, corners.begin() + i + 4); const vector< vector<Point> > contours {contour}; drawContours(frame, contours, 0, lineColor, 1); // draw vertices for (size_t j = 0; j < 4; j++) circle(frame, contour[j], 2, randColor(), -1); // write decoded text if (isDecodable) {
   
    ostringstream buf; buf << "[" << decode_type[idx] << "] " << decode_info[idx]; putText(frame, buf.str(), contour[1], FONT_HERSHEY_COMPLEX, 0.8, yellowColor, 1); } }

Bild

Freundliche Tipps:

Die Barcode-Erkennung ist erfolgreich, aber die Dekodierung schlägt fehl: Der Barcode-Rahmen ist rot;

Die Barcode-Erkennung ist erfolgreich und die Dekodierung ist erfolgreich: Der Barcode-Rahmen ist grün und der dekodierte Inhalt ist gelb.

      

Zusammenfassung verwenden

[1] Der Erkennungseffekt von eindimensionalem Code ist besser und die meisten Barcodes können erkannt werden.

[2] Der eindimensionale Code-Dekodierungseffekt ist besser für Standard-Barcodes und eignet sich besser zum Scannen von Codes auf Mobiltelefonen.

【3】Unterstützung für das Hinzufügen ähnlicher Barcodes;

【4】 Die Geschwindigkeit der Videoerkennung und -dekodierung ist hoch, die FPS mit einer Auflösung von 640 x 480 liegt zwischen 40 und 200.

Supongo que te gusta

Origin blog.csdn.net/stq054188/article/details/132257212
Recomendado
Clasificación