C++版OpenCVでトラックバーを表示してみた

# なぜ必要か
[OpenCVで油絵エフェクトは1行でかけるとのことです。(C++限定)](https://qiita.com/satsukiya/items/8adc069772df7465bd85) で `oilPainting` を紹介しました。 公式ドキュメントで[oilPainting()](https://docs.opencv.org/master/de/daa/group__xphoto.html#gac050a6e876298cb9713cd2c09db9a027) を詳しくみると、、、

```c++
void cv::xphoto::oilPainting	
 	 	(InputArray 	src,
 	 	 OutputArray 	dst,
 	 	int 	size,
 	 	int 	dynRatio,
 	 	int 	code 
)
```

と `size` `dynRatio` などのパラメータが用意されています。

documentには

- `size` :  neighbouring size is 2-size+1 (隣接サイズ 2-size+1)
- `dynRatio` : image is divided by dynRatio before histogram processing (ヒストグラム処理の前に動的比率で分割する)

と書かれていますが、これだけではよくわかりません。

おそらく他のクラス・メソッドもすぐには理解できないパラメータが多く含まれていると思います。仮にdocumentが充実していても難しい内容が含まれている可能性があります。
幸い扱っているデータソースが画像なので、処理をかけると何らかの出力がなされるのでそこから類推することもできます。

今回説明するトラックバーはパラメータを可変に動かすことで出力画像を表示することができるので、どのようにパラメータが使われているか確認するために用いています。

# 開発

```c++
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/xphoto.hpp>

cv::Mat src = cv::imread("./mikan.jpg");
int nsize_slider = 2;
int r_slider = 1;

void nsize_trackbar( int size, void*)
{
   cv::Mat dst;   
   cv::xphoto::oilPainting(src, dst, size, r_slider, cv::COLOR_BGR2Lab);
   cv::imshow("oil painting effect", dst);
}

void dynRatio_trackbar( int r, void* )
{
   cv::Mat dst;   
   cv::xphoto::oilPainting(src, dst, nsize_slider, r, cv::COLOR_BGR2Lab);
   cv::imshow("oil painting effect", dst);
}

int main(int argc, const char* argv[]) {

   if (src.empty()) {
      std::cout << "read error.\n";
      return -1;
   }

   cv::namedWindow("oil painting effect", cv::WINDOW_AUTOSIZE);

   //トラックバー表示
   cv::createTrackbar("neighbouring size", "oil painting effect", &nsize_slider, 20, nsize_trackbar);
   cv::setTrackbarPos("neighbouring size", "oil painting effect", 5);
   cv::setTrackbarMin("neighbouring size", "oil painting effect", 2);

   cv::createTrackbar("dynRatio", "oil painting effect", &r_slider, 10, dynRatio_trackbar );
   cv::setTrackbarPos("dynRatio", "oil painting effect", 3);
   cv::setTrackbarMin("dynRatio", "oil painting effect", 1);

   //最初の表示
   nsize_trackbar(2, NULL);
   dynRatio_trackbar(1, NULL);

   cv::waitKey(0);
   src.release();
   cv::destroyAllWindows();

   return 0;
}
```

```c++
void nsize_trackbar( int size, void*)
{
   cv::Mat dst;   
   cv::xphoto::oilPainting(src, dst, size, r_slider, cv::COLOR_BGR2Lab);
   cv::imshow("oil painting effect", dst);
}
```
はコールバック関数で、ユーザが動かしたトラックバーの値と同期しています。例えばトラックバー`size`を10にすると`oilPainting`の`size`は10として画像処理されます。

# 結果
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/13e23d1c-623d-2eb4-8df4-d5e9db18f584.gif)

メソッド内の処理は詳しくはわかりませんが、アプリを開いてトラックバーを動かしてみると `(neighbour)size` はペンの太さ、`dynRatio`はペンのかすれ具合と同義なのがわかります。

# おわりに

```c++
cv::Mat src = cv::imread("./mikan.jpg");
int nsize_slider = 2;
int r_slider = 1;
```
をグローバル変数で宣言していますが `cv::createTrackbar` の `userdata` を使うとローカルのコールバック関数の引数として使えるっぽいのですが、次回のまとめはこの引数についてネタにするかもしれんす。:thinking:

# 参考になりそうなリンク

- [oilPainting()](https://docs.opencv.org/master/de/daa/group__xphoto.html#gac050a6e876298cb9713cd2c09db9a027)
- [OpenCVとVisual C++による画像処理と認識（３）](http://ishidate.my.coocan.jp/opencv_3/opencv_3.htm)
- [Adding a Trackbar to our applications!](https://docs.opencv.org/4.1.2/da/d6a/tutorial_trackbar.html)