OpenCVは、画像処理や動画処理、物体検出、特徴点抽出、カメラキャリブレーション、DNN推論などに使われる代表的なコンピュータビジョンライブラリです。
C++、Python、Javaなど複数の言語から利用できますが、OpenCVの主要APIはC++を中心に設計されているため、C++から使うとライブラリ本来の構造を理解しやすいという特徴があります。
C++版OpenCVは、リアルタイム処理や製品開発、産業用画像処理、ロボット、組み込みシステムなどでよく使われます。
Python版より環境構築やビルドはやや複雑ですが、処理速度やメモリ制御、アプリケーションへの組み込みやすさという点で大きなメリットがあります。
C++でOpenCVを使うメリット
高速な画像処理がしやすい
C++は実行速度が速く、リアルタイム性が求められる画像処理に向いています。
たとえば、カメラ映像を1フレームずつ処理する場合や、産業用検査装置で大量の画像を短時間で解析する場合には、C++版OpenCVがよく使われます。
ただし、Python版OpenCVも内部ではC++実装を呼び出しているため、単純に cv2.Canny() や cv2.GaussianBlur() のような関数を呼ぶだけであれば、Pythonでも十分高速な場合があります。
C++版が特に有利になるのは、アプリケーション全体を低遅延に作りたい場合や、ピクセル単位の独自処理を多く書く場合、組み込み機器や製品に組み込む場合です。
製品開発や組み込みに向いている
C++版OpenCVは、実務の画像処理システムでよく使われます。
たとえば、以下のような分野です。
- 工場の外観検査
- 監視カメラシステム
- ロボットビジョン
- 自動運転・ADAS
- 医療画像処理
- ドローン映像解析
- 産業用カメラ制御
C++は処理速度だけでなく、既存のC++アプリケーションやネイティブライブラリとの連携もしやすいため、業務システムやハードウェア制御を含む開発に向いています。
OpenCVの仕組みを理解しやすい
OpenCVでは、cv::Mat、cv::Point、cv::Rect、cv::Scalar などのC++クラスが多く使われます。
C++でOpenCVを学ぶと、画像データがどのようにメモリ上で扱われているか、コピーと参照がどのように動くか、処理の入力と出力がどのように渡されるかを理解しやすくなります。
Python版ではこれらの細かい部分が隠れているため、学習初期には便利ですが、実務で高速化や不具合調査を行う場合にはC++の理解が役立ちます。
C++ OpenCVの基本構造
基本的なコード
C++でOpenCVを使う最小構成は、以下のようになります。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::imshow("Image", image);
cv::waitKey(0);
return 0;
}
このコードでは、画像を読み込み、表示し、キー入力があるまでウィンドウを開いたままにしています。
opencv2/opencv.hpp について
#include <opencv2/opencv.hpp> は、OpenCVの主要な機能をまとめて読み込むヘッダです。
学習用や小規模なサンプルコードでは便利ですが、実務では必要なヘッダだけを読み込むこともあります。
たとえば、画像の読み込みと表示だけであれば、以下のように書くこともできます。
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
必要なヘッダだけにすると、依存関係が明確になり、コンパイル時間を抑えやすくなります。
cv::Matとは
OpenCVで最も重要なクラス
C++版OpenCVで最も重要なのが cv::Mat です。
cv::Mat は画像データを表すためのクラスです。
cv::Mat image;
画像は、画素が縦横に並んだデータです。
たとえば、640×480のカラー画像であれば、概念的には以下のようなデータ構造になります。
高さ480 × 幅640 × 3チャンネル
C++でOpenCVを使う場合、ほとんどの画像処理関数は cv::Mat を入力や出力として受け取ります。
cv::Matの行と列
cv::Mat では、第1引数が行数、第2引数が列数です。
cv::Mat image(480, 640, CV_8UC3);
これは、幅640px、高さ480pxのカラー画像を作るという意味です。
注意点として、画像サイズを考えるときは「幅 × 高さ」で表現することが多いですが、cv::Mat のコンストラクタでは「高さ、幅」の順に指定します。
cv::Matの型
OpenCVでは、画像の画素型を次のように表します。
CV_8UC1
CV_8UC3
CV_32FC1
CV_64FC1
意味は以下の通りです。
CV_[ビット深度][符号・型]C[チャンネル数]
代表的な型は以下です。
| 型 | 意味 |
|---|---|
CV_8UC1 | 8bit unsigned char、1チャンネルの画像 |
CV_8UC3 | 8bit unsigned char、3チャンネルの画像 |
CV_32FC1 | 32bit float、1チャンネルの画像 |
CV_64FC1 | 64bit double、1チャンネルの画像 |
たとえば、黒いカラー画像を作る場合は以下のように書きます。
cv::Mat image(480, 640, CV_8UC3, cv::Scalar(0, 0, 0));
OpenCVのカラー形式
OpenCVは基本的にBGR順
OpenCVでカラー画像を扱うときに重要なのが、色の順番です。
一般的にはカラー画像はRGB順で考えることが多いですが、OpenCVでは通常BGR順で扱います。
つまり、1ピクセルの値は以下の順番です。
Blue, Green, Red
カラー画像のピクセルにアクセスする場合は、以下のようになります。
cv::Vec3b pixel = image.at<cv::Vec3b>(y, x);
uchar blue = pixel[0];
uchar green = pixel[1];
uchar red = pixel[2];
RGBに変換する方法
他のライブラリやGUI、Web系の処理と連携する場合、RGB順に変換したいことがあります。
その場合は cv::cvtColor() を使います。
cv::Mat rgb;
cv::cvtColor(image, rgb, cv::COLOR_BGR2RGB);
逆に、RGB画像をOpenCVで扱うためにBGRへ変換する場合は以下です。
cv::Mat bgr;
cv::cvtColor(rgb, bgr, cv::COLOR_RGB2BGR);
画像を読み込む
imread()の基本
画像を読み込むには cv::imread() を使います。
cv::Mat image = cv::imread("sample.jpg");
読み込みに失敗した場合、image.empty() が true になります。
そのため、実務では必ず読み込みチェックを入れるべきです。
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
画像が読み込めない原因としては、以下がよくあります。
- ファイルパスが間違っている
- 実行ディレクトリが想定と違う
- ファイル名や拡張子が違う
- 画像ファイルが壊れている
- 日本語パスや特殊文字を含むパスで問題が起きている
- 対応していない画像形式を読み込もうとしている
グレースケールで読み込む
画像を最初からグレースケールで読み込みたい場合は、以下のようにします。
cv::Mat gray = cv::imread("sample.jpg", cv::IMREAD_GRAYSCALE);
アルファチャンネル込みで読み込む
PNG画像などでアルファチャンネルを保持したい場合は、cv::IMREAD_UNCHANGED を使います。
cv::Mat image = cv::imread("sample.png", cv::IMREAD_UNCHANGED);
通常の imread() では、アルファチャンネルが保持されない場合があります。
画像を表示する
imshow()の基本
画像を表示するには cv::imshow() を使います。
cv::imshow("Image", image);
第1引数はウィンドウ名、第2引数は表示する画像です。
waitKey()の役割
imshow() の後には、通常 cv::waitKey() を使います。
cv::waitKey(0);
waitKey(0) は、キー入力があるまで待機するという意味です。
これを書かないと、プログラムがすぐ終了してウィンドウが一瞬で閉じることがあります。
動画処理では、以下のように短い待ち時間を指定することが多いです。
cv::waitKey(1);
終了時にウィンドウを閉じたい場合は、以下を使うこともあります。
cv::destroyAllWindows();
画像を保存する
imwrite()の基本
画像を保存するには cv::imwrite() を使います。
cv::imwrite("output.jpg", image);
たとえば、読み込んだ画像を別名で保存する場合は以下です。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::imwrite("output.jpg", image);
return 0;
}
グレースケール変換
cvtColor()を使う
カラー画像をグレースケールに変換するには、cv::cvtColor() を使います。
cv::Mat gray;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
完全なコード例は以下です。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::Mat gray;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::imshow("Original", image);
cv::imshow("Gray", gray);
cv::waitKey(0);
return 0;
}
グレースケール化は、二値化、エッジ検出、輪郭抽出などの前処理としてよく使われます。
二値化
threshold()の基本
二値化とは、画像を白と黒の2値に分ける処理です。
cv::threshold(gray, binary, 128, 255, cv::THRESH_BINARY);
各引数の意味は以下です。
cv::threshold(src, dst, thresholdValue, maxValue, thresholdType);
| 引数 | 意味 |
|---|---|
src | 入力画像 |
dst | 出力画像 |
thresholdValue | しきい値 |
maxValue | しきい値を超えた場合の値 |
thresholdType | 二値化の種類 |
基本的なコード例は以下です。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::Mat gray, binary;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::threshold(gray, binary, 128, 255, cv::THRESH_BINARY);
cv::imshow("Gray", gray);
cv::imshow("Binary", binary);
cv::waitKey(0);
return 0;
}
実務では固定しきい値だけでは不十分な場合がある
128 のような固定しきい値は分かりやすいですが、実務では照明条件や画像の明るさによって結果が大きく変わります。
そのため、実務では大津の二値化を使うことがあります。
cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
また、照明ムラがある画像では適応的二値化を使うこともあります。
cv::adaptiveThreshold(
gray,
binary,
255,
cv::ADAPTIVE_THRESH_GAUSSIAN_C,
cv::THRESH_BINARY,
11,
2
);
ぼかし処理
GaussianBlur()の基本
ノイズ除去や前処理には、ぼかし処理がよく使われます。
代表的なのが cv::GaussianBlur() です。
cv::GaussianBlur(image, blurred, cv::Size(5, 5), 0);
コード例は以下です。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::Mat blurred;
cv::GaussianBlur(image, blurred, cv::Size(5, 5), 0);
cv::imshow("Original", image);
cv::imshow("Blurred", blurred);
cv::waitKey(0);
return 0;
}
cv::Size(5, 5) はカーネルサイズです。
一般的には、3×3、5×5、7×7 のような正の奇数サイズを使います。
エッジ検出
Canny()の基本
画像の輪郭や境界線を検出するには、cv::Canny() がよく使われます。
cv::Canny(gray, edges, 100, 200);
基本的なコード例は以下です。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::Mat gray, edges;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::Canny(gray, edges, 100, 200);
cv::imshow("Original", image);
cv::imshow("Edges", edges);
cv::waitKey(0);
return 0;
}
Cannyはしきい値調整が重要
100, 200 はあくまで例です。
どの値が適切かは画像によって変わります。
ノイズが多い画像では、Cannyの前にぼかしを入れることがあります。
cv::Mat gray, blurred, edges;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 1.5);
cv::Canny(blurred, edges, 50, 150);
実務では、エッジが出すぎる場合、出なさすぎる場合があるため、画像に合わせてしきい値を調整します。
リサイズ
resize()の基本
画像サイズを変更するには cv::resize() を使います。
cv::resize(image, resized, cv::Size(300, 200));
これは、幅300px、高さ200pxにリサイズする例です。
比率で縮小・拡大する場合は以下のように書きます。
cv::resize(image, resized, cv::Size(), 0.5, 0.5);
これは横方向・縦方向をそれぞれ50%にするという意味です。
ROIによる画像の切り出し
ROIとは
ROIは、Region of Interestの略で、画像の中で処理対象にしたい領域のことです。
OpenCVでは、cv::Rect を使って画像の一部を切り出せます。
cv::Rect roi(100, 50, 200, 150);
cv::Mat cropped = image(roi);
cv::Rect の引数は以下です。
cv::Rect(x, y, width, height)
clone()が必要な場合
以下のように書いた場合、cropped は元画像の一部を参照しているだけの場合があります。
cv::Mat cropped = image(roi);
完全に別データとしてコピーしたい場合は、clone() を使います。
cv::Mat croppedCopy = image(roi).clone();
ROIの範囲外アクセスに注意
ROIが画像の範囲を超えると、エラーになることがあります。
安全に処理したい場合は、画像全体の範囲と重なる部分だけを使うようにします。
cv::Rect roi(100, 50, 200, 150);
cv::Rect imageRect(0, 0, image.cols, image.rows);
roi = roi & imageRect;
if (roi.width > 0 && roi.height > 0) {
cv::Mat cropped = image(roi).clone();
}
図形や文字の描画
線を描く
画像上に線を描くには cv::line() を使います。
cv::line(
image,
cv::Point(10, 10),
cv::Point(200, 200),
cv::Scalar(0, 255, 0),
2
);
四角形を描く
四角形を描くには cv::rectangle() を使います。
cv::rectangle(
image,
cv::Rect(50, 50, 200, 100),
cv::Scalar(255, 0, 0),
2
);
円を描く
円を描くには cv::circle() を使います。
cv::circle(
image,
cv::Point(150, 150),
50,
cv::Scalar(0, 0, 255),
3
);
文字を書く
文字を書くには cv::putText() を使います。
cv::putText(
image,
"OpenCV",
cv::Point(50, 50),
cv::FONT_HERSHEY_SIMPLEX,
1.0,
cv::Scalar(255, 255, 255),
2
);
cv::Scalar() の色指定もBGR順です。
cv::Scalar(Blue, Green, Red)
輪郭抽出
findContours()の基本
物体の形状や領域を検出したい場合には、輪郭抽出を使います。
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
基本的なコード例は以下です。
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::Mat gray, binary;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::threshold(gray, binary, 128, 255, cv::THRESH_BINARY);
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
cv::drawContours(image, contours, -1, cv::Scalar(0, 0, 255), 2);
cv::imshow("Contours", image);
cv::waitKey(0);
return 0;
}
輪郭抽出で注意すべき点
findContours() は、基本的に白い領域を対象物、黒い領域を背景として扱います。
そのため、二値化した結果が逆になっている場合は、THRESH_BINARY_INV を使うことがあります。
cv::threshold(gray, binary, 128, 255, cv::THRESH_BINARY_INV);
輪郭抽出は、以下のような用途でよく使われます。
- 物体の個数を数える
- 面積を測る
- 外接矩形を求める
- 形状を判定する
- 欠陥や異物を検出する
カメラ映像を扱う
VideoCaptureの基本
Webカメラや動画ファイルを扱うには、cv::VideoCapture を使います。
Webカメラを開く場合は以下です。
cv::VideoCapture cap(0);
0 は通常、最初のカメラを意味します。
ただし、カメラ番号は環境によって異なります。
複数カメラが接続されている場合は、1 や 2 を指定する必要があることもあります。
カメラ映像を表示するサンプル
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::VideoCapture cap(0);
if (!cap.isOpened()) {
std::cerr << "カメラを開けませんでした。" << std::endl;
return -1;
}
while (true) {
cv::Mat frame;
cap >> frame;
if (frame.empty()) {
break;
}
cv::imshow("Camera", frame);
if ((cv::waitKey(1) & 0xFF) == 27) {
break;
}
}
return 0;
}
27 はEscキーです。
環境によっては waitKey() の戻り値に上位ビットが含まれることがあるため、以下のように書くとより安全です。
(cv::waitKey(1) & 0xFF) == 27
動画ファイルを読み込む
動画ファイルを読み込む場合は、ファイルパスを指定します。
cv::VideoCapture cap("movie.mp4");
カメラや動画の読み込みでは、コーデック、OS、バックエンドの違いによって挙動が変わることがあります。
WindowsではDirectShowやMedia Foundation、LinuxではV4L2、macOSではAVFoundationなどが関係する場合があります。
OpenCVの主要モジュール
OpenCVは、複数のモジュールに分かれています。
代表的なモジュールは以下です。
| モジュール | 役割 |
|---|---|
core | 基本データ構造、行列演算、cv::Mat |
imgproc | 画像処理、フィルタ、変換、輪郭抽出 |
imgcodecs | 画像ファイルの読み書き |
highgui | 画像表示、簡易GUI |
videoio | カメラ、動画ファイル入出力 |
features2d | 特徴点検出、特徴量記述 |
objdetect | 顔検出などの物体検出 |
dnn | 深層学習モデルの推論 |
calib3d | カメラキャリブレーション、3D復元 |
ml | 機械学習 |
初心者が最初に使うことが多いのは、core、imgproc、imgcodecs、highgui、videoio あたりです。
C++ OpenCVの環境構築
Windowsの場合
Windowsでは、主に以下の方法があります。
- OpenCV公式ビルドを使う
- Visual Studioにincludeパスとlibパスを設定する
- DLLへのPATHを通す
- vcpkgを使ってインストールする
- ソースからビルドする
最近は、vcpkgを使う方法もよく使われます。
vcpkg install opencv4
Windowsでは、OpenCVのDLLが見つからずに実行エラーになることがあります。
たとえば、以下のようなDLLです。
opencv_worldxxx.dll
opencv_corexxx.dll
opencv_imgprocxxx.dll
opencv_imgcodecsxxx.dll
opencv_highguixxx.dll
opencv_world はOpenCVのビルド構成によって存在する場合としない場合があります。
macOSの場合
macOSでは、Homebrewを使う方法が一般的です。
brew install opencv
CMakeからOpenCVが見つからない場合は、OpenCV_DIR や CMAKE_PREFIX_PATH の指定が必要になることがあります。
Ubuntu / Debianの場合
UbuntuやDebianでは、APTでインストールできます。
sudo apt update
sudo apt install libopencv-dev
ただし、APTで入るOpenCVのバージョンはディストリビューションに依存します。
最新バージョンを使いたい場合は、ソースビルド、vcpkg、Conan、Dockerなどを検討します。
CMakeでOpenCVを使う
基本的な構成
C++でOpenCVを使う場合、CMakeを使うのが一般的です。
ディレクトリ構成の例は以下です。
project/
CMakeLists.txt
main.cpp
sample.jpg
CMakeLists.txtの例
cmake_minimum_required(VERSION 3.10)
project(OpenCVSample)
set(CMAKE_CXX_STANDARD 17)
find_package(OpenCV REQUIRED)
add_executable(OpenCVSample main.cpp)
target_link_libraries(OpenCVSample ${OpenCV_LIBS})
ビルド方法
mkdir build
cd build
cmake ..
cmake --build .
実行ファイルの場所や名前は、OSやビルド環境によって変わります。
CMakeでOpenCVが見つからない場合は、OpenCV_DIR を指定します。
cmake -DOpenCV_DIR=/path/to/opencv/build ..
Windowsの場合は、たとえば以下のようなパスになることがあります。
C:/opencv/build
ピクセルアクセス
グレースケール画像の場合
グレースケール画像の1ピクセルにアクセスするには、以下のように書きます。
uchar value = gray.at<uchar>(y, x);
値を書き換える場合は以下です。
gray.at<uchar>(y, x) = 255;
カラー画像の場合
カラー画像では、cv::Vec3b を使います。
cv::Vec3b pixel = image.at<cv::Vec3b>(y, x);
uchar blue = pixel[0];
uchar green = pixel[1];
uchar red = pixel[2];
値を書き換える場合は以下です。
image.at<cv::Vec3b>(y, x)[0] = 255;
image.at<cv::Vec3b>(y, x)[1] = 0;
image.at<cv::Vec3b>(y, x)[2] = 0;
これは青色になります。
OpenCVではBGR順である点に注意してください。
実務でよく使う画像処理の流れ
基本的な処理フロー
実務で画像処理を行う場合、以下のような流れになることが多いです。
画像読み込み
↓
グレースケール化
↓
ノイズ除去
↓
二値化
↓
輪郭抽出
↓
面積・座標・形状を計算
↓
結果を描画・保存
サンプルコード
以下は、一定以上の面積を持つ領域を検出し、赤枠で囲む例です。
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::Mat gray, blurred, binary;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::GaussianBlur(gray, blurred, cv::Size(5, 5), 0);
cv::threshold(blurred, binary, 128, 255, cv::THRESH_BINARY);
std::vector<std::vector<cv::Point>> contours;
cv::findContours(binary, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (const auto& contour : contours) {
double area = cv::contourArea(contour);
if (area > 500) {
cv::Rect rect = cv::boundingRect(contour);
cv::rectangle(image, rect, cv::Scalar(0, 0, 255), 2);
}
}
cv::imshow("Result", image);
cv::waitKey(0);
return 0;
}
このような処理は、異物検出、部品検査、物体カウント、形状判定などに応用できます。
顔検出
Haar Cascadeによる顔検出
OpenCVでは、Haar Cascadeを使った顔検出もできます。
cv::CascadeClassifier faceCascade;
faceCascade.load("haarcascade_frontalface_default.xml");
検出処理は以下のように書きます。
std::vector<cv::Rect> faces;
faceCascade.detectMultiScale(gray, faces);
検出結果を描画するには以下です。
for (const auto& face : faces) {
cv::rectangle(image, face, cv::Scalar(0, 255, 0), 2);
}
Haar Cascadeは古典的な手法
Haar Cascadeは軽量で扱いやすい一方、現在の実務ではDNNベースの顔検出やYOLO系の物体検出が使われることも多いです。
特に、角度変化、照明変化、部分的な隠れ、複雑な背景に対しては、DNN系の手法の方が安定しやすいです。
そのため、学習目的ではHaar Cascadeを使い、実務用途ではDNNベースの検出も検討するとよいです。
Python版OpenCVとの違い
C++版とPython版の比較
C++版とPython版には、それぞれメリットがあります。
| 項目 | C++版 | Python版 |
|---|---|---|
| 実行速度 | 高速化しやすい | OpenCV関数自体は内部C++で高速 |
| 開発の手軽さ | やや難しい | 手軽に書ける |
| 環境構築 | やや複雑 | 比較的簡単 |
| 製品組み込み | 向いている | 用途による |
| メモリ制御 | 細かく制御できる | 抽象化されている |
| 学習コスト | 高め | 低め |
どちらを選ぶべきか
画像処理の概念を学ぶだけであれば、Python版の方が始めやすいです。
一方で、以下のような場合はC++版OpenCVを学ぶ価値が高いです。
- リアルタイム処理を行いたい
- C++アプリケーションに組み込みたい
- 産業用画像処理を行いたい
- 組み込み機器で動かしたい
- メモリや速度を細かく制御したい
- 製品レベルの画像処理システムを作りたい
C++ OpenCVでよくあるエラー
画像が読み込めない
もっともよくあるのが、imread() で画像が読み込めないケースです。
cv::Mat image = cv::imread("sample.jpg");
必ず以下のようにチェックします。
if (image.empty()) {
std::cerr << "読み込み失敗" << std::endl;
}
原因としては、ファイルパスや実行ディレクトリの違いが多いです。
DLLが見つからない
Windowsでは、OpenCVのDLLが見つからずに実行できないことがあります。
対策としては、以下があります。
- OpenCVの
binフォルダを環境変数PATHに追加する - 実行ファイルと同じフォルダにDLLを置く
- Debug/Releaseのライブラリを混在させない
- OpenCVのバージョンとリンク設定を一致させる
CMakeでOpenCVが見つからない
find_package(OpenCV REQUIRED) が失敗する場合、OpenCVの場所をCMakeに伝える必要があります。
cmake -DOpenCV_DIR=/path/to/opencv/build ..
環境によっては、Homebrew、vcpkg、APT、ソースビルドなどでインストール先が異なります。
色がおかしい
画像の色が赤青反転して見える場合、BGRとRGBの違いが原因であることが多いです。
OpenCVでは通常BGR順です。
RGBに変換する場合は以下です。
cv::cvtColor(image, rgb, cv::COLOR_BGR2RGB);
C++ OpenCVの学習順序
初心者におすすめの順番
C++でOpenCVを学ぶ場合、以下の順番で進めると理解しやすいです。
1. C++の基本
2. cv::Mat
3. imread / imshow / imwrite
4. グレースケール変換
5. 二値化
6. フィルタ処理
7. エッジ検出
8. 輪郭抽出
9. 動画・カメラ処理
10. 特徴点検出
11. 物体検出
12. DNN
最初からDNNや高度な物体検出に進むよりも、まずは cv::Mat と基本的な画像処理を理解することが重要です。
最小サンプルコード
画像を読み込んでエッジ検出する例
最後に、C++ OpenCVの基本をまとめたサンプルを紹介します。
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat image = cv::imread("sample.jpg");
if (image.empty()) {
std::cerr << "画像を読み込めませんでした。" << std::endl;
return -1;
}
cv::Mat gray;
cv::Mat edges;
cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
cv::Canny(gray, edges, 100, 200);
cv::imshow("Original", image);
cv::imshow("Gray", gray);
cv::imshow("Edges", edges);
cv::imwrite("edges.jpg", edges);
cv::waitKey(0);
return 0;
}
このコードには、OpenCVの基本要素が含まれています。
cv::Matcv::imread()empty()チェックcv::cvtColor()cv::Canny()cv::imshow()cv::imwrite()cv::waitKey()
まとめ
C++のOpenCVでは、まず cv::Mat を理解することが重要です。
cv::Mat は画像データを扱う中心的なクラスであり、画像の読み込み、変換、加工、保存、表示など、ほとんどの処理で使われます。
特に重要な関数は以下です。
cv::imread()
cv::imshow()
cv::waitKey()
cv::imwrite()
cv::cvtColor()
cv::threshold()
cv::GaussianBlur()
cv::Canny()
cv::findContours()
cv::VideoCapture
C++版OpenCVは、Python版より環境構築やビルドが難しい一方で、リアルタイム処理、産業用途、組み込み開発、製品レベルの画像処理に向いています。
入門段階では、画像を読み込む、表示する、グレースケール化する、二値化する、輪郭を抽出する、という基本処理をしっかり押さえることが大切です。
そのうえで、動画処理、特徴点検出、物体検出、DNN推論へ進むと、OpenCVをより実践的に活用できるようになります。
以上、C++のOpenCVについてでした。
最後までお読みいただき、ありがとうございました。
