OpenCV |
作成日:2021-01-18 最終更新日: |
OpenCV とは、画像処理ライブラリである。
ソースコードからコンパイルする方法もあるのだろうが、 私は結局 apt get install でインストールした。 Ubuntu 20.04 (Windows Subsystem for Linux 2 , WSL2) である。
$ sudo apt-get install libopencv-dev python3-opencv
dpkg -l | grep libopencv
私の場合は 4.2.0+dfsg-5 だった。
私は C++ でプログラムを動かそうと思っている。使うコンパイラは g++ 9.3.0 である。 さて、OpenCV のサンプルを探そうとして、OpenCV サンプルプログラム、サンプルプログラム、 などでで検索すると、 OpenCV のバージョンが 1 のものから、最新のものまでけっこうみつかった。
この先どう進めてよいか迷ったが、OpenCV 本家のサンプルを使うのがよいだろうと判断した。 本家の C++ のサンプルプログラムは下記にある:
https://github.com/opencv/opencv/tree/master/samples/cpp
このページ直下にあるプログラムだけで 88 もある。どれが一番簡単かわからない。 ファイル名をたよりに探したところ、opencv_version.cpp が簡単そうなので、コンパイルしてみた。
$ g++ opencv_version.cpp -I/usr/include/opencv4 -lopencv_core -o opencv_version $ ./opencv_version Welcome to OpenCV 4.2.0
次に簡単なプログラムはどれだろうか。demhist.cpp というのが、 ヒストグラムのデモンストレーションではないかと推測し、コンパイルしてみた。
$ g++ demhist.cpp -I/usr/include/opencv4 -L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_highgui -o demhist
/usr/bin/ld: /tmp/ccZ19vcW.o: undefined reference to symbol 'tempfilename'
/usr/bin/ld: /lib/x86_64-linux-gnu/libopencv_imgproc.so.4.2: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
ああ、これはライブラリが足りなかったのだな。
$ g++ demhist.cpp -I/usr/include/opencv4 -L/usr/local/lib -lopencv_core -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc -o demhist
/usr/bin/ld: /tmp/ccZ19vcW.o: undefined reference to symbol 'tempfilename'
コンパイルは通った。実行してみよう。
$ ./demhist
[ WARN:0] global ../modules/core/src/utils/samples.cpp (59) findFile cv::samples::findFile('baboon.jpg') => ''
terminate called after throwing an instance of 'cv::Exception'
what(): OpenCV(4.2.0) ../modules/core/src/utils/samples.cpp:62: error: (-2:Unspecified error) OpenCV samples: Can't find required data file: baboon.jpg in function 'findFile'
カレントディレクトリに baboon.jpg を用意すればよさそうだ。
https://github.com/opencv/opencv/blob/master/samples/data/baboon.jpg
からダウンロードした。
再度実行して、無事ヒストグラムが表示された。
なお、OpenCV のライブラリ libopencv_***.so は、私の環境(Ubuntu 20.04)では、
/lib/x86_64-linux-gnu/
にある。C++ でコンパイル・リンクして実行ファイルを作るとき、
g++ や Makefile で -L オプションを指定せずとも上記ディレクトリを見るようだ。
もう少し C++ による OpenCV のサンプルプログラムがないか探していたら、 OpenCV超入門 サンプルプログラム集 (nn-hokuson.hatenablog.com)というページがあった。非常にありがたい。
上記ページのプログラムを WSL2 の Ubuntu 20.04, C++ (g++ 9.30), OpenCV 4.2 でコンパイルするにあたって考慮すべき点を以下述べる。
では、画像ファイルを読み込んで表示をするだけのプログラム display.cpp を掲げる。 起動したファイルと同じディレクトリ(フォルダ)に img.png があるという決め打ちのプログラムである。
/* display.cpp */ #include <opencv2/core.hpp> // cvcore #include <opencv2/opencv.hpp> // line, rectangle, circle, ... #include <opencv2/imgcodecs.hpp> // imread, ... #include <opencv2/highgui.hpp> // imshow, ... #include <opencv2/imgproc/imgproc.hpp> // blur, canny, ... #include <iostream> // cout, ... int main(void) { Mat img = imread("img.png"); if (!img.data) { std::cout << "Image not loaded" << "\n"; return -1; } imshow("image",img); waitKey(0); return 0; }
Makefile は次のとおりとなる。
# Makefile all : display INCDIR = -I /usr/include/opencv4 CXXFLAGS = -Wall $(INCDIR) LDLIBS = -lopencv_core -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc
本家の C++ のサンプルプログラム:
https://github.com/opencv/opencv/tree/master/samples/cpp
の一覧の一部をまとめてみた。
ファイル名 | 内容 | 備考 |
---|---|---|
3calibration.cpp | 較正 | |
application_trace.cpp | ||
asift.cpp | アフィン特徴検出器・抽出器:AffineFeature detector/extractor | |
bgfg_segm.cpp | 背景前景分離 | |
calibration.cpp | 較正 | |
camshiftdemo.cpp | 移動平均に基づくトラッキング:mean-shift based tracking | |
cloning_demo.cpp | GUI を使わないクローニングのデモンストレーション | |
cloning_gui.cpp | GUI を使うクローニングのデモンストレーション | |
connected_components.cpp | 連結成分とトラックバー使用のデモンストレーション | |
contours2.cpp | 等高線 | |
convexhull.cpp | 凸包 | |
cout_mat.cpp | 直列出力:demonstrates the serial out capabilities of cv::Mat | |
create_mask.cpp | マスク像の作成:demonstrates how to make mask image (black and white) | |
dbt_face_detection.cpp | 顔検出(dbt : DetectionBasedTracker) | |
delaunay2.cpp | ドロネー図 | |
demhist.cpp | ヒストグラムのデモ | |
detect_blob.cpp | 領域検出・フィルターに BLOB を使う方法 | |
detect_mser.cpp | 領域検出に MSER (Maximally Stable Extremal Regions)を使う方法 | |
dft.cpp | 離散フーリエ変換 | |
digits_lenet.cpp | LeNet-5と連結成分解析に基づくディジタル認識 | |
digits_svm.cpp | サポートベクトルマシン(SVM)とk-近傍法に基づくディジタル認識 | |
dis_opticalflow.cpp | DIS (Dense Inverse Search) オプティカルフロー | |
distrans.cpp | エッジ画像間距離変換関数の使い方 | |
drawing.cpp | ドローイング関数とテキスト関数 | |
edge.cpp | Canny フィルタによるエッジ検出 | |
ela.cpp | 誤差レベル解析(Error Level Analysis)を用いた画像内領域同定 | |
em.cpp | Expectation-Maximization アルゴリズムによるクラスタリング | |
epipolar_lines.cpp | エピポーラ線 | |
essential_mat_reconstr.cpp | 基本行列(Essential Matrix)再構成 | |
facedetect.cpp | 顔検出 | |
facial_features.cpp | 顔特徴 | |
falsecolor.cpp | applyColorMap 関数の使い方 | |
fback.cpp | Gunnar Farneback による密オプティカルフローアルゴリズム | |
ffilldemo.cpp | floodFill() 関数 | |
filestorage.cpp | シリアライズ機能 | |
fitellipse.cpp | 楕円フィッティング | |
flann_search_dataset.cpp | FLANN を使った画像の探索 | |
grabcut.cpp | GrabCut セグメンテーションのデモ | |
image_alignment.cpp | 画像のアラインメントに使う ECC アルゴリズムを実装した findTransformECC 関数のデモ | |
imagelist_creator.cpp | コマンドラインの引数からファイルの一覧を YAML か XML で作る | |
imagelist_reader.cpp | imagelist_creator.cpp で作った一覧をアップロードする | |
inpaint.cpp | ||
intelligent_scissors.cpp | 知的なハサミ | |
intersectExample.cpp | 凸図形どうしの交わり | |
kalman.cpp | カルマンフィルター | |
kmeans.cpp | K-平均クラスタリング | |
laplace.cpp | ラプラシアンフィルタによる点・エッジ検出 | |
letter_recog.cpp | 文字認識 | |
lkdemo.cpp | Lukas-Kanade 法によるオプティカルフロー | |
logistic_regression.cpp | ロジスティック回帰 | |
mask_tmpl.cpp | マスクを用いたテンプレートマッチング | |
matchmethod_orb_akaze_brisk.cpp | ||
minarea.cpp | 輪郭外接(長方形|三角形|円) | |
morphology2.cpp | ||
neural_network.cpp | 神経回路網 | |
npr_demo.cpp | 非写実的レンダリング(Non-Photorealistic Rendering) | |
opencv_version.cpp | OpenCV のバージョン表示 | |
pca.cpp | 主成分分析(Principal Component Analysis) | |
peopledetect.cpp | ||
phase_corr.cpp | 位相限定相関法 | |
points_classifier.cpp | 点のクラス分け | |
polar_transforms.cpp | ||
qrcode.cpp | QR コード | |
segment_objects.cpp | ||
select3dobj.cpp | ||
simd_basic.cpp | SIMDアクセラレーション組み込み関数の基本 | |
smiledetect.cpp | ||
squares.cpp | ピラミッドスケーリング、Canny フィルタ、等高線を用いた四角形検出 | |
stereo_calib.cpp | ||
stereo_match.cpp | ||
stitching.cpp | パノラマ写真画像合成 | |
stitching_detailed.cpp | ||
text_skewness_correction.cpp | テキストの傾き補正 | |
train_HOG.cpp | HOG 特徴量の訓練 | |
train_svmsgd.cpp | サポートベクトルマシン(Support Vector Machine)・確率的勾配降下法(Stochastic Gradient Method) | |
travelsalesman.cpp | ||
tree_engine.cpp | 決定木の取り扱い方法 | |
videocapture_basic.cpp | ビデオキャプチャー基本 | |
videocapture_camera.cpp | ||
videocapture_gphoto2_autofocus.cpp | ||
videocapture_gstreamer_pipeline.cpp | ||
videocapture_image_sequence.cpp | ||
videocapture_intelperc.cpp | ||
videocapture_openni.cpp | ||
videocapture_starter.cpp | ||
videowriter_basic.cpp | ||
warpPerspective_demo.cpp | 透視変換のデモ | |
watershed.cpp | 有名な watershed アルゴリズムセグメンテーション |
上記のサンプルプログラムのうち、intersectExample.cpp をコンパイルし、 実行すると、エラーになる。なお、このエラーになるプログラムを、 intersectExampleErr.cpp とリネームする。
$ ./intersectExampleErr terminate called after throwing an instance of 'cv::Exception' what(): OpenCV(4.2.0) ../modules/core/src/matrix_wrap.cpp:50: error: (-215:Assertion failed) i < 0 in function 'getMat_'
一方、docs.opencv.org には似たプログラムがある。
https://docs.opencv.org/4.2.0/df/da5/samples_2cpp_2intersectExample_8cpp-example.html
こちらをコンパイルして実行した結果は正常である。どこが違うのか。diff -c をかけて調べてみた。 なお、違いを最小限にするため、intersectExampleErr.cpp の空行は省いている。
$ diff -c intersectExampleErr.cpp intersectExample.cpp *** intersectExampleErr.cpp 2021-02-02 15:52:50.020160700 +0900 --- intersectExample.cpp 2021-02-02 14:39:17.165149100 +0900 *************** *** 42,48 **** { fillColor = Scalar(0, 0, 255); } ! fillPoly(image, intersectionPolygon, fillColor); } polylines(image, polygons, true, Scalar(0, 0, 0)); return intersectArea; --- 42,50 ---- { fillColor = Scalar(0, 0, 255); } ! vector<vector<Point> > pp; ! pp.push_back(intersectionPolygon); ! fillPoly(image, pp, fillColor); } polylines(image, polygons, true, Scalar(0, 0, 0)); return intersectArea;
実行で失敗するプログラムは、fillPoly の第2引数が intersectionPolygon であったが、 成功するプログラムは pp である。両者の違いは、 変数 intersectionPolygon の型がvector <Point> であるのに対し、 変数 pp の型は vector<vector<Point> > であることだ。 成功するプログラムでは、事前に intersectionPolygon を push_back メソッドによって型を変換している。
fillPoly のプロトタイプは次のいずれかである:
今回の fillPoly は後者のプロトタイプを使っていることは明らかだ。 そのため第2引数は配列の配列 InputArrayOfArrays にする必要があり、成功するプログラムは型を合わせる変換をしていた、 ということがわかった(2021-02-02)。
https://docs.opencv.org/4.2.0/index.html
にあることができればいい、と思っている。