QT Qカメラを使用しているウェブカメラでバーコードスキャナを実装する方法


数日前、私はblog post QtとC +を使用してデスクトップバーコードリーダーアプリケーションを実装する方法について.アプリケーションはまだイメージモードをサポートしています.この記事では、私はリアルタイムでバーコードをスキャンするアプリケーションに権限を与えるためにウェブカメラのサポートを追加するつもりです.

のQmakeの設定をCMake


Qtのアプリケーションでのウェブカメラのサポートを追加するには、我々はインポートする必要がありますQCamera クラスからQtMultimedia 図書館.私のWindows Qt環境では、私はQtQtMultimedia 図書館.によるとQt documentation , 私たちはQCamera Qt 5のクラス.
そこで、QTメンテナンスツールを実行してQT 5.12.11をインストールする必要があります.

その後、ビルドツールをダウングレードするパス環境変数を更新します.

QCameraヘッダーファイルはQt/5.12.11/mingw73_64/include/QtMultimedia/qcamera.h .
インCMakeLists.txt ファイルをQtのバージョンを5に変更しますQtMultimedia ライブラリ
cmake_minimum_required(VERSION 3.5)

project(BarcodeReader VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if (CMAKE_HOST_WIN32)
    link_directories("${PROJECT_SOURCE_DIR}/platform/windows/lib/") 
elseif(CMAKE_HOST_UNIX)
    link_directories("${PROJECT_SOURCE_DIR}/platform/linux/")
endif()
include_directories("${PROJECT_SOURCE_DIR}/include/")

find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt5MultimediaWidgets REQUIRED)

set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mainwindow.h
        mainwindow.ui
        myvideosurface.h
        myvideosurface.cpp
)

add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})

if (CMAKE_HOST_WIN32)
    target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets Qt5::MultimediaWidgets "DBRx64")    
elseif(CMAKE_HOST_UNIX)
    target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Widgets Qt5::MultimediaWidgets "DynamsoftBarcodeReader")
endif()

if(CMAKE_HOST_WIN32)
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
        COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/platform/windows/bin/"      
        $<TARGET_FILE_DIR:${PROJECT_NAME}>)
endif()
The myvideosurface.h ファイルとmyvideosurface.cpp ファイルは、ウェブカメラのプレビューを表示し、リアルタイムでバーコードを認識するために使用されます.次のセクションでの実装についてお話します.

リアルタイムバーコードスキャン


qameraにはsetViewfinder() ウェブカメラのプレビューを表示するために使用できる関数.のサポートパラメータsetViewfinder() 含めるQVideoWidget , QGraphicsVideoItem and QAbstractVideoSurface .
私の目標は、バーコード検出用のウェブカメラからプレビューフレームを取得することです.したがって、私はサブクラスQAbstractVideoSurface でフレームデータを取得するpresent() メソッド:
を作成するmyvideosurface.h ファイル
#ifndef MYVIDEOSURFACE_H
#define MYVIDEOSURFACE_H

#include <QImage>
#include <QPixmap>
#include <QDebug>
#include <QCamera>
#include <QCameraInfo>
#include <QAbstractVideoSurface>
#include <QLabel>
#include <QDateTime>

#include "DynamsoftCommon.h"
#include "DynamsoftBarcodeReader.h"

QT_BEGIN_NAMESPACE
namespace Ui
{
    class MainWindow;
}
QT_END_NAMESPACE

class MyVideoSurface : public QAbstractVideoSurface
{
    Q_OBJECT
private:
    Ui::MainWindow *ui;
    void *reader;
    bool is_detecting;

public:
    MyVideoSurface(QObject *parent, Ui::MainWindow *ui, void *reader);
    ~MyVideoSurface();

    void reset();

    QList<QVideoFrame::PixelFormat>
    supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const;

    bool present(const QVideoFrame &frame);
};
#endif // MYVIDEOSURFACE_H

のコンストラクタMyVideoSurface クラスはAを取るQObject ポインタUi::MainWindow ポインタとvoid ポインタ.The Ui::MainWindow ポインタは全てのUIウィジェットにアクセスするために使用されます.The void *reader ポインタを使用してバーコードを検出します.
次に、私はMyVideoSurface.cpp の実装を追加するファイルMyVideoSurface クラス.
The supportedPixelFormats() ウェブカメラのサポートされているピクセル形式を取得することです.どのフォーマットを使うべきですか.正直、私は知りません.私の使用QVideoFrame::Format_RGB24 初めに、しかしそれはQVideoFrame::Format_RGB24 私のウェブカメラでサポートされていません.エラーメッセージによるとQVideoFrame::Format_ARGB32 代わりに
QList<QVideoFrame::PixelFormat> MyVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const
{
    return QList<QVideoFrame::PixelFormat>()
               << QVideoFrame::Format_RGB32;
}
インpresent() 関数は、QVideoFrame オブジェクトを変換し、QImage 対象:
bool MyVideoSurface::present(const QVideoFrame &frame)
{
    if (frame.isValid() && is_detecting)
    {
        QVideoFrame cloneFrame(frame);
        cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
        const QImage img(cloneFrame.bits(),
                         cloneFrame.width(),
                         cloneFrame.height(),
                         QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat()));

        cloneFrame.unmap();

        return true;
    }
    return false;
}

