课程来源:哔哩哔哩

环境:OpenCV4.5.1 + VS2019

目录

002.图像色彩空间转换

003.图像对象的创建与赋值

004.图像像素的读写操作

005.图像像素的算术操作(加减乘除4种不同的API实现

006.滚动条-调整图像亮度

007.滚动条-传递参数

008.键盘响应操作

009.OpenCV自带颜色表操作

010.图像像素的逻辑操作(与,或,非,异或

011.通道合并与分离

012.图像色彩空间转换(提取轮廓然后换绿幕

013.图像像素值统计(min,max,mean均值,standard deviation标准方差

014.图像几何形状绘制(圆,矩形,直线,椭圆

015.随机数与随机颜色

016.多边形填充与绘制

017.鼠标操作与响应(提取选中的ROI区域

018.图像像素类型转换和归一化

019.图像放缩与插值

020.图像翻转

021.图像旋转

022.视频文件摄像头使用

023.视频处理与保存

024.图像直方图

025.二维直方图

026.直方图均衡化

027.图像卷积操作(会变模糊,且卷积核尺寸越大则越模糊

028.高斯模糊

029.高斯双边模糊(可磨皮操作

030.案例:实时人脸检测

代码总结


002.图像色彩空间转换

void colorSpace_Demo(Mat &image);

void QuickDemo::colorSpace_Demo(Mat &image) {Mat gray, hsv; //定义2个矩阵类型的图像cvtColor(image, hsv, COLOR_BGR2HSV);    //转换成hdv (图像转换函数,第三个参数是转成的类型cvtColor(image, gray, COLOR_BGR2GRAY);    //转成灰度imshow("HSV", hsv);     //显示图片imshow("灰度", gray); //显示图片//imwrite("F:\\文件夹\\C++\\OPENCV4入门学习\\图\\hsv.png", hsv);      //保存图片 (保存地址,保存图的名称)//imwrite("F:\\文件夹\\C++\\OPENCV4入门学习\\图\\gray.png", gray); //保存
}

003.图像对象的创建与赋值

void mat_creation_demo(/*Mat& image*/);

void QuickDemo::mat_creation_demo(/*Mat& image*/) {//Mat m1, m2;//m1 = image.clone();//image.copyTo(m2);//创建空白图形Mat m3 = Mat::ones(Size(400, 400), CV_8UC3);   //8位的无符号的3通道(改1则为单通道//ones 改 zeros则初始化为0//长度 = 通道数 * 宽度m3 = Scalar(255, 0, 0);     //给三个通道都赋值,单通道则 m3 = 127;//m3初始化为蓝色cout << "width:" << m3.cols << endl << "hight:" << m3.rows << endl << "channels:" << m3.channels() << endl;//显示宽度,长度,通道数//cout << m3 << endl;Mat m4;//m4 = m3;            //直接赋值 则m4变,m3也变(同体//m4 = m3.clone();    //m4为m3的克隆,m4变,m3不会变(不同体m3.copyTo(m4);     //把m3赋值给m4,m4为蓝色m4 = Scalar(0, 255, 255);   //改变m4的颜色为黄色imshow("图像3", m3);        //标题和图像名称  显示图像3 纯蓝色imshow("图像4", m4);
}

004.图像像素的读写操作

void pixel_visit_demo(Mat &image);

void QuickDemo::pixel_visit_demo(Mat &image) {int dims = image.channels();int h = image.rows;int w = image.cols;//数组下标访问像素值/*for (int row = 0; row < h; row++) {for (int col = 0; col < w; col++) {if (dims == 1) { //单通道的灰度图像int pv = image.at<uchar>(row, col);        //得到像素值image.at<uchar>(row, col) = 255 - pv; //给像素值重新赋值(取反}if (dims == 3) { //三通道的彩色图像Vec3b bgr = image.at<Vec3b>(row, col); //opencv特定的类型,获取三维颜色,3个值image.at<Vec3b>(row, col)[0] = 255 - bgr[0];image.at<Vec3b>(row, col)[1] = 255 - bgr[1];image.at<Vec3b>(row, col)[2] = 255 - bgr[2]; //对彩色图像读取其像素值,并将其改写}}}*///指针访问模式for (int row = 0; row < h; row++) {uchar* current_row = image.ptr<uchar>(row);for (int col = 0; col < w; col++) {if (dims == 1) {   //单通道的灰度图像int pv = image.at<uchar>(row, col);        //得到像素值*current_row++ = 255 - pv;    //给像素值重新赋值(取反}if (dims == 3) { //三通道的彩色图像*current_row++ = 255 - *current_row;   //指针每做一次运算,就向后移动一位*current_row++ = 255 - *current_row;*current_row++ = 255 - *current_row;}}}namedWindow("像素读写演示", WINDOW_FREERATIO);imshow("像素读写演示", image);//imwrite("E:/2021.9.26备份/图片/Camera Roll/003颜色取反.png", image);  //保存
}

005.图像像素的算术操作(加减乘除4种不同的API实现

void operators_demo(Mat &image);

void QuickDemo::operators_demo(Mat &image) {Mat dst = Mat::zeros(image.size(), image.type());Mat m = Mat::zeros(image.size(), image.type());dst = image - Scalar(50, 50, 50);m = Scalar(50, 50, 50);multiply(image, m, dst); //乘法操作 apiimshow("乘法操作", dst);add(image, m, dst);         //加法操作 apiimshow("加法操作", dst);subtract(image, m, dst);    //减法操作 apiimshow("减法操作", dst);divide(image, m, dst);      //除法操作 apiimshow("除法操作", dst);//加法操作底层/*int dims = image.channels();int h = image.rows;int w = image.cols;for (int row = 0; row < h; row++) {for (int col = 0; col < w; col++) {Vec3b p1 = image.at<Vec3b>(row, col);   //opencv特定的类型,获取三维颜色,3个值Vec3b p2 = m.at<Vec3b>(row, col);dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);}}namedWindow("加法操作底层", WINDOW_FREERATIO);imshow("加法操作底层", dst);*/
}

006.滚动条-调整图像亮度

void tracking_bar_demo1(Mat &image);

Mat src, dst, m;
int lightness = 50;//定义初始化的亮度为50
static void on_track(int, void*) {m = Scalar(lightness, lightness, lightness);//创建调整亮度的数值add(src, m, dst);//subtract(src, m, dst);//定义亮度变换为减imshow("亮度调整", dst);//显示调整亮度之后的图片
}void QuickDemo::tracking_bar_demo1(Mat &image) {namedWindow("亮度调整", WINDOW_AUTOSIZE);dst = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像m = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像src = image;//给src赋值int max_value = 100;//定义最大值为100createTrackbar("Value Bar", "亮度调整", &lightness, max_value, on_track);//调用函数实现功能on_track(50, 0);
}

007.滚动条-传递参数

void tracking_bar_demo2(Mat &image);

static void on_lightness(int b, void* userdata) {Mat image = *((Mat*)userdata);Mat dst = Mat::zeros(image.size(), image.type());Mat m = Mat::zeros(image.size(), image.type());m = Scalar(b, b, b);//创建调整亮度的数值addWeighted(image, 1.0, m, 0, b, dst); //融合两张图 dst = image * 1.0 + m * 0 + bimshow("亮度&对比度调整", dst);//显示调整亮度之后的图片
}
static void on_contrast(int b, void* userdata) {Mat image = *((Mat*)userdata);Mat dst = Mat::zeros(image.size(), image.type());Mat m = Mat::zeros(image.size(), image.type());double contrast = b / 100.0;addWeighted(image, contrast, m, 0.0, 0, dst);imshow("亮度&对比度调整", dst);//显示调整亮度之后的图片
}void QuickDemo::tracking_bar_demo2(Mat& image) {namedWindow("亮度&对比度调整", WINDOW_AUTOSIZE);int lightness = 50;//定义初始化的亮度为50int max_value = 100;//定义最大值为100int contrast_value = 100;createTrackbar("Value Bar", "亮度&对比度调整", &lightness, max_value, on_lightness, (void*)(&image));//调用函数实现功能createTrackbar("Contrast Bar", "亮度&对比度调整", &contrast_value, 200, on_contrast, (void*)(&image));//调用函数实现功能on_lightness(50, &image);
}

008.键盘响应操作

void key_demo(Mat &image);

void QuickDemo::key_demo(Mat& image) {Mat dst = Mat::zeros(image.size(), image.type());while (true) {char c = waitKey(100);//等待100ms(1s = 1000ms),做视频处理都是1if (c == 27) {   //按 esc 退出应用程序break;}if (c == 49) {   //key#1cout << "you enter key #1" << endl;cvtColor(image, dst, COLOR_BGR2GRAY); //按键盘1,则转换后为灰度图像}if (c == 50) {  //key#2cout << "you enter key #2" << endl;cvtColor(image, dst, COLOR_BGR2HSV); //按键盘1,则转换后为HSV图像}if (c == 51) {  //key#3cout << "you enter key #3" << endl;dst = Scalar(50, 50, 50);cvtColor(image, dst, COLOR_BGR2HSV); //直接1到3会报错,则先转换为HSV图像add(image, dst, dst); //按键盘1,则转换后为增加亮度后的图像}imshow("键盘响应",dst);  //输出图像}
}

009.OpenCV自带颜色表操作

void color_style_demo(Mat& image);

void QuickDemo::color_style_demo(Mat& image) {int colormap[] = {    //共19种COLORMAP_AUTUMN,COLORMAP_BONE,COLORMAP_CIVIDIS,COLORMAP_DEEPGREEN,COLORMAP_HOT,COLORMAP_HSV,COLORMAP_INFERNO,COLORMAP_JET,COLORMAP_MAGMA,COLORMAP_OCEAN,COLORMAP_PINK,COLORMAP_PARULA,COLORMAP_RAINBOW,COLORMAP_SPRING,COLORMAP_TWILIGHT,COLORMAP_TURBO,COLORMAP_TWILIGHT,COLORMAP_VIRIDIS,COLORMAP_TWILIGHT_SHIFTED,COLORMAP_WINTER};Mat dst;int index = 0; //初始化为指向0的位置while (true) {char c = waitKey(500);//等待半秒(1s = 1000ms),做视频处理都是1if (c == 27) { //按 esc 退出应用程序break;}if (c == 49) {   //key#1 按下按键1时。保存图片到指定位置cout << "you enter key #1" << endl;imwrite("F:/文件夹/C++/OPENCV4入门学习/图/颜色表的成果.jpg", dst);}applyColorMap(image, dst, colormap[index % 19]);//循环展示19种图片(产生伪色彩图像)index++;imshow("循环播放", dst);}
}

010.图像像素的逻辑操作(与,或,非,异或

void bitwise_demo(Mat& image);

void QuickDemo::bitwise_demo(Mat& image) {//绘制两张图Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);//-1 =》小于0为填充,大于0为绘制// Rect(左上角x,左上角y,矩形长,矩形宽)           |=》搞锯齿的(表示四领域或者八领域的绘制//最后的参数0表示中心坐标 或 半径坐标的小数位rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);//小于0为填充,大于0为绘制imshow("m1", m1);imshow("m2", m2);//进行逻辑操作Mat dst;bitwise_and(m1, m2, dst);  //位操作 与imshow("像素位操作 与", dst);bitwise_or(m1, m2, dst);    //位操作 或imshow("像素位操作 或", dst);// dst = ~image;           //位操作 非(取反bitwise_not(image, dst);   //位操作 非(取反imshow("像素位操作 非", dst);bitwise_xor(m1, m2, dst); //位操作 异或imshow("像素位操作 异或", dst);
}

与,或,异或 效果如图:

非操作: 

011.通道合并与分离

void channels_demo(Mat& image);

void QuickDemo::channels_demo(Mat& image) {vector<Mat>mv;//可存放Mat类型的容器split(image, mv);//将多通道 拆分成 单通道(通道分离//imshow("蓝色", mv[0]);//imshow("绿色", mv[1]);//imshow("红色", mv[2]);// 三个通道分别为 B G R// 0,1,2 三个通道分别代表 B G R//关闭其中两个通道,则意味着 只开启剩余那个通道Mat dst;mv[0] = 0;mv[2] = 0;   // 关0,1则红色  关1,2则蓝色merge(mv, dst);//合并mv和dstimshow("绿色", dst);int from_to[] = { 1,2,1,1,2,0 };//把通道相互交换,第0->第2,第1->第1,第2->第0mixChannels(&image, 1, &dst, 1, from_to, 3);//3表示有3对要交换(即3个通道//参数为要进行混合的图像的地址,参数2为混合后图像的存放地址imshow("通道混合", dst);imshow("原图image不会变", image);
}

只开放绿色通道 / B与R交换后的通道混合

012.图像色彩空间转换(提取轮廓然后换绿幕

void inrange_demo(Mat& image);

void QuickDemo::inrange_demo(Mat& image) {//提取任务的轮廓Mat hsv;cvtColor(image, hsv, COLOR_BGR2HSV);//先把RGB色彩空间转换到hsv的空间中Mat mask;//其次提取图片的maskinRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), mask);//通过inRange提取hsv色彩空间的颜色//35,43,46根据图片表中的绿色最低来确定最小值(hmin,smin,vmim//77,255,255                          最大值//参数一为低范围,参数二高范围//将hsv中的由低到高的像素点提取出来并存储到mask中imshow("mask", mask);          //此时mask为白底Mat redback = Mat::zeros(image.size(), image.type());redback = Scalar(40, 40, 200);    //红色背景图bitwise_not(mask, mask);     //取反变成黑底imshow("mask", mask);image.copyTo(redback, mask);//将mask中不为0部分(白色像素点)对应的原图 拷贝到 redback上,mask通过inRange得到imshow("roi区域提取", redback);
}

HSV色彩空间的颜色:

013.图像像素值统计(min,max,mean均值,standard deviation标准方差

void pixel_statistic_demo(Mat& image);

void QuickDemo::pixel_statistic_demo(Mat& image) {double minv, maxv;Point minLoc, maxLoc;    //定义地址vector<Mat> mv;         //可存放Mat类型的容器split(image, mv);      //将多通道 拆分成 单通道(通道分离for (int i = 0; i < mv.size(); i++) {//分别打印各个通道的数值minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());//求出图像的最大值和最小值及其位置//参数一:输入单通道的数组       //参数二:返回最小值的指针           参数三:返回最大值的指针//参数四:返回最小值位置的指针      参数五:返回最大值位置的指针cout << "No.channels:" << i << "  minvalue:" << minv << "  maxvalue:" << maxv << endl;}Mat mean, stddev;meanStdDev(image, mean, stddev);//求出图像的均值的方差cout << "mean:" << mean << endl;cout << "stddev:" << stddev << endl;
}

014.图像几何形状绘制(圆,矩形,直线,椭圆

void drawing_demo(Mat& image);

void QuickDemo::drawing_demo(Mat& image) {Rect rect;             //矩形尺寸rect.x = 200;            //起始点x坐标rect.y = 200;          //起始点y坐标rect.width = 150;      //矩形宽度rect.height = 200;       //矩形高度Mat bg = Mat::zeros(image.size(), image.type());rectangle(bg, rect, Scalar(0, 0, 255), -1, 8, 0);                                //画矩形//参数一:绘图的底图或画布名称   参数二:图片的起始,宽高//参数三:填充颜色               参数四:>0为线宽,<0为填充//参数五:领域填充(控制边缘锯齿     参数六:默认值为0circle(bg, Point(350, 400), 25, Scalar(0, 255, 0), 2, LINE_AA, 0);             //画圆//参数二:图片中心的位置         参数三:表示圆的半径为25line(bg, Point(100, 100), Point(350, 400), Scalar(255, 0, 0), 8, LINE_AA, 0);  //画直线//参数二:线段起点坐标         参数三:线段终点坐标       LINE_AA表示去掉锯齿RotatedRect rrt;              //角度构造rrt.center = Point(200, 200);    //中心点位置rrt.size = Size(100, 200);      //x正沿x正方向,y正沿y正方向(可以是负的rrt.angle = 0.0;              //顺时针的角度(0-360度ellipse(bg, rrt, Scalar(255, 0, 255), 2, 8);                                  //画椭圆imshow("矩形,圆,直线,椭圆的绘制", bg);
}

015.随机数与随机颜色

void random_demo();

void QuickDemo::random_demo() {Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);//创建画布int w = canvas.cols;int h = canvas.rows;RNG rng(12345);     //产生随机数(12345为随机数的种子,默认的while (true) {char c = waitKey(10);//等待10ms(1s = 1000ms),做视频处理都是1if (c == 27) {  //按 esc 推出应用程序break;}int x1 = rng.uniform(0, canvas.cols); //将随机坐标控制在画布范围内int y1 = rng.uniform(0, canvas.rows);int x2 = rng.uniform(0, w);int y2 = rng.uniform(0, h);int r = rng.uniform(0, 255);          //将随机颜色控制在255范围内int g = rng.uniform(0, 255);           //将随机颜色控制在255范围内int b = rng.uniform(0, 255);           //将随机颜色控制在255范围内//canvas = Scalar(0, 0, 0);                //想要每次都只出现一条线而不是叠加,则加上此句line(canvas, Point(x1, y1), Point(x2, y2), Scalar(r, g, b), 2, LINE_AA); //画直线//参数二:线段起点坐标        参数三:线段终点坐标   2为线宽         LINE_AA表示去掉锯齿imshow("随机绘制演示", canvas);}
}

016.多边形填充与绘制

void polyline_drawing_demo(Mat& image);

void QuickDemo::polyline_drawing_demo(Mat& image) {Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);Point p1(150, 100);     //第一个点的坐标Point p2(350, 200);        //  二Point p3(240, 300);        //  三Point p4(150, 300);        //  四Point p5(50, 200);     //  五vector<Point> pts;                           //搞一个容器,用来装 点pts.push_back(p1);      //将点放进容器内pts.push_back(p2);     //因 未初始化数组容量,所以要用 push_back 操作pts.push_back(p3);     //若 已初始化,可以用 数组下标 来操作pts.push_back(p4);pts.push_back(p5);//fillPoly(canvas, pts, Scalar(122, 155, 255), 8, 0);               //填充多边形//polylines(canvas, pts, true, Scalar(90, 0, 255), 2, 8, 0);     //绘制多边形//参数一:画布              参数二:点集           参数三:一定要写true(封闭图形//参数倒3:线宽(最少为1        参数倒2:线的渲染方式  参数倒1:相对左上角(0,0)的位置//单个API搞定多边形的绘制和填充vector<vector<Point>> contours;                //搞一个容器,用来装 多边形的点集contours.push_back(pts);       //将一个多边形的点集放进容器内,作为一个元素drawContours(canvas, contours, -1, Scalar(0, 0, 255), -1);            //参数倒1:<0表示填充,>0表示线宽//参数二:多边形的点集     参数三:-1为绘制全部的多边形;0为绘制第一个,1为绘制第二个,以此类推imshow("多边形绘制", canvas);
}

017.鼠标操作与响应(提取选中的ROI区域

void mouse_drawing_demo(Mat& image);

//选中的矩形区域提取
Point sp(-1, -1);   //鼠标的起始位置
Point ep(-1, -1);   //鼠标的结束位置
Mat temp;
static void on_draw(int event, int x, int y, int flags, void* userdata) {//参数一(event)为鼠标事件Mat image = *((Mat*)userdata);if (event == EVENT_LBUTTONDOWN) {          //若鼠标的左键按下sp.x = x;sp.y = y;      //此时鼠标的起始位置坐标cout << "start point" << sp << endl;}else if (event == EVENT_LBUTTONUP) {        //若鼠标的左键抬起ep.x = x;ep.y = y;      //此时鼠标的结束位置坐标int dx = ep.x - sp.x;int dy = ep.y - sp.y;if (dx > 0 && dy > 0) {      //若鼠标有移动过Rect box(sp.x, sp.y, dx, dy);imshow("ROI区域", image(box));rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);imshow("鼠标绘制", image);              //这里是为了显示结果sp.x = -1;  //复位,为下一次做准备sp.y = -1;  //复位,为下一次做准备}}else if (event == EVENT_MOUSEMOVE) {     //若鼠标正在移动if (sp.x > 0 && sp.y > 0) {ep.x = x;ep.y = y;      //此时鼠标的结束位置坐标int dx = ep.x - sp.x;int dy = ep.y - sp.y;if (dx > 0 && dy > 0) {      //若鼠标有移动过Rect box(sp.x, sp.y, dx, dy);temp.copyTo(image);   //为了不将鼠标移动过程中的框也显示出来rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);imshow("鼠标绘制", image);          //这里是为了每次重新提取都将前面的覆盖}}}
}
void QuickDemo::mouse_drawing_demo(Mat& image) {namedWindow("鼠标绘制", WINDOW_AUTOSIZE);setMouseCallback("鼠标绘制",on_draw, (void*)(&image));//设置窗口是回调函数,参数二表示调用on_drawimshow("鼠标绘制", image);temp = image.clone();
}

018.图像像素类型转换和归一化

void norm_demo(Mat& image);

void QuickDemo::norm_demo(Mat& image) {Mat dst;cout << image.type() << endl;             //打印图片的类型image.convertTo(image, CV_32F);                //将image的数据转换成浮点型float32位数据cout << image.type() << endl;                //打印转换后的图片数据类型normalize(image, dst, 1.0, 0, NORM_MINMAX);   //进行归一化操作//参数一:要进行归一化的图片 参数二:归一化后要输出的图片//参数三:alpha                 参数四:beta         参数五:归一化方法cout << dst.type() << endl;                 //打印归一化后的图像的类型imshow("图像的归一化", dst);              //显示归一化后的图像//CV_8UC3   原本为 3通道,每个通道8位的UC(无符号)类型//CV_32FC3  转换后 3通道,每个通道32位的浮点数类型/*归一化方法:NORM_L1(依据sum)             b不用,a为归一化后矩阵的范数值NORM_L2(依据单位向量为1)      b不用,a为 同上NORM_MINMAX(依据最大值)        b不用,a为 同上NORM_INF(依据min与max的差值)    a为归一化后的最小值,b归一化后的最大值*/
}

019.图像放缩与插值

void resize_demo(Mat& image);

void QuickDemo::resize_demo(Mat& image) {Mat zoomin, zoomout;int h = image.rows;int w = image.cols;resize(image, zoomout, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);     // INTER_LINEAR 为线性插值//若Size里的值没变,则按照参数四fx(水平轴)和参数五fy(垂直轴)来进行放缩操作//参数六:插值的方法imshow("zoomout", zoomout);resize(image, zoomin, Size(w * 1.5, h * 1.5), 0, 0, INTER_LINEAR);imshow("zoomin", zoomin);
}

020.图像翻转

void flip_demo(Mat& image);

void QuickDemo::flip_demo(Mat& image) {Mat dst;flip(image, dst, 0);          // 0 上下翻转 x对称imshow("图像上下翻转", dst);flip(image, dst, 1);           // 1 左右翻转 y对称imshow("图像左右翻转", dst);flip(image, dst, -1);          //-1 上下左右都翻转(相当于旋转180°)imshow("图像上下左右翻转", dst);
}

021.图像旋转

void rotate_demo(Mat& image);

void QuickDemo::rotate_demo(Mat& image) {Mat dst, M;             //M为2*3的变换矩阵(旋转矩阵)int w = image.cols;        //图片宽度int h = image.rows;      //图片高度M = getRotationMatrix2D(Point(w / 2, h / 2), 45, 1.0);   //获得旋转矩阵 M//参数一:原来图像的中心点位置       参数二:旋转角度(逆时针)    参数三:图像本身大小的放大缩小double cos = abs(M.at<double>(0, 0));  //取绝对值double sin = abs(M.at<double>(0, 1));/*[x'] = [ cos  sin] * [x][y']   [-sin  cos]   [y],M =    [ cos  sin  0][-sin  cos  0], (第三列用来控制平移)*/double nw = cos * w + sin * h;       //旋转后图像所占矩形的宽double nh = sin * w + cos * h;       //旋转后图像所占矩形的高//更新 新的中心  (将新中心平移到正确位置上)M.at<double>(0, 2) += (nw / 2 - w / 2);     //将矩形的宽高 加上偏差量  (新M的第一列最后的值)M.at<double>(1, 2) += (nh / 2 - h / 2);       //将矩形的宽高 加上偏差量  (新M的第二列最后的值)warpAffine(image, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 255, 0));    //进行旋转//参数四:原来图像的中心点位置       参数五:插值方式//参数六:边缘的处理方式         参数七:边缘底图的颜色//namedWindow("旋转演示", WINDOW_FREERATIO); //可调整显示图片的窗口大小imshow("旋转演示", dst);
}

022.视频文件摄像头使用

void video_demo1(Mat& image);

void QuickDemo::video_demo1(Mat& image) {//读已有视频VideoCapture capture("E:/2021.9.26备份/图片/Camera Roll/人脸素材.mp4");//读取视频地址Mat frame;  //定义一个二值化的 framewhile (true) {capture.read(frame);//flip(frame, frame, 1);          // 1 左右翻转 y对称 (镜像)if (frame.empty())  //如果读入失败{break; //若视频为空,则跳出操作}imshow("frame", frame);          //显示视频colorSpace_Demo(frame);           //对视频调用之前的demoint c = waitKey(1);          //等待10ms(1s = 1000ms),做视频处理都是1if (c == 27) {    //按 esc 退出应用程序break;}}capture.release();    //释放相机的资源/*//调用电脑摄像头VideoCapture capture(0);Mat frame;  //定义一个二值化的 framewhile (true) {capture.read(frame);if (frame.empty())    //如果读入失败{break; //若视频为空,则跳出操作}flip(frame, frame, 1);         // 1 左右翻转 y对称 (镜像)imshow("frame", frame);           //显示视频int c = waitKey(10);         //等待10ms(1s = 1000ms),做视频处理都是1if (c == 27) {    //按 esc 退出应用程序break;}}*/
}

023.视频处理与保存

void video_demo2(Mat& image);

void QuickDemo::video_demo2(Mat& image) {//视频的属性:SD(标清),HD(高清),UHD(超清),蓝光。VideoCapture capture("E:/2021.9.26备份/图片/Camera Roll/人脸素材.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);            //获取视频总的帧数//fps是衡量处理视频的能力 (一秒钟处理多少张图片的能力,处理速度越快则越好)double fps = capture.get(CAP_PROP_FPS);cout << "frame width:" << frame_width << endl;cout << "frame height:" << frame_height << endl;cout << "FPS:" << fps << endl;cout << "Number of frame:" << count << endl;VideoWriter writer("F:/文件夹/C++/OPENCV4入门学习/图/test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_height), true);//参数一:保存地址     参数二:获取图片的格式(编码方式)        参数三:图片是帧数        参数四:视频宽高     参数五:与原来颜色保持一致//等全部运行完再去查看视频是否保存成功Mat frame;while (true) {capture.read(frame);//flip(frame, frame, 1);            // 1 左右翻转 y对称 (镜像)if (frame.empty())  //如果读入失败{break; //若视频为空,则跳出操作}imshow("frame", frame);          //显示视频colorSpace_Demo(frame);           //对视频调用之前的demowriter.write(frame);int c = waitKey(1);          //等待10ms(1s = 1000ms),做视频处理都是1if (c == 27) {    //按 esc 退出应用程序break;}}//releasewriter.release();capture.release();  //释放相机的资源
}

024.图像直方图

void histogram_demo(Mat& image);

void QuickDemo::histogram_demo(Mat& image) {//三通道分离vector<Mat> bgr_plane;split(image, bgr_plane);//定义参数变量const int channels[1] = { 0 };const int bins[1] = { 256 };  //总共 256 个灰度级别float hranges[2] = { 0,255 };    //每个通道的取值范围是 0 到 255const float* ranges[1] = { hranges };Mat b_hist;Mat g_hist;Mat r_hist;//计算 Blue,Green,Red 通道的直方图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);//参数一:要计算直方图的数据                   参数二:1表示只有一张图(输入图像的格式)//参数三:需要统计直方图的第几个通道          参数四:掩模,mask必须是8位的数组且和参数一的大小一致//参数五:b_hist表示直方图的输出              参数六:1表示维度是一维的(输出直方图的维度dims)//参数七:直方图中每个维度需分成的区间个数     参数八:ranges表示直方图的取值范围(区间)//显示直方图int hist_w = 512;                                        //设置 画布宽度 为512int hist_h = 400;                                        //设置 画布高度 为400int bin_w = cvRound((double)hist_w / bins[0]);           //每个 bin 占的宽度//cvRound()四舍五入返回数值Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);   //创建画布//归一化直方图数据(归一化到大小一致的范围内)normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());   //histImage.rows是为了不超出画布许可的高度范围normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());//参数一:要进行归一化的图片 参数二:归一化后要输出的图片//参数三:alpha                 参数四:beta         参数五:归一化方法//绘制直方图曲线for (int i = 1; i < bins[0]; i++) {      //每个bin占2个像素的位置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, 3, 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, 3, 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, 3, 0);//从前一个位置到当前位置连上一条线}//显示直方图namedWindow("Histogram Demo", WINDOW_AUTOSIZE);imshow("Histogram Demo", histImage);
}

025.二维直方图

void histogram_2d_demo(Mat& image);

void QuickDemo::histogram_2d_demo(Mat& image) {//2D直方图Mat hsv, hs_hist;cvtColor(image, hsv, COLOR_BGR2HSV);  //先把RGB色彩空间转换到hsv的空间中int hbins = 30, sbins = 32;int hist_bins[] = { hbins, sbins };      //h和s这两个维度需分成的 区间个数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(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);//参数一:要计算直方图的数据                 参数二:1表示只有一张图(输入图像的格式)//参数三:需要统计直方图的第几个通道(前两个) 参数四:掩模,mask必须是8位的数组且和参数一的大小一致//参数五:b_hist表示直方图的输出              参数六:2表示维度是二维的(输出直方图的维度dims)//参数七:直方图中每个维度需分成的区间个数     参数八:hs_ranges表示直方图的取值范围(区间)//参数九:是否对得到的直方图进行归一化处理     参数十:在多个图像时,是否累计计算像素值的个数double maxVal = 0;minMaxLoc(hs_hist, 0, &maxVal, 0, 0);   //寻找最大值和最小值及其位置(这里先找到最大值)//参数一:输入单通道的数组        //参数二:返回最小值的指针           参数三:返回最大值的指针//参数四:返回最小值位置的指针      参数五:返回最大值位置的指针int scale = 10;Mat hist2d_image = 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, COLORMAP_JET);  //产生伪色彩图像namedWindow("H-S Histogram", WINDOW_AUTOSIZE);imshow("H-S Histogram", hist2d_image);//imwrite("F:/文件夹/C++/OPENCV4入门学习/图/hist_2d.png", hist2d_image);
}

026.直方图均衡化

void histogram_eq_demo(Mat& image);

直方图均衡化是通过调整图像的灰阶分布,使得在0~255灰阶上的分布更加均衡,提高了图像的对比度,达到改善图像主观视觉效果的目的。对比度较低的图像适合使用直方图均衡化方法来增强图像细节。

void QuickDemo::histogram_eq_demo(Mat& image) {//直方图均衡化 (目的是对比度拉伸,即 对比度会更强)//用途:用于图像增强,人脸检测,卫星遥感(提升图像质量)。//opencv中,均衡化的图像只支持单通道Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);imshow("灰度图像", gray);Mat dst;equalizeHist(gray, dst);imshow("直方图均衡化演示", dst);
}

对三通道的图像进行直方图均衡化:

    Mat image;Mat imageRGB[3];split(image, imageRGB);for (int i = 0; i < 3; i++){equalizeHist(imageRGB[i], imageRGB[i]);}merge(imageRGB, 3, image);imshow("直方图均衡化图像增强效果", image);

027.图像卷积操作(会变模糊,且卷积核尺寸越大则越模糊

void blur_demo(Mat& image);

void QuickDemo::blur_demo(Mat& image) {  //会变模糊,且卷积核尺寸越大则越模糊Mat dst;blur(image, dst, Size(15, 15), Point(-1, -1));    //均值滤波 均值模糊//参数三:卷积核的大小      参数四:卷积的起始点(Point(-1, -1)则默认取核的中心)//    参数三中://Size(15, 1) 左右晃动的模糊(只有行的话//Size(1, 15) 上下          (      列imshow("图像卷积操作", dst);
}

028.高斯模糊

void gaussian_blur_demo(Mat& image);

void QuickDemo::gaussian_blur_demo(Mat& image) {//中心值最大,离中心越远值越小Mat dst;GaussianBlur(image, dst, Size(5, 5), 15);//参数三:高斯矩阵的大小(正数且奇数)//参数四:sigmaX 和 sigmaY 为15 //(参数三和四都 值越大则越模糊,且参数四的影响更明显)imshow("高斯模糊", dst);
}

高斯卷积数学表达式说明:

高斯卷积的图像说明:

029.高斯双边模糊(可磨皮操作

(同时考虑空间临近信息与颜色相似信息,在滤除噪声、平滑图像的同时,又做到边缘保存)

(高斯双边模糊:可以在去除噪声的同时,保持边缘信息相对清晰。但是,相比于大多数滤波器,双边滤波的速度是非常慢的。)

void bifilter_demo(Mat& image);

void QuickDemo::bifilter_demo(Mat& image) { //可做磨皮操作Mat dst;bilateralFilter(image, dst, 0, 100, 10);//参数三:色彩空间        参数四:坐标空间 (双边是指 色彩空间 和 坐标空间namedWindow("高斯双边模糊", WINDOW_AUTOSIZE);imshow("高斯双边模糊", dst);
}

030.案例:实时人脸检测

(24条消息) openCV4.0 C++ 实战:人脸检测 学习笔记(自用 代码+注释)_chxin14160的博客-CSDN博客

代码总结

(24条消息) openCV4.0 C++ 快速入门30讲学习笔记(自用 代码+注释)_chxin14160的博客-CSDN博客

openCV4.0 C++ 快速入门30讲学习笔记(自用 代码+注释)详细版相关推荐

  1. openCV4.0 C++ 快速入门30讲学习笔记(自用 代码+注释)

    课程来源:哔哩哔哩 环境:OpenCV4.5.1 + VS2019 目录 一.代码+注释 quickopencv.h quickdemo.cpp 源.cpp 二.相关图片 012.图像色彩空间转换(提 ...

  2. 古月ROS入门21讲学习笔记

    古月ROS入门21讲学习笔记 1.VMware+Ubuntu18.04+ROS安装 2.Linux命令 3.ROS是什么 ROS中的通信机制 ROS的开发工具 ROS的应用功能 ROS中的生态系统 老 ...

  3. 古月居ROS入门21讲学习笔记P9

    古月居ROS入门21讲学习笔记P9 工作空间(workspace) 创建工作空间 创建功能包 实操 创建工作空间 创建功能包 老师在B站的原视频 链接: [古月居]古月·ROS入门21讲 | 一学就会 ...

  4. 0基础快速入门CSS技术栈(4)—图解详细阐述CSS的复合选择器、标签显示模式、行高、CSS背景,及最为重要的CSS三大特性附带权重计算笔试题(附详细案例源码解析过程)

    文章目录 1. 0基础快速入门CSS技术栈(4) 2. 重点提炼 3. CSS复合选择器 3.1 后代选择器(重点) 3.1.1 example01 3.2 子元素选择器 3.2.1 exmaple0 ...

  5. 【个人笔记 - 目录】OpenCV4 C++ 快速入门 30讲

    个人资料,仅供学习使用 修改时间--2022年2月10日 09:51:53 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 笔者对每一节课都做了详细的笔记,在包含了所有视频内容 ...

  6. 如何快速入门Ajax(学习笔记)—— 原生ajax、jQuery、axios

    如何快速入门Ajax 1. 服务器的基本概念 客户端与服务器 URL地址 网页中如何请求数据 资源的请求方式 2. 了解Ajax Ajax是什么 Ajax的应用场景 3. jQuery中的Ajax g ...

  7. 【0基础快速入门】Python学习快速参考手册

    Python学习快速参考手册 目录 文章目录 Python学习快速参考手册 目录 @[toc] 下载 Python下载与配置 IDE下载与配置 第一章 · Python的基本语法 变量 数据类型 注释 ...

  8. 0基础快速入门CSS技术栈(5)—图解详细阐述说透CSS的盒子模型(超级重要)、圆角边框、盒子阴影及相关重要的笔试题——css的核心中的核心(附详细案例源码解析过程)2021.01.07更新

    文章目录 1. 盒子模型(CSS重点) 1.1 看透网页布局的本质 1.2 盒子模型(Box Model) 1.3 盒子边框(border) 1.3.1 边框综合设置 1.3.2 example01 ...

  9. 黑马程序员新版Linux零基础快速入门到精通——学习笔记

    01初识Linux 1.1.操作系统概述 1.1.1.硬件和软件 我们所熟知的计算机是由硬件和软件组成的. 硬件: 计算机系统中由电子.机械和光电元件等组成的各种物理装置的总称. ​ (看的见.摸得着 ...

最新文章

  1. 笔记本x31搭建家用win服务器系统,Thinkpad X31怎么硬盘安装win7系统
  2. 实力封装:Unity打包AssetBundle(二)
  3. sqlyog如何设置.时提示字段名_雷神新用户手册:拿到新电脑时如何简易设置参数!...
  4. python中的PEP是什么?怎么理解?(转)
  5. python如何表示代码块_如何在Python中重复代码块
  6. 本地计算机上的mysql服务怎么注册,本地计算机上的mysql服务启动后中止
  7. oh-my-zsh扫描git仓库卡慢的解决方法
  8. __builtin_apply/__builtin_apply_args
  9. 中国首档程序员综艺:你有freebug吗?
  10. 设置php中字符编码_php如何设置字符编码
  11. windows痛苦面具-C盘瘦身法
  12. 【WORD】01 多级标题自动编号
  13. 【从零开始学架构-李运华】01|架构到底是指什么?
  14. 软件质量因素 6个_影响软件质量管理的主要因素
  15. [转] 大学的终结—1950年代初期的“院系调整”
  16. 软件架构设计---产品线及系统演化
  17. matlab中的帮助命令
  18. linux下查看系统内存使用情况的几个命令
  19. 计算机的it入门知识点,基础乐理知识点电脑基础知识IT计算机专业资料-基础乐理知识点(5页)-原创力文档...
  20. 第十一章无线渗透 理论篇

热门文章

  1. 航班信息的查询与检索Java,航班信息查询与检索
  2. 2021高考浙江成绩查询阳光高考,浙江教育考试院
  3. 互联网公司校招Java面试题总结及答案——微店、去哪儿、蘑菇街
  4. 天然气阶梯是按年还是按月_燃气阶梯是一年一清吗
  5. python实现图形旋转_python实现旋转和水平翻转的方法
  6. android edittext字数显示不全,Android的EditText字数检测和限制解决办法
  7. 邀请函 | 2021 ISIG中国产业智能大会,产业数字智能化的年度最大盛会!
  8. python log壁纸_一个爬取Bing每日壁纸的python脚本
  9. 异步就是异步,根本就没有 异步非阻塞IO这个说法。阻塞 非阻塞,同步I/O 异步I/O 的区别
  10. cpu锁频(cpu锁频软件)