C++ Opencvのdnn_superresを使ってお手軽超解像

# 概要
opencv contribにあるdnn_superresを用いて超解像を触ってみる
モデルごとに計算速度に差があるかが気になったので処理時間も計測した
言語は問わないからとにかく超解像を試してみたい！という人は恐らくpythonで良いかと
初投稿なので拙い部分しかないと思いますがご容赦ください

# 環境
* visual studio 2019 version 16.10.4
* windows 10 home
* opencv 4.5.3
* C++14
* gcc version 8.1.0

# 準備
* visual stduio 2019はこちらからdlできます

https://visualstudio.microsoft.com/ja/downloads/

* opencv 4.5.3はこちらからdlできます

https://opencv.org/releases/

* opencv 4.5.3の中にはdnn_superresは無いのでここから別途dlして使ってください

https://github.com/opencv/opencv_contrib

* 今回用いた超解像モデルは以下のリンクからdlしました 今回はすべてx4を使います
https://github.com/Saafke/EDSR_Tensorflow/tree/master/models
https://github.com/fannymonori/TF-ESPCN/tree/master/export
https://github.com/Saafke/FSRCNN_Tensorflow/tree/master/models



* 写真の方が超解像の結果がわかりやすいかなとは思いましたが,今回はお手軽に試したかったのでいらすとやの壁に隠れられてないチョッパーを使いました かわいい！

https://www.irasutoya.com/2021/01/chopper.html

# 参考にしたページ
* visual studioとopencv導入で参考にしました

https://qiita.com/koteko/items/60936f34f21d7decf0b5

* opencv conrtib導入で参考にしました

https://swallow-incubate.com/archives/blog/20200508/?doing_wp_cron=1628073484.5498480796813964843750

* コーディングで参考にしました

http://gori-naru.blogspot.com/

https://learnopencv.com/super-resolution-in-opencv/#sec3

http://cvwww.ee.ous.ac.jp/opencv_practice1/#1.4

http://vivi.dyndns.org/tech/cpp/timeMeasurement.html

https://mirucacule.hatenablog.com/entry/2019/10/14/223721

https://yag-ays.github.io/project/opencv-superresolution/

# コード
まずはEDSRでやってみます
pathは環境に合わせて書き換えてください
モデルを変えたい場合はモデルパスを適宜書き換えてください

```
#include <iostream>
#include <windows.h>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/dnn_superres.hpp>

using namespace std;
using namespace cv;
using namespace dnn;
using namespace dnn_superres;

    // 超解像関数
Mat upscaleImage(Mat img, string model, string modelPath, int scale) {
	DnnSuperResImpl sr;
	Mat image_output;

	// 超解像モデルへのpath
	sr.readModel(modelPath);
	// 超解像モデル,スケールのセット
	sr.setModel(model, scale);
	
	// 画像出力
	sr.upsample(img, image_output);
	return (image_output);
}

int main(int argc, char* argv[])
{
	// 入力画像読み込み
	Mat img = imread("C:/~~.png");
	// 領域選択
	Rect roi;
	roi.x = 100;
	roi.y = 0;
	roi.width = img.size().width - 100;
	roi.height =300;
	img = img(roi);

	// 超解像モデル指定(EDSR_x4)
	string path = "C:/~~/EDSR_x4.pb";
	string model = "edsr";
	int scale = 4;

	// 処理時間計測開始
	DWORD start = GetTickCount64();

	// 超解像処理
	Mat result = upscaleImage(img, model, path, scale);

	// 計測終了
	DWORD end = GetTickCount64();

	// 比較用非超解像画像
	Mat normal_zoom;
	resize(img, normal_zoom, cv::Size(), scale, scale);

	// 出力画像保存
	imwrite("C:\~~\SR_upscaled.png", result);
	imwrite("C:\~~\Opencv_upscaled.png", normal_zoom);

	// 超解像結果,比較用画像,処理時間を出力
	imshow("Original", img);
	imshow("SR upscaled", result);
	imshow("Opencv_resized", normal_zoom);
	cout << "processing time = " << (double)(end - start) / 1000 / 60 << "minutes.\n";
	waitKey(0);
	destroyAllWindows();

	return (0);
}
```

# EDSR
まずはオリジナルイメージです かわいいですね！
![onepiece06_chopper.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403933/88ca57c2-5689-16d2-b28a-e415ac9b351c.png)

![chopper_EDSR4x_zoom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403933/f32656c7-3cf3-8a77-64b5-b60f9031e8cb.png)

![chopper_EDSR4x_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403933/45cb4a39-7745-8efe-6212-0487c005674a.png)

上がEDSR無しでズームした場合で,下がEDSRを用いた超解像結果です
角と背景の境界などがなめらかになっているのが見て取れますね
ちなみに自分の環境での処理時間は173.4sでした

# FSRCNN
このくらいの画像だとFDSRとの違いはそこまで顕著ではないですね
ただ処理時間が0.345sととんでもなく短縮できてます

![FSRCNN_horn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403933/2d1ea8e7-1caf-9fa8-e581-26f2b83d3dbe.png)

# ESPCN
こちらも大きな違いは見当たりませんが,処理時間は0.234sと今回試したモデルの中では最短です
![ESPCN_horn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403933/97fb1ae4-c53d-c27e-3396-8549e62c6481.png)

# 感想
超解像を勉強していくために,とりあえず触ってみようと思って実装したのですが,
コーディングよりも環境構築に時間がかかるレベルのお手軽さでとても驚きました.先人に感謝です.
モデルごとの利点や大幅な処理時間の短縮はなぜ実現されているのかが気になるところ
FPGAに実装してみたいのでスクラッチ開発にも挑戦していきたい