Merge remote-tracking branch 'origin/2.4' into merge-2.4
[profile/ivi/opencv.git] / samples / cpp / tutorial_code / introduction / windows_visual_studio_Opencv / Test.cpp
1 // Video Image PSNR and SSIM
2 #include <iostream>     // for standard I/O
3 #include <string>   // for strings
4 #include <iomanip>  // for controlling float print precision
5 #include <sstream>  // string to number conversion
6
7 #include <opencv2/imgproc/imgproc.hpp>  // Gaussian Blur
8 #include <opencv2/core/core.hpp>        // Basic OpenCV structures (cv::Mat, Scalar)
9 #include <opencv2/highgui/highgui.hpp>  // OpenCV window I/O
10
11 using namespace std;
12 using namespace cv;
13
14 double getPSNR ( const Mat& I1, const Mat& I2);
15 Scalar getMSSIM( const Mat& I1, const Mat& I2);
16
17 static void help()
18 {
19     cout
20         << "\n--------------------------------------------------------------------------" << endl
21         << "This program shows how to read a video file with OpenCV. In addition, it tests the"
22         << " similarity of two input videos first with PSNR, and for the frames below a PSNR "  << endl
23         << "trigger value, also with MSSIM."<< endl
24         << "Usage:"                                                                       << endl
25         << "./video-source referenceVideo useCaseTestVideo PSNR_Trigger_Value Wait_Between_Frames " << endl
26         << "--------------------------------------------------------------------------"   << endl
27         << endl;
28 }
29 int main(int argc, char *argv[])
30 {
31     help();
32     if (argc != 5)
33     {
34         cout << "Not enough parameters" << endl;
35         return -1;
36     }
37     stringstream conv;
38
39     const string sourceReference = argv[1],sourceCompareWith = argv[2];
40     int psnrTriggerValue, delay;
41     conv << argv[3] << argv[4];           // put in the strings
42     conv >> psnrTriggerValue >> delay;// take out the numbers
43
44     char c;
45     int frameNum = -1;                  // Frame counter
46
47     VideoCapture captRefrnc(sourceReference),
48                  captUndTst(sourceCompareWith);
49
50     if ( !captRefrnc.isOpened())
51     {
52         cout  << "Could not open reference " << sourceReference << endl;
53         return -1;
54     }
55
56     if( !captUndTst.isOpened())
57     {
58         cout  << "Could not open case test " << sourceCompareWith << endl;
59         return -1;
60     }
61
62     Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
63                      (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
64          uTSi = Size((int) captUndTst.get(CAP_PROP_FRAME_WIDTH),
65                      (int) captUndTst.get(CAP_PROP_FRAME_HEIGHT));
66
67     if (refS != uTSi)
68     {
69         cout << "Inputs have different size!!! Closing." << endl;
70         return -1;
71     }
72
73     const char* WIN_UT = "Under Test";
74     const char* WIN_RF = "Reference";
75
76     // Windows
77             namedWindow(WIN_RF, WINDOW_AUTOSIZE );
78             namedWindow(WIN_UT, WINDOW_AUTOSIZE );
79             moveWindow(WIN_RF, 400       ,            0);                //750,  2 (bernat =0)
80             moveWindow(WIN_UT, refS.width,            0);                //1500, 2
81
82     cout << "Frame resolution: Width=" << refS.width << "  Height=" << refS.height
83          << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
84
85     cout << "PSNR trigger value " <<
86           setiosflags(ios::fixed) << setprecision(3) << psnrTriggerValue << endl;
87
88     Mat frameReference, frameUnderTest;
89     double psnrV;
90     Scalar mssimV;
91
92     for(;;) //Show the image captured in the window and repeat
93     {
94         captRefrnc >> frameReference;
95         captUndTst >> frameUnderTest;
96
97         if( frameReference.empty()  || frameUnderTest.empty())
98         {
99             cout << " < < <  Game over!  > > > ";
100             break;
101         }
102
103         ++frameNum;
104         cout <<"Frame:" << frameNum;
105
106         ///////////////////////////////// PSNR ////////////////////////////////////////////////////
107         psnrV = getPSNR(frameReference,frameUnderTest);                                 //get PSNR
108         cout << setiosflags(ios::fixed) << setprecision(3) << psnrV << "dB";
109
110         //////////////////////////////////// MSSIM /////////////////////////////////////////////////
111         if (psnrV < psnrTriggerValue)
112         {
113             mssimV = getMSSIM(frameReference,frameUnderTest);
114
115             cout << " MSSIM: "
116                  << "R" << setiosflags(ios::fixed) << setprecision(3) << mssimV.val[2] * 100
117                  << "G" << setiosflags(ios::fixed) << setprecision(3) << mssimV.val[1] * 100
118                  << "B" << setiosflags(ios::fixed) << setprecision(3) << mssimV.val[0] * 100;
119         }
120
121        cout << endl;
122
123         ////////////////////////////////// Show Image /////////////////////////////////////////////
124         imshow( WIN_RF, frameReference);
125         imshow( WIN_UT, frameUnderTest);
126
127         c = (char)waitKey(delay);
128         if (c == 27) break;
129     }
130
131     return 0;
132 }
133
134 double getPSNR(const Mat& I1, const Mat& I2)
135 {
136     Mat s1;
137     absdiff(I1, I2, s1);       // |I1 - I2|
138     s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bits
139     s1 = s1.mul(s1);           // |I1 - I2|^2
140
141     Scalar s = sum(s1);         // sum elements per channel
142
143     double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
144
145     if( sse <= 1e-10) // for small values return zero
146         return 0;
147     else
148     {
149         double  mse =sse /(double)(I1.channels() * I1.total());
150         double psnr = 10.0*log10((255*255)/mse);
151         return psnr;
152     }
153 }
154
155 Scalar getMSSIM( const Mat& i1, const Mat& i2)
156 {
157     const double C1 = 6.5025, C2 = 58.5225;
158     /***************************** INITS **********************************/
159     int d     = CV_32F;
160
161     Mat I1, I2;
162     i1.convertTo(I1, d);           // cannot calculate on one byte large values
163     i2.convertTo(I2, d);
164
165     Mat I2_2   = I2.mul(I2);        // I2^2
166     Mat I1_2   = I1.mul(I1);        // I1^2
167     Mat I1_I2  = I1.mul(I2);        // I1 * I2
168
169     /*************************** END INITS **********************************/
170
171     Mat mu1, mu2;   // PRELIMINARY COMPUTING
172     GaussianBlur(I1, mu1, Size(11, 11), 1.5);
173     GaussianBlur(I2, mu2, Size(11, 11), 1.5);
174
175     Mat mu1_2   =   mu1.mul(mu1);
176     Mat mu2_2   =   mu2.mul(mu2);
177     Mat mu1_mu2 =   mu1.mul(mu2);
178
179     Mat sigma1_2, sigma2_2, sigma12;
180
181     GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
182     sigma1_2 -= mu1_2;
183
184     GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
185     sigma2_2 -= mu2_2;
186
187     GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
188     sigma12 -= mu1_mu2;
189
190     ///////////////////////////////// FORMULA ////////////////////////////////
191     Mat t1, t2, t3;
192
193     t1 = 2 * mu1_mu2 + C1;
194     t2 = 2 * sigma12 + C2;
195     t3 = t1.mul(t2);              // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
196
197     t1 = mu1_2 + mu2_2 + C1;
198     t2 = sigma1_2 + sigma2_2 + C2;
199     t1 = t1.mul(t2);               // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
200
201     Mat ssim_map;
202     divide(t3, t1, ssim_map);      // ssim_map =  t3./t1;
203
204     Scalar mssim = mean( ssim_map ); // mssim = average of ssim map
205     return mssim;
206 }