1.1 超分辨率初體驗
簡單來講,圖像超分辨率就是提高圖像的空間分辨率,例如將一幅圖片的分辨率由352x288擴大到704x576,方便用戶在大尺寸的顯示設備上觀看。圖像的超分辨率,是圖像處理相關問題中的基礎問題之一,並具有廣泛的實際需求和應用場景,在數字成像技術,視頻編碼通信技術,深空衛星遙感技術,目標識別分析技術和醫學影像分析技術等方面,視頻圖像超分辨率技術都能夠應對顯示設備分辨率大於圖像源分辨率的問題。

簡單來說超分辨率技術可以分為以下兩種:
1)只參考當前低分辨率圖像,不依賴其他相關圖像的超分辨率技術,稱之為單幅圖像的超分辨率(single image super resolution),也可以稱之為圖像插值(image interpolation);
2)參考多幅圖像或多個視頻幀的超分辨率技術,稱之為多幀視頻/多圖的超分辨率(multi-frame super resolution)。
1.2 超分辨率理論描述
這個很直觀的超分辨率問題,它的理論描述又是什么樣子的呢?如下圖所示,超分辨率就是將左圖中像素點之間的空間位置用像素點進行填充,使得整個圖像具有更多的像素點,更豐富的細節,從信號的角度講就是補充出更多的高頻成分。
通常在處理這個超分辨率問題的時候,我們常常探索這個退化信號是如何從我們希望的理想信號變化得到的(即分辨率的退化過程),如果對退化過程進行精確地描述,往往對其逆問題的求解有重要的意義。
在本文的問題中,即超分辨率的退化模型,可以通過以下公式來描述:
Y = HDX + n
其中Y為低分辨率的視頻幀/圖像,X為我們理想高分辨率的視頻幀/圖像,而H和D分別為模糊算子和分辨率下采樣算子,n為退化過程中產生的噪聲。
超分代碼:https://github.com/opencv/opencv_contrib/blob/master/modules/wechat_qrcode/src/wechat_qrcode.cpp#L68
模型文件:
https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/sr.prototxt
參數文件:
https://github.com/WeChatCV/opencv_3rdparty/blob/wechat_qrcode/sr.caffemodel
Mat src
= imread(
"e:/template/bj1.png"); Mat dst;
std
:
:shared_ptr
<SuperScale
> sr
= std
:
:make_shared
<SuperScale
>();
//智能指針
sr
-
>init(
"E:/template/sr.prototxt",
"E:/template/sr.caffemodel");
bool use_nn_sr
=
true;
sr
-
>processImageScale(src, dst,
3, use_nn_sr);
path-to-opencv\sources\doc\tutorials\videoio\video-input-psnr-ssim
Scalar getMSSIM( const Mat& i1, const Mat& i2)
{
const double C1 = 6.5025, C2 = 58.5225;
/***************************** INITS **********************************/
int d = CV_32F;
Mat I1, I2;
i1.convertTo(I1, d); // cannot calculate on one byte large values
i2.convertTo(I2, d);
Mat I2_2 = I2.mul(I2); // I2^2
Mat I1_2 = I1.mul(I1); // I1^2
Mat I1_I2 = I1.mul(I2); // I1 * I2
/*************************** END INITS **********************************/
Mat mu1, mu2; // PRELIMINARY COMPUTING
GaussianBlur(I1, mu1, Size(11, 11), 1.5);
GaussianBlur(I2, mu2, Size(11, 11), 1.5);
Mat mu1_2 = mu1.mul(mu1);
Mat mu2_2 = mu2.mul(mu2);
Mat mu1_mu2 = mu1.mul(mu2);
Mat sigma1_2, sigma2_2, sigma12;
GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
sigma1_2 -= mu1_2;
GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
sigma2_2 -= mu2_2;
GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
sigma12 -= mu1_mu2;
///////////////////////////////// FORMULA ////////////////////////////////
Mat t1, t2, t3;
t1 = 2 * mu1_mu2 + C1;
t2 = 2 * sigma12 + C2;
t3 = t1.mul(t2); // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
t1 = mu1_2 + mu2_2 + C1;
t2 = sigma1_2 + sigma2_2 + C2;
t1 = t1.mul(t2); // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
Mat ssim_map;
divide(t3, t1, ssim_map); // ssim_map = t3./t1;
Scalar mssim = mean(ssim_map); // mssim = average of ssim map
return mssim;
}
Scalar getMSSIM(
const
Mat
&
i1,
const
Mat
&
i2)
{
const
double C1
=
6.
5025, C2
=
58.
5225;
/***************************** INITS **********************************/
int d
= CV_32F;
Mat I1, I2;
i1.convertTo(I1, d);
// cannot calculate on one byte large values
i2.convertTo(I2, d);
Mat I2_2
= I2.mul(I2);
// I2^2
Mat I1_2
= I1.mul(I1);
// I1^2
Mat I1_I2
= I1.mul(I2);
// I1 * I2
/*************************** END INITS **********************************/
Mat mu1, mu2;
// PRELIMINARY COMPUTING
GaussianBlur(I1, mu1, Size(
11,
11),
1.
5);
GaussianBlur(I2, mu2, Size(
11,
11),
1.
5);
Mat mu1_2
= mu1.mul(mu1);
Mat mu2_2
= mu2.mul(mu2);
Mat mu1_mu2
= mu1.mul(mu2);
Mat sigma1_2, sigma2_2, sigma12;
GaussianBlur(I1_2, sigma1_2, Size(
11,
11),
1.
5);
sigma1_2
-= mu1_2;
GaussianBlur(I2_2, sigma2_2, Size(
11,
11),
1.
5);
sigma2_2
-= mu2_2;
GaussianBlur(I1_I2, sigma12, Size(
11,
11),
1.
5);
sigma12
-= mu1_mu2;
///////////////////////////////// FORMULA ////////////////////////////////
Mat t1, t2, t3;
t1
=
2
* mu1_mu2
+ C1;
t2
=
2
* sigma12
+ C2;
t3
= t1.mul(t2);
// t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
t1
= mu1_2
+ mu2_2
+ C1;
t2
= sigma1_2
+ sigma2_2
+ C2;
t1
= t1.mul(t2);
// t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
Mat ssim_map;
divide(t3, t1, ssim_map);
// ssim_map = t3./t1;
Scalar mssim
= mean(ssim_map);
// mssim = average of ssim map
return mssim;
}
int main(
int argc,
char
* argv[])
{
//對於一張分辨率比較大的圖片,
Mat src
= imread(
"E:/template/test_3000X2000.bmp"); Mat dstResize; Mat dstSF;
Mat temp;
//將其按照不同比例變小后
resize(src, temp, cv
:
:Size(
750,
500));
std
:
:shared_ptr
<SuperScale
> sr
= std
:
:make_shared
<SuperScale
>();
//智能指針
sr
-
>init(
"E:/template/sr.prototxt",
"E:/template/sr.caffemodel");
bool use_nn_sr
=
true;
//主運算,並打印運算時間
double t1
= (
double)getTickCount();
resize(temp, dstResize, cv
:
:Size(
3000,
2000));
double t2
= (
double)getTickCount();
sr
-
>processImageScale(temp, dstSF,
6, use_nn_sr);
double t3
= (
double)getTickCount();
double timeResize
= (t2
- t1)
/ getTickFrequency();
double timeSF
= (t3
- t2)
/ getTickFrequency();
cout
<<
"Resize耗時"
<< timeResize
<<
"s "
<<
"SF耗時"
<< timeSF
<<
"s"
<< endl;
/////計算並打印ssim
Scalar mssimV
= getMSSIM(src, src);
cout
<<
"自身對比結果: "
<<
" R "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
2]
*
100
<<
"%"
<<
" G "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
1]
*
100
<<
"%"
<<
" B "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
0]
*
100
<<
"%"
<< endl;
mssimV
= getMSSIM(src, dstResize);
cout
<<
" resize結果: "
<<
" R "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
2]
*
100
<<
"%"
<<
" G "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
1]
*
100
<<
"%"
<<
" B "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
0]
*
100
<<
"%"
<< endl;
mssimV
= getMSSIM(src, dstSF);
cout
<<
" sf結果: "
<<
" R "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
2]
*
100
<<
"%"
<<
" G "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
1]
*
100
<<
"%"
<<
" B "
<< setiosflags(ios
:
:fixed)
<< setprecision(
2)
<< mssimV.val[
0]
*
100
<<
"%";
waitKey();
}
Resize耗時
0.
0121942s SF耗時
0.
0245566s
自身對比結果
: R
100.00
% G
100.00
% B
100.00
%
resize結果
: R
75.
12
% G
74.
45
% B
73.
46
%
sf結果
: R
76.
90
% G
76.
09
% B
75.
11
%
Resize耗時
0.
0107573s SF耗時
0.
0202321s
自身對比結果
: R
100.00
% G
100.00
% B
100.00
%
resize結果
: R
93.
68
% G
93.
49
% B
93.
23
%
sf結果
: R
97.
25
% G
97.
20
% B
97.
07
%
Resize耗時
0.
0121942s SF耗時
0.
0245566s
自身對比結果
: R
100.00
% G
100.00
% B
100.00
%
resize結果
: R
75.
12
% G
74.
45
% B
73.
46
%
sf結果
: R
76.
90
% G
76.
09
% B
75.
11
%
Resize耗時
0.
0116356s SF耗時
0.
0207268s
自身對比結果
: R
100.00
% G
100.00
% B
100.00
%
resize結果
: R
67.
05
% G
66.
16
% B
65.
05
%
sf結果
: R
66.
74
% G
65.
48
% B
64.
20
%
Resize耗時
0.
0197857s SF耗時
0.
0182384s
自身對比結果
: R
100.00
% G
100.00
% B
100.00
%
resize結果
: R
52.
94
% G
51.
89
% B
51.
05
%
sf結果
: R
51.
66
% G
50.
15
% B
49.
13
%
Resize耗時
0.
0175215s SF耗時
0.
0138289s
自身對比結果
: R
100.00
% G
100.00
% B
100.00
%
resize結果
: R
47.
59
% G
46.
66
% B
46.
18
%
sf結果
: R
46.
14
% G
44.
85
% B
44.
22
%
附件列表