OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
コンピュータビジョンアプリケーションのインタラクティブな視覚デバッグ

コンピュータビジョンアプリケーションをデバッグする最も一般的な方法は何だろうか。たいていの答えは、その場しのぎで寄せ集めた一時的なカスタムコードであり、リリース用にコンパイルする際にはコードから取り除かなければならない。

このチュートリアルでは、その代わりに cvv モジュール(opencv2/cvv.hpp)のビジュアルデバッグ機能の使い方を示す。

目標

このチュートリアルでは、以下の方法を学ぶ:

  • アプリケーションにcvvデバッグ呼び出しを追加する
  • ビジュアルデバッグGUIを使用する
  • コンパイル時にビジュアルデバッグ機能を有効化・無効化する(無効化時は実行時オーバーヘッドがゼロ)

コード

サンプルコードは

  • 画像をキャプチャし(videoio)、たとえばWebカメラから取得する。
  • 各画像にいくつかのフィルタを適用し(imgproc)、
  • 画像特徴を検出して前の画像とマッチングする(features2d)。

(後述のCMakeLists.txtを参照)ビジュアルデバッグなしでプログラムをコンパイルした場合、唯一の結果はコマンドラインに出力される情報のみである。わずか数行の cvv コマンドを加えるだけで、どれだけ多くのデバッグ機能や開発機能が追加されるかを示したい。