プレビューフレームを表示するには、フレームデータのコピーを作成する必要があります.
QImage cp = img.copy();
私のケースでは、私はQVideoFrame オブジェクトを垂直方向に反転します.私はイメージを反転することができますQImage::mirrored() 機能
cp = cp.mirrored(false, true);
それから、私は電話しますDBR_DecodeBuffer() フレーム内のバーコードを検出し、画像の境界ボックスを描画するには、次の手順に従います.
int ret = DBR_DecodeBuffer(reader, (unsigned char *)cp.bits(), cp.width(), cp.height(), cp.bytesPerLine(), IPF_ARGB_8888, "");

DBR_GetAllTextResults(reader, &handler);

QPixmap pm = QPixmap::fromImage(cp);
QPainter painter(&pm);
painter.setPen(Qt::red);

QString out = "";
TextResult **results = handler->results;
for (int index = 0; index < handler->resultsCount; index++)
{
    LocalizationResult* localizationResult = results[index]->localizationResult;
    out += "Index: " + QString::number(index) + ", Elapsed time: " + QString::number(start.msecsTo(end)) + "ms\n";
    out += "Barcode format: " + QString(results[index]->barcodeFormatString) + "\n";
    out += "Barcode value: " + QString(results[index]->barcodeText) + "\n";
    out += "Bounding box: (" + QString::number(localizationResult->x1) + ", " + QString::number(localizationResult->y1) + ") "
    + "(" + QString::number(localizationResult->x2) + ", " + QString::number(localizationResult->y2) + ") "
    + "(" + QString::number(localizationResult->x3) + ", " + QString::number(localizationResult->y3) + ") "
    + "(" + QString::number(localizationResult->x4) + ", " + QString::number(localizationResult->y4) + ")\n";
    out += "----------------------------------------------------------------------------------------\n";

    painter.drawLine(localizationResult->x1, localizationResult->y1, localizationResult->x2, localizationResult->y2);
    painter.drawLine(localizationResult->x2, localizationResult->y2, localizationResult->x3, localizationResult->y3);
    painter.drawLine(localizationResult->x3, localizationResult->y3, localizationResult->x4, localizationResult->y4);
    painter.drawLine(localizationResult->x4, localizationResult->y4, localizationResult->x1, localizationResult->y1);
}

DBR_FreeTextResults(&handler);

painter.end();
最後に、ラベルにイメージを表示し、テキストボックスにバーコード認識結果を表示します.
ui->label->setPixmap(pm.scaled(ui->label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
ui->textEdit_results->setText(out);
これまでmyvideosurface 出来上がった.私は行くことができますmainwindow.cpp カメラコントロールロジックのコードを追加するには
開けるmainwindow.ui Qtの作成者とカメラのコントロールボタンを追加します.

MainWindow カメラのステータスを確認し、カメラオブジェクトと表面オブジェクトを初期化します.
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
if (cameras.size() > 0) 
{
    for( int i = 0; i < cameras.count(); ++i )
    { 
        QCameraInfo cameraInfo = cameras.at(i);
        qDebug() << cameraInfo.deviceName();
        qDebug() << cameraInfo.description();
        camera = new QCamera(cameraInfo);
        surface = new MyVideoSurface(this, ui, reader);
        camera->setViewfinder(surface);
        break;
    }
}
else {
    ui->pushButton_open->setEnabled(false);
    ui->pushButton_stop->setEnabled(false);
}
その後、ボタンClickイベントを対応する関数にバインドします.
connect(ui->pushButton_open, SIGNAL(clicked()), this, SLOT(startCamera()));
connect(ui->pushButton_stop, SIGNAL(clicked()), this, SLOT(stopCamera()));

void MainWindow::startCamera()
{
    surface->reset();
    camera->start();
}

void MainWindow::stopCamera()
{
    camera->stop();
}
バーコードスキャナを使用する準備が整いました.アプリケーションを構築して実行します
mkdir build
cd build
cmake -G "MinGW Makefiles" ..
cmake --build .
BarcodeReader.exe

ソースコード


https://github.com/yushulx/Qt-desktop-barcode-reader