OpenCV

作成日:2021-01-18
最終更新日:

OpenCV とは

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)。

OpenCV 4.2 について

https://docs.opencv.org/4.2.0/index.html
にあることができればいい、と思っている。

まりんきょ学問所UNIX 手習い > OpenCV


MARUYAMA Satosi