1// system includes
2#include <iostream>
3
4// library includes
5#include <opencv2/imgproc.hpp>
7#include <opencv2/videoio.hpp>
8
9#define CVVISUAL_DEBUGMODE
15
16using namespace std;
17using namespace cv;
18
19template<class T> std::string toString(const T& p_arg)
20{
21 std::stringstream ss;
22
23 ss << p_arg;
24
25 return ss.str();
26}
27
28
29
30
31int
32main(int argc, char** argv)
33{
34 // parser keys
35 const char *keys =
36 "{ help h usage ? | | show this message }"
37 "{ width W | 0| camera resolution width. leave at 0 to use defaults }"
38 "{ height H | 0| camera resolution height. leave at 0 to use defaults }";
39
40 CommandLineParser parser(argc, argv, keys);
41 if (parser.has("help")) {
42 parser.printMessage();
43 return 0;
44 }
45 int res_w = parser.get<int>("width");
46 int res_h = parser.get<int>("height");
47
48 // setup video capture
49 cv::VideoCapture capture(0);
50 if (!capture.isOpened()) {
51 std::cout << "Could not open VideoCapture" << std::endl;
52 return 1;
53 }
54
55 if (res_w>0 && res_h>0) {
56 printf("Setting resolution to %dx%d\n", res_w, res_h);
57 capture.set(cv::CAP_PROP_FRAME_WIDTH, res_w);
58 capture.set(cv::CAP_PROP_FRAME_HEIGHT, res_h);
59 }
60
61
62 cv::Mat prevImgGray;
63 std::vector<cv::KeyPoint> prevKeypoints;
64 cv::Mat prevDescriptors;
65
66 int maxFeatureCount = 500;
67 Ptr<ORB> detector = ORB::create(maxFeatureCount);
68
70
71 for (int imgId = 0; imgId < 10; imgId++) {
72 // capture a frame
73 cv::Mat imgRead;
74 capture >> imgRead;
75 printf("%d: image captured\n", imgId);
76
77 std::string imgIdString{"imgRead"};
78 imgIdString += toString(imgId);
79 cvv::showImage(imgRead, CVVISUAL_LOCATION, imgIdString.c_str());
80
81 // convert to grayscale
82 cv::Mat imgGray;
83 cv::cvtColor(imgRead, imgGray, COLOR_BGR2GRAY);
84 cvv::debugFilter(imgRead, imgGray, CVVISUAL_LOCATION, "to gray");
85
86 // detect ORB features
87 std::vector<cv::KeyPoint> keypoints;
88 cv::Mat descriptors;
89 detector->detectAndCompute(imgGray, cv::noArray(), keypoints, descriptors);
90 printf("%d: detected %zd keypoints\n", imgId, keypoints.size());
91
92 // match them to previous image (if available)
93 if (!prevImgGray.empty()) {
94 std::vector<cv::DMatch> matches;
95 matcher.match(prevDescriptors, descriptors, matches);
96 printf("%d: all matches size=%zd\n", imgId, matches.size());
97 std::string allMatchIdString{"all matches "};
98 allMatchIdString += toString(imgId-1) + "<->" + toString(imgId);
99 cvv::debugDMatch(prevImgGray, prevKeypoints, imgGray, keypoints, matches, CVVISUAL_LOCATION, allMatchIdString.c_str());
100
101 // remove worst (as defined by match distance) bestRatio quantile
102 double bestRatio = 0.8;
103 std::sort(matches.begin(), matches.end());
104 matches.resize(int(bestRatio * matches.size()));
105 printf("%d: best matches size=%zd\n", imgId, matches.size());
106 std::string bestMatchIdString{"best " + toString(bestRatio) + " matches "};
107 bestMatchIdString += toString(imgId-1) + "<->" + toString(imgId);
108 cvv::debugDMatch(prevImgGray, prevKeypoints, imgGray, keypoints, matches, CVVISUAL_LOCATION, bestMatchIdString.c_str());
109 }
110
111 prevImgGray = imgGray;
112 prevKeypoints = keypoints;
113 prevDescriptors = descriptors;
114 }
115
117
118 return 0;
119}
#define CVVISUAL_LOCATION
Creates an instance of CallMetaData with the location of the macro as value.
Definition call_meta_data.hpp:65
Brute-force descriptor matcher.
Definition features2d.hpp:1256
Designed for command line parsing.
Definition utility.hpp:890
n-dimensional dense array class
Definition mat.hpp:840
bool empty() const
Returns true if the array has no elements.
Class for video capturing from video files, image sequences or cameras.
Definition videoio.hpp:786
@ NORM_HAMMING
Definition base.hpp:199
std::shared_ptr< _Tp > Ptr
Definition cvstd_wrapper.hpp:23
InputOutputArray noArray()
Returns an empty InputArray or OutputArray.
void finalShow()
Passes the control to the debug-window for a last time.
Definition final_show.hpp:23
static void debugDMatch(cv::InputArray img1, std::vector< cv::KeyPoint > keypoints1, cv::InputArray img2, std::vector< cv::KeyPoint > keypoints2, std::vector< cv::DMatch > matches, const impl::CallMetaData &data, const char *description=nullptr, const char *view=nullptr, bool useTrainDescriptor=true)
Add a filled in DMatch <dmatch> to debug GUI.
Definition dmatch.hpp:49
static void showImage(cv::InputArray img, impl::CallMetaData metaData=impl::CallMetaData(), const char *description=nullptr, const char *view=nullptr)
Add a single image to debug GUI (similar to imshow <>).
Definition show_image.hpp:38
static void debugFilter(cv::InputArray original, cv::InputArray result, impl::CallMetaData metaData=impl::CallMetaData(), const char *description=nullptr, const char *view=nullptr)
Use the debug-framework to compare two images (from which the second is intended to be the result of ...
Definition filter.hpp:36
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
Converts an image from one color space to another.
@ CAP_PROP_FRAME_WIDTH
Width of the frames in the video stream.
Definition videoio.hpp:145
@ CAP_PROP_FRAME_HEIGHT
Height of the frames in the video stream.
Definition videoio.hpp:146
int main(int argc, char *argv[])
Definition highgui_qt.cpp:3
Definition core.hpp:107
STL namespace.
cmake_minimum_required(VERSION 2.8)
project(cvvisual_test)
SET(CMAKE_PREFIX_PATH ~/software/opencv/install)
SET(CMAKE_CXX_COMPILER "g++-4.8")
SET(CMAKE_CXX_FLAGS "-std=c++11 -O2 -pthread -Wall -Werror")
# (un)set: cmake -DCVV_DEBUG_MODE=OFF ..
OPTION(CVV_DEBUG_MODE "cvvisual-debug-mode" ON)
if(CVV_DEBUG_MODE MATCHES ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCVVISUAL_DEBUGMODE")
endif()
FIND_PACKAGE(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(cvvt main.cpp)
target_link_libraries(cvvt
opencv_core opencv_videoio opencv_imgproc opencv_features2d
opencv_cvv
)

解説

  1. プログラムは、上記のCmakeLists.txtでオプション CVV_DEBUG_MODE=ONcmake -DCVV_DEBUG_MODE=ON)を使ってコンパイルするか、または対応する定義 CVVISUAL_DEBUGMODE をコンパイラに追加して(たとえば g++ -DCVVISUAL_DEBUGMODE)コンパイルする。
  2. 最初のcvv呼び出しは、imgIdStringをコメントとして単に画像を表示する(imshow に類似)。
    cvv::showImage(imgRead, CVVISUAL_LOCATION, imgIdString.c_str());
    画像はビジュアルデバッグGUIのオーバービュータブに追加され、cvv呼び出しはブロックする。
image

その後、画像を選択して表示できる

image

コード内で続行したいとき、すなわちcvv呼び出しのブロックを解除したいときは、次のcvv呼び出しまで続行する(Step)、最後のcvv呼び出しまで続行する(*>>*)、またはアプリケーションが終了するまで実行する(Close)のいずれかを選べる。

ここでは緑色の Step ボタンを押すことにする。

  1. 次のcvv呼び出しは、あらゆる種類のフィルタ操作、すなわち画像を入力として受け取り画像を出力として返す操作をデバッグするために使われる。
    cvv::debugFilter(imgRead, imgGray, CVVISUAL_LOCATION, "to gray");
    すべてのcvv呼び出しと同様、まずオーバービューに到達する。
image

グレースケールへの変換については気にしないことにして、Step を押す。

cvv::debugFilter(imgGray, imgGraySmooth, CVVISUAL_LOCATION, "smoothed");

フィルタ呼び出しを開くと、いわゆる「DefaultFilterView」に到達する。2つの画像が並べて表示され、(同期して)ズームできる。

image

非常に高いズームレベルにすると、各ピクセルにその数値が注釈として表示される。

image

Step を2回押し、膨張させた画像を確認する。

cvv::debugFilter(imgEdges, imgEdgesDilated, CVVISUAL_LOCATION, "dilated edges");

両方の画像を表示するDefaultFilterView

image

次に、右上の View セレクタを使って「DualFilterView」を選択する。フィルタとして「Changed Pixels」を選択して適用する(中央の画像)。

image

これらの画像をじっくり見たあと、おそらく異なるビューやフィルタ、その他のGUI機能を使った後で、プログラムを最後まで実行させることにする。そのため、黄色の *>>* ボタンを押す。

プログラムは次の箇所でブロックする

そして、その間にcvvに渡されたすべてを含むオーバービューを表示する。

image
  1. cvvのdebugDMatch呼び出しは、それぞれが記述子の集合を持つ2つの画像があり、それらが互いにマッチングされている状況で使われる。

    両方の画像、両方のキーポイントの集合、およびそのマッチングをビジュアルデバッグモジュールに渡す。

    cvv::debugDMatch(prevImgGray, prevKeypoints, imgGray, keypoints, matches, CVVISUAL_LOCATION, allMatchIdString.c_str());

    マッチを確認したいので、オーバービューでフィルタ機能(*#type match*)を使い、マッチ呼び出しのみを表示する。

image

そのうちの1つを詳しく見たい。たとえば、マッチングを使う引数を調整するためである。このビューには、キーポイントとマッチをどう表示するかについてさまざまな設定がある。さらに、マウスオーバーのツールチップもある。

image

悪いマッチが多数あることが(ビジュアルデバッグで!)分かる。マッチの70%のみ、すなわちマッチ距離が最も小さい70%のみを表示することにする。

image

視覚的な煩雑さをうまく減らせたので、2つの画像間で何が変わったのかをより明確に見たい。キーポイントがどこにマッチしたのかを別の方法で示す「TranslationMatchView」を選択する。

image

2つの画像の間でカップが左に動かされたことが容易に分かる。

cvvはコンピュータビジョンのバグをインタラクティブに 見る ことが本質だが、それを補完するものとして、基礎となる数値データを確認できる「RawView」がある。

image
  1. cvv GUIには、ほかにも便利な機能が多数含まれている。たとえば、オーバービュータブをグループ化できる。
image

結果

  • コンピュータビジョンプログラムに表現力のある数行を加えることで、さまざまな可視化を通してインタラクティブにデバッグできる。
  • 開発・デバッグが終わっても、それらの行を取り除く必要はない。単にcvvデバッグを無効化する(cmake -DCVV_DEBUG_MODE=OFF または -DCVVISUAL_DEBUGMODE なしのg++)だけで、プログラムはデバッグのオーバーヘッドなしに実行される。

コンピュータビジョンを楽しもう!