2.20、图像旋转
公式:
i′=icosθ−jsinθi′=icosθ−jsinθ
i′=isinθ+jcosθi′=isinθ+jcosθ
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::rotate_demo(Mat &image) { Mat dst, M; int w = image.cols; int h = image.rows; M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0); double cos = abs(M.at<double>(0, 0)); double sin = abs(M.at<double>(0, 1)); int nw = cos * w + sin * h; int nh = sin * w + cos * h; M.at<double>(0, 2) += (nw / 2 - w / 2); M.at<double>(1, 2) += (nh / 2 - h / 2); warpAffine(image, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 255, 0)); imshow("旋转展示", dst); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.rotate_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.21、视频文件摄像头使用
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::video_demo(Mat &image) { //VideoCapture capture(0); //获取当前设备摄像头视频 VideoCapture capture("D:/images/video/example.mp4"); //获取该地址下的视频 Mat frame; while (true) { capture.read(frame); int h = frame.rows; //获取视频每一帧的宽高 int w = frame.cols; //flip(frame, frame, 1); //摄像头需要翻转,视频不需要翻转 if (frame.empty()) { break; } resize(frame, frame, Size(w / 4, h / 4), 0, 0, INTER_LINEAR); //缩放视频 imshow("frame", frame); //显示缩放后的视频 colorSpace_Demo(frame); //调用色彩空间转换函数,将视频转换为灰度图像及HSV图像并显示 // TODO: do something.... int c = waitKey(10); if (c == 27) { //退出 break; } } //release capture.release(); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 //imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.video_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.22、视频处理与保存
分辨率清晰度对照:
视频显示格式 | 分辨率尺寸名 | 汉语简称 |
480p、576p | SD(Standard Definition) | 标清 |
720p | HD(High Definition) | 高清 |
1080p | FHD(Full High Definition) | 全高清 |
2k | QHD(Quad High Definition) | 四倍HD |
4k | UHD(Ultra High Definition) | 超高清 或 4k UHD |
8k | FUHD(Full Ultra High Definition) | 8k超高清 或 8k UHD |
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::video_demo(Mat &image) { //VideoCapture capture(0); //获取当前设备摄像头视频 VideoCapture capture("D:/images/video/example.mp4"); //获取该地址下的视频 int frame_width = capture.get(CAP_PROP_FRAME_WIDTH); //获取视频帧的宽高 int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT); int count = capture.get(CAP_PROP_FRAME_COUNT); //获取视频的全部帧数 double fps = capture.get(CAP_PROP_FPS); //获取视频每秒帧数fps std::cout << "frame width: " << frame_width << std::endl; std::cout << "frame height: " << frame_height << std::endl; std::cout << "FPS: " << fps << std::endl; std::cout << "Number of Frames: " << count << std::endl; int fourcc = VideoWriter::fourcc('a','v','c','1'); //H264编码格式的fourcc code //VideoWriter writer(保存地址,fourcc编码格式code,帧率,保存视频的画面宽高,是否是彩色); VideoWriter writer("D:/test.mp4", fourcc, fps, Size(frame_width, frame_height), true); Mat frame; Mat frame1; while (true) { capture.read(frame); int h = frame.rows; //获取视频每一帧的宽高 int w = frame.cols; //flip(frame, frame, 1); //摄像头需要翻转,视频不需要翻转 if (frame.empty()) { break; } resize(frame, frame1, Size(w / 4, h / 4), 0, 0, INTER_LINEAR); //缩放视频 imshow("frame", frame1); //显示缩放后的视频 //colorSpace_Demo(frame); //调用色彩空间转换函数,将视频转换为灰度图像及HSV图像并显示 writer.write(frame); //将每一帧保存到新的文件中 // TODO: do something.... int c = waitKey(10); if (c == 27) { //退出 break; } } //release capture.release(); writer.release(); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 //imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.video_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
运行过程中缺少H264编码器:
1、出现错误
2、到给出的网站中下载对应的dll
文件
3、将该文件下载解压后放到opencv的bin目录下
4、再次运行正常
注意:H264
对应的fourcc code
为avc1
! 具体原因可以自行百度,与OpenCV遵守的开源协议有关
2.23、图像直方图
图像直方图解释:
图像直方图使图像像素值的统计学特征,计算代价较小,具有图像平移、旋转、缩放不变性等众多优点,广泛地应用域图像处理的各个领域,特别是灰度图像的阈值分割、基于颜色的图像检索以及图像分类、反向投影跟踪。常见的分为灰度直方图、颜色直方图。
Bins是指直方图的大小范围,对于像素值取在0~255之间的,最少有256个bin,此外还可以有16、32、48、128等,256除以bin的大小应该是整数倍。
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); void histogram_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::histogram_demo(Mat &image) { //三通道分离 std::vector<Mat> bgr_plane; //定义Mat类型的集合,用来保存三通道数据 split(image, bgr_plane); //将图像三通道分离,保存到定义的集合中 //定义参数变量 const int channels[1] = { 0 }; const int bins[1] = { 256 }; //总共256个灰度级别,bins[中括号内为该变量一共有几个数值] float hranges[2] = { 0,255 }; //每个通道取值范围0-255 const float* ranges[1] = { hranges }; Mat b_hist; Mat g_hist; Mat r_hist; //计算Blue,Green,Red通道的直方图 //calcHist(输入图像指针,输入图像个数,统计直方图的第几通道,mask()只统计不为0的部分,直方图计算的输出值,输出直方图的维度由channels指定,每个维度分成多少个区间,统计像素值的区间) calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges); calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges); calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges); //显示直方图 int hist_w = 512; int hist_h = 400; int bin_w = cvRound((double)hist_w / bins[0]); Mat histImage = Mat::zeros(hist_h, hist_w,CV_8UC3); //归一化直方图数据 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 < bins[0]; 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, LINE_AA, 0); line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA, 0); line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA, 0); } //显示直方图 namedWindow("Histogram Demo", WINDOW_AUTOSIZE); imshow("Histogram Demo", histImage); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/flower.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.histogram_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.24、二维直方图
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); void histogram_demo(Mat &image); void histogram_2d_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::histogram_2d_demo(Mat &image) { //2D直方图 Mat hsv, hs_hist; cvtColor(image, hsv, COLOR_BGR2HSV); //输入图像色彩空间转化 int hbins = 30, sbins = 32; //H通道分为30个bins,S通道分为32个bins int hist_bins[] = { hbins,sbins }; float h_range[] = { 0,180 }; //图像H通道取值范围 float s_range[] = { 0,256 }; //图像S通道取值范围 const float* hs_ranges[] = { h_range,s_range }; int hs_channels[] = { 0,1 }; //calcHist(输入图像,输入图像个数,输入图像的通道,mask处理值不为0的部分,输出结果,输入直方图的维度,每个维度分成多少区间,每个维度取值范围,) calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false); double maxVal = 0; minMaxLoc(hs_hist, 0, &maxVal, 0, 0); //求图像全局最大最小值 int scale = 10; Mat hist2d_image = Mat::zeros(sbins*scale, hbins*scale, CV_8UC3); Mat hist2d_image_back = Mat::zeros(sbins*scale, hbins*scale, CV_8UC3); for (int h = 0; h < hbins; h++) { for (int s = 0; s < sbins; s++) { float binVal = hs_hist.at<float>(h, s); int intensity = cvRound(binVal * 255 / maxVal); rectangle(hist2d_image, Point(h*scale, s*scale), Point((h + 1)*scale - 1, (s + 1)*scale - 1), Scalar::all(intensity), -1); } } applyColorMap(hist2d_image, hist2d_image_back, COLORMAP_JET); imshow("H-S Histogram", hist2d_image); imshow("H-S Histogram_back", hist2d_image_back); imwrite("D:/hist_2d.png", hist2d_image); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/flower.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.histogram_2d_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.25、直方图均衡化
直方图均衡化的概念:
直方图均衡化(Histogram Equalization)是一种增强图像对比度(Image Contrast)的方法,其主要思想是将一副图像的直方图分布通过累积分布函数变成近似均匀分布,从而增强图像的对比度。为了将原图像的亮度范围进行扩展, 需要一个映射函数, 将原图像的像素值均衡映射到新直方图中, 这个映射函数有两个条件:
①不能打乱原有的像素值大小顺序, 映射后亮、 暗的大小关系不能改变;
② 映射后必须在原有的范围内,即像素映射函数的值域应在0和255之间;
综合以上两个条件,累积分布函数是个好的选择,因为累积分布函数是单调增函数(控制大小关系),并且值域是0到1(控制越界问题),所以直方图均衡化中使用的是累积分布函数。
累积分布函数的数学原理:
因为图像由一个个像素点组成,所以图像直方图均衡化是通过离散形式的累积分布函数求解的,直方图均衡化过程中,映射方法是:
Sk=∑j=0knjnk=0,1,2,...,L−1Sk=∑j=0knjnk=0,1,2,...,L−1
其中,S_k指当前灰度级经过累积分布函数映射后的值,n是图像中像素的总和,n_j是当前灰度级的像素个数,L是图像中的灰度级总数。
直方图均衡化的步骤:
①依次扫描原始灰度图像的每一个像素, 计算出图像的灰度直方图;
②计算灰度直方图的累积分布函数;
③根据累积分布函数和直方图均衡化原理得到输入与输出之间的映射关系。
④最后根据映射关系得到结果进行图像变换
直观理解直方图均衡化原理及过程:
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); void histogram_demo(Mat &image); void histogram_2d_demo(Mat &image); void histogram_eq_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::histogram_eq_demo(Mat &image) { Mat gray; cvtColor(image, gray, COLOR_BGR2GRAY); imshow("灰度图像", gray); Mat dst; equalizeHist(gray, dst); imshow("直方图均衡化演示", dst); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/flower.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.histogram_eq_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.26、图像卷积操作
卷积运算原理示意图:
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); void histogram_demo(Mat &image); void histogram_2d_demo(Mat &image); void histogram_eq_demo(Mat &image); void blur_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::blur_demo(Mat &image) { Mat dst01, dst02, dst03, dst04, dst05; //blur为均值卷积,卷积后求平均值得到对应的值 //blur(输入图像,输出图像,卷积核大小,卷积输出位置默认为中心(-1,-1)),默认均值卷积核,卷积核越大模糊程度越高 blur(image, dst01, Size(3, 3), Point(-1, -1)); blur(image, dst02, Size(13, 13), Point(-1, -1)); blur(image, dst03, Size(23, 23), Point(-1, -1)); blur(image, dst04, Size(13, 1), Point(-1, -1)); blur(image, dst05, Size(1, 13), Point(-1, -1)); imshow("图像模糊01", dst01); imshow("图像模糊02", dst02); imshow("图像模糊03", dst03); imshow("图像模糊04", dst04); imshow("图像模糊05", dst05); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/flower.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.blur_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.27、高斯模糊
高斯模糊计算公式:
高斯核函数符合空间正态分布(正态分布又名高斯分布),越靠近卷积核中心的值权重越大
高斯函数示意图:
高斯模糊计算公式:
G(x,y)=12πσ2e−(x2+y2)/(2σ2)G(x,y)=12πσ2e−(x2+y2)/(2σ2)
该计算公式可看作是二维正态分布函数,是根据一维高斯函数推导来的,一维高斯函数就是正态分布函数。
使用高斯模糊计算公式根据输入的参数计算高斯权重矩阵,具体计算方法可参考该文章:https://blog.csdn.net/qq_32515081/article/details/115006246。
得到权重矩阵后,按卷积核计算规则将每个值乘以对应的矩阵再求和即可得到中心点对应的值。
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); void histogram_demo(Mat &image); void histogram_2d_demo(Mat &image); void histogram_eq_demo(Mat &image); void blur_demo(Mat &image); void gaussian_blue_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::gaussian_blue_demo(Mat &image) { Mat dst01, dst02, dst03; //GaussianBlur(输入图像,输出图像,卷积核大小,高斯函数σ的值(默认σx=σy),边缘处理方式) GaussianBlur(image, dst01, Size(5, 5), 15); GaussianBlur(image, dst02, Size(3, 3), 15); GaussianBlur(image, dst03, Size(0, 0), 15); imshow("高斯模糊01",dst01); imshow("高斯模糊02",dst02); imshow("高斯模糊03",dst03); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/flower.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.gaussian_blue_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
2.28、高斯双边模糊
双边滤波原理:
- 空间距离:当前点距离滤波模板中心点的欧式距离。
- 灰度距离:当前点距离滤波模板中心点的灰度的差值的绝对值。
双边滤波的核函数是空间域核与像素范围域核的综合结果:
- 在图像的平坦区域,像素值变化很小,那么像素差值接近于0,对应的像素范围域权重接近于1,此时空间域权重起主要作用,相当于进行高斯模糊;
- 在图像的边缘区域,像素值变化很大,那么像素差值大,对应的像素范围域权重变大,即使距离远空间域权重小,加上像素域权重总的系数也较大,从而保护了边缘的信息。
双边滤波在突变的边缘上,使用了像素差权重,很好的保留了边缘。
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); void histogram_demo(Mat &image); void histogram_2d_demo(Mat &image); void histogram_eq_demo(Mat &image); void blur_demo(Mat &image); void gaussian_blue_demo(Mat &image); void bifilter_demo(Mat &image); };
quickdemo.cpp
void QuickDemo::bifilter_demo(Mat &image) { Mat dst; bilateralFilter(image, dst, 0, 100, 10); imshow("双边模糊", dst); }
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.bifilter_demo(src); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果
3、案例:实时人脸识别
先下载三个文件置于opencv的face_detector路径下:D:\environment\opencv\sources\samples\dnn\face_detector
下载地址及文件如下:
quickopencv.h
#pragma once #include<opencv2/opencv.hpp> using namespace cv; class QuickDemo { public: void colorSpace_Demo(Mat &image); void mat_creation_demo(); void pixel_visit_demo(Mat &image); void operators_demo(Mat &image); void tracking_bar_demo(Mat &image); void key_demo(Mat &image); void color_style_demo(Mat &image); void bitwise_demo(Mat &image); void channels_demo(Mat &image); void inrange_demo(Mat &image); void pixel_statistic_demo(Mat &image); void form_paint_random(); void polyline_drawing_demo(); void mouse_drawing_demo(Mat &image); void norm_demo(Mat &image); void resize_demo(Mat &image); void flip_demo(Mat &image); void rotate_demo(Mat &image); void video_demo(Mat &image); void histogram_demo(Mat &image); void histogram_2d_demo(Mat &image); void histogram_eq_demo(Mat &image); void blur_demo(Mat &image); void gaussian_blue_demo(Mat &image); void bifilter_demo(Mat &image); void face_detection_demo(); };
quickdemo.cpp
#include<quickopencv.h> #include<opencv2/dnn.hpp> using namespace cv; using namespace std; void QuickDemo::face_detection_demo() { std::string root_dir = "D:/environment/opencv/sources/samples/dnn/face_detector/"; //读取深度神经网络 dnn::readNetFromTensorflow(路径+模型文件名,路径+配置文件名) dnn::Net net = dnn::readNetFromTensorflow(root_dir + "opencv_face_detector_uint8.pb", root_dir + "opencv_face_detector.pbtxt"); VideoCapture capture("D:/images/video/example_dsh.mp4"); //加载一段视频 Mat frame; while (true) { capture.read(frame); if (frame.empty()) { break; } //张量(tensor)可以看作是一个多维矩阵,这里定义一个张量blob //dnn::blobFromImage(输入图像,scale factor 1.0表示色彩空间还是0-255,模型要求的输入尺寸,模型要求的均值(models.yml文件中的mean值),是否进行通道交换(models.yml文件中),是否要剪切图像) Mat blob = dnn::blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false); //将输入图像张量输入到深度神经网络中 net.setInput(blob); //输入的blob格式 NCHW 多少个图像,输入通道数,高度,宽度 //对输入图片进行推理 Mat probs = net.forward(); //输出结果(多少张图像每张图有对应编号,每张图第几个批次第几张图,多少框,每个框有7列) Mat detectionMat(probs.size[2], probs.size[3], CV_32F, probs.ptr<float>()); //只获取输出结果的后两部分 //解析结果 for (int i = 0; i < detectionMat.rows; i++) { //前两个值代表类型和index,第三个值是人脸得分 float confidence = detectionMat.at<float>(i, 2); //判断是否是人脸的部分 if (confidence > 0.5) { //得到人脸部分矩形的左上角和右下角坐标,用户绘制检测框 int x1 = static_cast<int>(detectionMat.at<float>(i, 3)*frame.cols); int y1 = static_cast<int>(detectionMat.at<float>(i, 4)*frame.rows); int x2 = static_cast<int>(detectionMat.at<float>(i, 5)*frame.cols); int y2 = static_cast<int>(detectionMat.at<float>(i, 6)*frame.rows); Rect box(x1, y1, x2 - x1, y2 - y1); rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0); } } imshow("人脸检测演示", frame); //TODO: do something... int c = waitKey(1); if (c == 27) { //退出 break; } } }
深度神经网络模型models.yml配置文件说明:
test440.cpp
#include<opencv2/opencv.hpp> #include<quickopencv.h> #include<iostream> using namespace cv; using namespace std; int main(int argc, char**argv) { // imread函数的第二个参数有很多,默认为IMREAD_COLOR,还有IMREAD_UNCHANGED,IMREAD_GRAYSCALE,IMREAD_ANYCOLOR等等,实现对不同图片的读取操作 // B,G,R Mat src = imread("D:/images/lena.jpg"); //Mat为matrix,二维图像都是Mat类型,第一个参数为图片绝对路径 if (src.empty()) { printf("could not load image...\n"); return -1; } //namedWindow("输入窗口", WINDOW_FREERATIO); //不管图片大小,都能进行调整,图像很小可以不使用这个函数 //imshow("输入窗口", src); //第一个参数为窗口名 QuickDemo qd; qd.face_detection_demo(); waitKey(0); //窗口停留时间,0为一直停留,数值为停留的毫秒数 destroyAllWindows(); //关闭所有打开的窗口 return 0; }
效果