cv::QRCodeDetector の使い方【OpenCV/C++】〜QRコードを読み取る〜
cv::QRCodeDetector は OpenCV 標準機能だけで QR コードの検出・デコードができるクラスです。ZBar などの外部ライブラリを追加せずに、detectAndDecode() 1 呼び出しで文字列まで取り出せます。
cv::QRCodeDetector detector;
std::string text = detector.detectAndDecode(img, points);
動作環境
- OpenCV 4.x(4.5 以降を推奨)
- コンパイル例:
g++ -std=c++17 main.cpp `pkg-config --cflags --libs opencv4` -o main
環境構築がまだの方は環境構築ガイドを先にどうぞ。
基本の使い方
完全プログラム
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: ./main <image_path>" << std::endl;
return 1;
}
// 画像の読み込み
cv::Mat img = cv::imread(argv[1]);
if (img.empty()) {
std::cerr << "画像を読み込めませんでした: " << argv[1] << std::endl;
return 1;
}
cv::QRCodeDetector detector;
// QR コードの検出とデコードを一括実行
// points: QR コード四隅の座標(InputOutputArray)
cv::Mat points;
std::string decoded = detector.detectAndDecode(img, points);
if (decoded.empty()) {
std::cout << "QR コードが検出されませんでした" << std::endl;
return 0;
}
std::cout << "デコード結果: " << decoded << std::endl;
// 検出した領域を描画(points は 1×4 の CV_32FC2)
if (!points.empty()) {
// polylines は vector<vector<Point>> を受け取るため変換
std::vector<cv::Point> contour;
for (int i = 0; i < 4; ++i) {
cv::Point2f pt = points.at<cv::Point2f>(0, i);
contour.emplace_back(static_cast<int>(pt.x), static_cast<int>(pt.y));
}
std::vector<std::vector<cv::Point>> contours = {contour};
cv::polylines(img, contours, true, cv::Scalar(0, 255, 0), 3);
}
cv::imshow("QR Result", img);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
実行結果
デコード結果: https://example.com
ウィンドウには QR コード四隅を結んだ緑色の矩形が重畳描画されます。
コード解説
| 行のポイント | 説明 |
|---|---|
cv::QRCodeDetector detector; |
デフォルトコンストラクタで生成するだけで使える |
detector.detectAndDecode(img, points) |
検出 + デコードを 1 呼び出しで完結。戻り値は std::string |
| 戻り値が空文字 | 検出失敗または読み取り不可。エラー例外は投げない |
points.at<cv::Point2f>(0, i) |
points は 1×4 の CV_32FC2。型に注意 |
cv::polylines |
閉じた多角形として描画。isClosed=true を渡す |
引数と戻り値
detectAndDecode()
| 引数 | 型 | 説明 |
|---|---|---|
img |
InputArray |
入力画像(グレースケール・カラー両対応) |
points |
OutputArray |
QR 四隅の座標(1×4, CV_32FC2)。不要なら cv::noArray() |
straight_qrcode |
OutputArray |
射影補正後の QR 画像。省略可(cv::noArray()) |
| 戻り値 | std::string |
デコードされた文字列。失敗時は空文字 |
detect()
| 引数 | 型 | 説明 |
|---|---|---|
img |
InputArray |
入力画像 |
points |
OutputArray |
QR 四隅の座標 |
| 戻り値 | bool |
検出できたか |
decode()
| 引数 | 型 | 説明 |
|---|---|---|
img |
InputArray |
入力画像 |
points |
InputArray |
detect() で得た四隅座標 |
straight_qrcode |
OutputArray |
射影補正後の QR 画像。省略可 |
| 戻り値 | std::string |
デコード文字列。失敗時は空文字 |
実践例
例 1: detect → decode を分けて呼ぶ
検出だけ先に行い、成功時のみデコードする分割パターンです。処理の成否を段階的に確認したい実務では、こちらの方が制御しやすいです。
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: ./main <image_path>" << std::endl;
return 1;
}
cv::Mat img = cv::imread(argv[1]);
if (img.empty()) {
std::cerr << "画像を読み込めませんでした: " << argv[1] << std::endl;
return 1;
}
cv::QRCodeDetector detector;
cv::Mat points;
// Step1: 検出
bool found = detector.detect(img, points);
if (!found) {
std::cout << "QR コードが見つかりませんでした" << std::endl;
return 0;
}
std::cout << "QR コードを検出しました" << std::endl;
// Step2: デコード
cv::Mat straight;
std::string decoded = detector.decode(img, points, straight);
if (decoded.empty()) {
std::cout << "デコードに失敗しました(汚損・傾きが大きい可能性)" << std::endl;
return 0;
}
std::cout << "デコード結果: " << decoded << std::endl;
return 0;
}
例 2: カメラ映像からリアルタイム読み取り
#include <iostream>
#include <opencv2/opencv.hpp>
int main() {
cv::VideoCapture cap(0);
if (!cap.isOpened()) {
std::cerr << "カメラを開けませんでした" << std::endl;
return 1;
}
cv::QRCodeDetector detector;
cv::Mat frame, points;
while (true) {
cap >> frame;
if (frame.empty()) break;
std::string decoded = detector.detectAndDecode(frame, points);
if (!decoded.empty()) {
std::cout << "読み取り: " << decoded << std::endl;
// 検出枠を描画
if (!points.empty()) {
std::vector<cv::Point> contour;
for (int i = 0; i < 4; ++i) {
cv::Point2f pt = points.at<cv::Point2f>(0, i);
contour.emplace_back(static_cast<int>(pt.x),
static_cast<int>(pt.y));
}
std::vector<std::vector<cv::Point>> contours = {contour};
cv::polylines(frame, contours, true, cv::Scalar(0, 255, 0), 2);
}
}
cv::imshow("QR Scanner", frame);
// q キーで終了
if (cv::waitKey(30) == 'q') break;
}
cv::destroyAllWindows();
return 0;
}
実行すると、カメラ映像ウィンドウが開き、QR コードが映ると緑枠が表示されターミナルに内容が出力されます。
つまずきポイント
⚠️ points の型を CV_32FC2 と意識する
detectAndDecode() が返す points は 1×4 の行列で、要素型は cv::Point2f(CV_32FC2)です。int 型の cv::Point でアクセスすると assertion エラーになります。
// NG: 型不一致でクラッシュ
cv::Point pt = points.at<cv::Point>(0, i);
// OK
cv::Point2f pt = points.at<cv::Point2f>(0, i);
⚠️ 戻り値が空文字でも例外は出ない
detectAndDecode() は検出・デコードに失敗しても例外を投げず、空の std::string を返します。戻り値のチェックを省略すると、空文字のまま処理が続いてバグの原因になります。必ず decoded.empty() で分岐してください。
⚠️ グレースケール変換は不要(でも有効)
cv::QRCodeDetector はカラー画像をそのまま受け付けます。ただし、照明条件が悪い場合はあらかじめグレースケール変換や二値化を施すと検出精度が上がることがあります。cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY) を前処理として試してみてください。
関連する関数
- cv::polylines — 検出した QR コードの輪郭描画に使用
- cv::VideoCapture — カメラ映像からのリアルタイム読み取り
- cv::cvtColor — グレースケール変換による前処理
まとめ
cv::QRCodeDetector は外部ライブラリ不要で QR コードの検出・デコードを完結できます。detectAndDecode() で手軽に、detect() + decode() の分割呼び出しで段階的な制御が可能です。戻り値の空文字チェックと points の型(CV_32FC2)に注意すれば、実務のカメラ検査ラインや組込システムでもそのまま使えます。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/API(C++製・OpenCV 4.10)を開発しています。顔認証システムへの組み込み実績多数。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

