实验1目录
1.7 histogramselfimplementation.cpp
2.7 histogramselfimplementation.h
实验内容
1.安装 opencv
2.opencv打开图片视频
3.opencv对图像进行加减乘取反
4.opencv使用点运算,进行各种函数的处理
5.直方图生成 (使用 opencv 库函数 & 自己实现)
运行效果
readimg:
readvideo:
imgadd:
img2:
1/2 img + 1/2 img2
img1 -img2
img1 * img2
reversed img
Histogram Library Implementation
Histogram Self Implementation
项目源码
1 Sources
1.1 main.cpp:
/**
* author : CHENHANXUAN
* class : m1701
* id : 201726010211
*/
#include "main.h"
int main(int argc, char** argv) {
// Self Histogram implementation
selfDrawHistogram();
// Read images
imageReader(argc, argv);
// Read videos
videoReader(argc, argv);
// Image add operation
imageAdd();
// Image subduce operation
imageSub();
// Image multiply operation
imageMul();
// Image reverse operation
imageRev();
// Function implementation - exponent
expTransform();
// OpenCV histogram generation
drawHistogram();
return 0;
}
1.2 readImg.cpp
#include "readImg.h"
void imageReader(int argc, char** argv) {
String img_name = "../media/orange_peel.jpeg";
// Arguments detection
if (argc < 3) {
cout << "Usage: " << argv[0] << " pic_path [G]" << endl;
cout << "Hint : [] means optional for grayscale" << endl;
cout << "Now use default img at '../media/orange.jpeg' " << endl;
}
else {
img_name = argv[1];
}
// Read img
Mat source_img;
if (argc >= 3) {
// Read image in grayscale
source_img = imread(img_name, IMREAD_GRAYSCALE);
}
else {
// Read the image in RGB format
source_img = imread(img_name, IMREAD_COLOR);
}
if (!source_img.empty()) {
namedWindow("ORIGINAL IMG", WINDOW_AUTOSIZE);
imshow("ORIGINAL IMG", source_img);
}
waitKey();
}
1.3 readVideo.cpp
#include "readvideo.h"
static void help()
{
cout
<< "------------------------------------------------------------------------------" << endl
<< "This program shows how to read a video file with OpenCV. In addition, it "
<< "tests the similarity of two input videos first with PSNR, and for the frames "
<< "below a PSNR trigger value, also with MSSIM." << endl
<< "Usage:" << endl
<< "./video-input-psnr-ssim <referenceVideo> <useCaseTestVideo> <PSNR_Trigger_Value> <Wait_Between_Frames> " << endl
<< "--------------------------------------------------------------------------" << endl
<< endl;
}
int videoReader(int argc, char **argv)
{
help();
stringstream conv;
int psnrTriggerValue, delay;
string sourceReference, sourceCompareWith;
if (argc != 5)
{
sourceReference = "/home/chenhanxuan/QtProjects/media/videos/Megamind.avi";
sourceCompareWith = "/home/chenhanxuan/QtProjects/media/videos/Megamind_bugy.avi";
psnrTriggerValue = 35;
delay = 10;
cout << "Not enough parameters" << endl;
cout << "Now use the default video clips" << endl;
cout << "Use default PSNR_Trigger_Value = 35" << endl;
cout << "Use default Wait_Between_Frame = 10" << endl;
}
else {
// Use the parameters caught from main function
sourceReference = argv[1], sourceCompareWith = argv[2];
conv << argv[3] << endl << argv[4]; // put in the strings
conv >> psnrTriggerValue >> delay; // take out the numbers
}
int frameNum = -1; // Frame counter
VideoCapture captRefrnc(sourceReference), captUndTst(sourceCompareWith);
if (!captRefrnc.isOpened())
{
cout << "Could not open reference " << sourceReference << endl;
return -1;
}
if (!captUndTst.isOpened())
{
cout << "Could not open case test " << sourceCompareWith << endl;
return -1;
}
Size refS = Size((int)captRefrnc.get(CAP_PROP_FRAME_WIDTH),
(int)captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
uTSi = Size((int)captUndTst.get(CAP_PROP_FRAME_WIDTH),
(int)captUndTst.get(CAP_PROP_FRAME_HEIGHT));
if (refS != uTSi)
{
cout << "Inputs have different size!!! Closing." << endl;
return -1;
}
const char* WIN_UT = "Under Test";
const char* WIN_RF = "Reference";
// Windows
namedWindow(WIN_RF, WINDOW_AUTOSIZE);
namedWindow(WIN_UT, WINDOW_AUTOSIZE);
moveWindow(WIN_RF, 400, 0); //750, 2 (bernat =0)
moveWindow(WIN_UT, refS.width, 0); //1500, 2
cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height
<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
cout << "PSNR trigger value " << setiosflags(ios::fixed) << setprecision(3)
<< psnrTriggerValue << endl;
Mat frameReference, frameUnderTest;
double psnrV;
Scalar mssimV;
for (;;) //Show the image captured in the window and repeat
{
captRefrnc >> frameReference;
captUndTst >> frameUnderTest;
if (frameReference.empty() || frameUnderTest.empty())
{
cout << " < < < Game over! > > > ";
break;
}
++frameNum;
cout << "Frame: " << frameNum << "# ";
psnrV = getPSNR(frameReference, frameUnderTest);
cout << setiosflags(ios::fixed) << setprecision(3) << psnrV << "dB";
if (psnrV < psnrTriggerValue && psnrV)
{
mssimV = getMSSIM(frameReference, frameUnderTest);
cout << " MSSIM: "
<< " 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 << "%";
}
cout << endl;
imshow(WIN_RF, frameReference);
imshow(WIN_UT, frameUnderTest);
char c = (char)waitKey(delay);
if (c == 27) break;
}
waitKey();
return 0;
}
double getPSNR(const Mat& I1, const Mat& I2)
{
Mat s1;
absdiff(I1, I2, s1); // |I1 - I2|
s1.convertTo(s1, CV_32F); // cannot make a square on 8 bits
s1 = s1.mul(s1); // |I1 - I2|^2
Scalar s = sum(s1); // sum elements per channel
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
if (sse <= 1e-10) // for small values return zero
return 0;
else
{
double mse = sse / (double)(I1.channels() * I1.total());
double psnr = 10.0 * log10((255 * 255) / mse);
return psnr;
}
}
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;
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;
}
1.4 imgprocess.cpp
#include "imgprocess.h"
// Use default imgs here to do calculation
const static String dir2 = "../media/desktop1.png";
const static String dir1 = "../media/desktop2.png";
// Use addWeighted() to solve the add and sub
void imageAdd() {
Mat img1 = imread(dir1, IMREAD_COLOR);
Mat img2 = imread(dir2, IMREAD_COLOR);
Mat dst;
double alpha = 0.5; double beta = 1.0 - alpha;
addWeighted( img1, alpha, img2, beta, 0.0, dst);
imshow("IMG1", img1);
imshow("IMG2", img2);
imshow( "1/2 * IMG1 + 1 / 2 * IMG2", dst );
waitKey(0);
}
void imageSub() {
Mat img1 = imread(dir1, IMREAD_COLOR);
Mat img2 = imread(dir2, IMREAD_COLOR);
Mat dst;
double alpha = 1; double beta = -1;
addWeighted( img1, alpha, img2, beta, 0.0, dst);
imshow("img1", img1);
imshow("img2", img2);
imshow( "IMG1 - IMG2", dst );
waitKey(0);
}
void init_lookup_table(uchar* lookup_table) {
for (int i = 0 ; i < 256 ; ++i) {
lookup_table[i] = 255 - i;
}
}
Mat& applyTableRev(Mat& I, const uchar* const table) {
CV_Assert(I.depth() == CV_8U);
uchar *p_row = NULL; // Start position of the row
int nRow = I.rows;
int nCol = I.cols * I.channels();
if (I.isContinuous()) {
nCol *= nRow;
nRow = 1;
}
for (int i = 0 ; i < nRow ; ++i) {
p_row = I.ptr<uchar>(i);
for (int j = 0 ; j < nCol ; ++j) {
p_row[j] = table[p_row[j]];
}
}
return I;
}
Mat& applyMul(Mat& I, Mat& J, Mat& dst) {
CV_Assert(I.depth() == CV_8U);
const int channels = I.channels();
switch (channels) {
case 1 : {
for (int i = 0 ; i < I.rows ; ++i) {
for (int j = 0 ; j < I.cols ; ++j) {
dst.at<uchar>(i, j) = (I.at<uchar> \
(i, j) * J.at<uchar>(i, j)) % 256;
}
}
break;
}
case 3 : {
Mat_<Vec3b> _dst = dst;
Mat_<Vec3b> _I = I, _J = J;
for (int i = 0 ; i < I.rows ; ++i) {
for (int j = 0 ; j < I.cols ; ++j) {
_dst(i, j)[0] = (_I(i, j)[0] * \
_J(i, j)[0]) % 256;
_dst(i, j)[1] = (_I(i, j)[1] * \
_J(i, j)[1]) % 256;
_dst(i, j)[2] = (_I(i, j)[2] * \
_J(i, j)[2]) % 256;
}
}
dst = _dst;
break;
}
}
return dst;
}
void imageRev() {
uchar lookup_table[256];
init_lookup_table(lookup_table);
Mat src = imread(dir1, IMREAD_COLOR);
Mat dst = src.clone();
applyTableRev(dst, lookup_table);
imshow("ORIGIN IMG", src);
imshow("REVERSED IMG", dst);
waitKey(0);
}
void imageMul() {
uchar lookup_table[256];
init_lookup_table(lookup_table);
Mat img1 = imread(dir1, IMREAD_COLOR);
Mat img2 = imread(dir2, IMREAD_COLOR);
Mat dst(img1.size(), img1.type());
applyMul(img1, img2, dst);
imshow("IMG1", img1);
imshow("IMG2", img2);
imshow("IMG1 * IMG2", dst);
waitKey(0);
}
1.5 functrans.cpp
#include "functrans.h"
static void init_lookup_table(uchar* lookup_table) {
double c = 0.8;
int r = 2;
for (int i = 0 ; i < 256 ; ++i) {
lookup_table[i] = int((c * pow((lookup_table[i])/255.0, r)) * 255 + 0.5);
}
}
Mat& applyExp(Mat& I, const uchar* const table) {
CV_Assert(I.depth() == CV_8U);
uchar *p_row = NULL; // Start position of the row
int nRow = I.rows;
int nCol = I.cols * I.channels();
if (I.isContinuous()) {
nCol *= nRow;
nRow = 1;
}
for (int i = 0 ; i < nRow ; ++i) {
p_row = I.ptr<uchar>(i);
for (int j = 0 ; j < nCol ; ++j) {
p_row[j] = table[p_row[j]];
}
}
return I;
}
void expTransform() {
uchar lookup_table[256];
init_lookup_table(lookup_table);
const static String dir1 = "../media/desktop2.png";
Mat src = imread(dir1, IMREAD_COLOR);
Mat dst = src.clone();
applyExp(dst, lookup_table);
imshow("ORIGIN IMG", src);
imshow("Exp IMG", dst);
waitKey(0);
}
1.6 drawhistogram.cpp
#include "drawhistogram.h"
void drawHistogram() {
String dir = "../media/orange_peel.jpeg";
Mat src = imread(dir, IMREAD_COLOR);
vector<Mat> bgr_planes;
split( src, bgr_planes );
int histSize = 256;
float range[] = { 0, 256 }; //the upper boundary is exclusive
const float* histRange = { range };
bool uniform = true, accumulate = false;
Mat b_hist, g_hist, r_hist;
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
int hist_w = 512, hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
}
imshow("Source image", src );
imshow("calcHist Demo", histImage );
waitKey();
}
1.7 histogramselfimplementation.cpp
#include "histogramselfimplementation.h"
#define DEBUG
// Draw histogram without calling the opencv function "calHist"
// Through img scanning and implement own way
void selfDrawHistogram() {
String dir = "../media/orange_peel.jpeg";
Mat I = imread(dir, IMREAD_COLOR);
if (I.empty()) {
std :: cout << "Error open Img" << std :: endl;
exit(0);
}
// Get the size of the Img
int max_b = 0;
int max_g = 0;
int max_r = 0;
// Declear the different color intensity value
int histSize = 256;
// Prepare the container (256 for 256 different intensity)
float b_hist[256], g_hist[256], r_hist[256];
memset(b_hist, 0, sizeof(b_hist));
memset(g_hist, 0, sizeof(g_hist));
memset(r_hist, 0, sizeof(r_hist));
// Count the frequency of apperance times of each intensity
MatIterator_<Vec3b> it, end;
for (it = I.begin<Vec3b>(), end = I.end<Vec3b>() ; it != end ; ++it) {
b_hist[(*it)[0]]++;
g_hist[(*it)[1]]++;
r_hist[(*it)[2]]++;
}
// Manually normalize
for (int i = 0 ; i < 256 ; i++) {
max_b = max_b < b_hist[i] ? b_hist[i] : max_b;
max_g = max_g < g_hist[i] ? g_hist[i] : max_g;
max_r = max_r < r_hist[i] ? r_hist[i] : max_r;
}
#ifdef DEBUG
for (int i = 0 ; i < 256 ; i++) {
std :: cout << "b_hist[i] = " << b_hist[i] << std :: endl;
std :: cout << "g_hist[i] = " << g_hist[i] << std :: endl;
std :: cout << "r_hist[i] = " << r_hist[i] << std :: endl;
}
#endif
// Set the width and the height of the canvas
int hist_w = 512, hist_h = 400;
int bin_w = cvRound( (double) hist_w / histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0, 0, 0 ) );
#ifdef DEBUG
std :: cout << "hist_w = " << hist_w << "hist_h = " << hist_h << std :: endl;
std :: cout << "bin_w = " << bin_w << std :: endl;
#endif
// Normalize the height and width manually
int reduced_height = int(hist_h * 0.9);
for ( int i = 1 ; i < 256 ; i++ ) {
b_hist[i] = ( b_hist[i] / max_b ) * reduced_height;
g_hist[i] = ( g_hist[i] / max_g ) * reduced_height;
r_hist[i] = ( r_hist[i] / max_r ) * reduced_height;
}
#ifdef DEBUG
for ( int i = 0 ; i < 256 ; i++ ) {
std :: cout << "b_hist[i] = " << b_hist[i] << std :: endl;
std :: cout << "g_hist[i] = " << g_hist[i] << std :: endl;
std :: cout << "r_hist[i] = " << r_hist[i] << std :: endl;
}
std :: cout << "" << std :: endl;
waitKey();
#endif
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w * (i-1), b_hist[i-1]),
Point( bin_w * (i), b_hist[i]) ,
Scalar( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w * (i-1), g_hist[i-1]),
Point( bin_w * (i), g_hist[i]),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w * (i-1), r_hist[i-1]),
Point( bin_w * (i), r_hist[i]),
Scalar( 0, 0, 255), 2, 8, 0 );
}
imshow("Source image", I );
imshow("Self Histogram Implementation", histImage );
waitKey();
}
2. Headers
2.1 main.h
#ifndef MAIN_H
#define MAIN_H
// This experiment use the following macros (#)
#include "readImg.h"
#include "readvideo.h"
#include "imgprocess.h"
#include "functrans.h"
#include "drawhistogram.h"
#include "histogramselfimplementation.h"
// This experiment use the following aliases (typedef)
// This experiment has following function definition
void read_img();
#endif // MAIN_H
2.2 readimg.h
#ifndef MAIN_H
#define MAIN_H
// This experiment use the following macros (#)
#include "readImg.h"
#include "readvideo.h"
#include "imgprocess.h"
#include "functrans.h"
#include "drawhistogram.h"
#include "histogramselfimplementation.h"
// This experiment use the following aliases (typedef)
// This experiment has following function definition
void read_img();
#endif // MAIN_H
2.3 readvideo.h
#ifndef READVIDEO_H
#define READVIDEO_H
#include <iostream> // for standard I/O
#include <string> // for strings
#include <iomanip> // for controlling float print precision
#include <sstream> // string to number conversion
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
double getPSNR(const Mat& I1, const Mat& I2);
Scalar getMSSIM(const Mat& I1, const Mat& I2);
int videoReader(int argc, char **argv);
#endif // READVIDEO_H
2.4 imgprocess.h
#ifndef IMGPROCESS_H
#define IMGPROCESS_H
#include <opencv2/opencv.hpp>
using namespace cv;
void imageAdd();
void imageSub();
void imageMul();
void imageRev();
#endif // IMGPROCESS_H
2.5 functrans.h
// Function transformations
#ifndef FUNCTRANS_H
#define FUNCTRANS_H
#include <cmath>
#include <opencv2/opencv.hpp>
using namespace cv;
void expTransform();
#endif // FUNCTRANS_H
2.6 drawhistogram.h
#ifndef DRAWHISTOGRAM_H
#define DRAWHISTOGRAM_H
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
void drawHistogram();
#endif // DRAWHISTOGRAM_H
2.7 histogramselfimplementation.h
#ifndef HISTOGRAMSELFIMPLEMENTATION_H
#define HISTOGRAMSELFIMPLEMENTATION_H
#include <opencv2/opencv.hpp>
using namespace cv;
void selfDrawHistogram();
#endif // HISTOGRAMSELFIMPLEMENTATION_H