实践教程 | 万字长文,值得收藏/参考的OpenCV C++基础代码

news/2024/10/29 7:18:09/

点击上方“3D视觉工坊”,选择“星标”

干货第一时间送达

作者丨卡拉肖克-X

来源丨OpenCV学堂

编辑丨极市平台

导读

 

一位友好人士做的B站OpenCV4.x C++ 快速入门30讲视频课程的笔记总结!

01 环境搭建

环境配置了一个早上,到10.48分配置完毕,有点难受。还好最后显示出第一张图片。

#include<opencv2/opencv.hpp>
#include<iostream>usingnamespacestd;
usingnamespace cv;
int main() 
{Mat src = imread("D:/images/011.jpg",IMREAD_GRAYSCALE);//读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。if (src.empty()) {printf("could not load image");//如果图片不存在 将无法读取,打印到终端。}//超过屏幕的图像无法显示时候调用此函数。namedWindow("输入窗口", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例imshow("输入窗口", src);//表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位msdestroyAllWindows();//销毁前面创建的显示窗口return0;
}

第一节课介绍了如何读取第一张图片,并且显示出来,通过调用imread函数读取照片,再调用imshow显示图片到窗口。同时,讲述了如何打印灰度图像,图片读取失败的处理方式,代码注释详细介绍了每条语句的意思。

02 显示图象

1、色彩空间转换函数 cvtColor
2、图像的保存

#include<opencv2/opencv.hpp>
using namespace cv;class QuickDemo //创建一个QuickDemo对象
{public:void colorSpace_Demo(Mat &imge); //定义一个类,里面包含输入一个图片,对图片操作
};#include<quickopencv.h>
void QuickDemo::colorSpace_Demo(Mat &image)
{Mat gray, hsv;//定义2个矩阵类的图像gray和hsv,cvtColor(image,hsv,COLOR_BGR2HSV);//图像转换函数,可以把image转成hsv,第三个参数是转成的类型cvtColor(image,gray,COLOR_BGR2GRAY);//图像转换函数,可以把image转成hsv,第三个参数是转成的类型imshow("HSV",hsv);imshow("灰度",gray);imwrite("D:/hsv.jpg",hsv);//保存图片,前面是保存图的地址,后面是保存图的名称imwrite("D:/gray.jpg",gray);
}#include<opencv2/opencv.hpp>
#include<iostream>
#include<quickopencv.h>using namespace std;
using namespace cv;
int main() 
{Mat src = imread("D:/images/1.jpg",IMREAD_ANYCOLOR);//B,G,R实际上0-255三色。3通道//读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。if (src.empty()) {printf("could not load image");//如果图片不存在 将无法读取,打印到终端。return-1;}//超过屏幕的图像无法显示时候调用此函数。namedWindow("输入窗口", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例imshow("输入窗口", src);//表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat 
//在主函数中调用之前创建的类对象    QuickDemo qd;qd.colorSpace_Demo(src);waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位msdestroyAllWindows();//销毁前面创建的显示窗口return0;
}

这节主要介绍了创建一个类对象,然后通过类对象调用函数,在main主函数中进行调用实现类对象中的功能,比如转换成HSV类型图片和GRAY类型图片,最后通过imwrite函数进行图像的保存。

03 图像对象的创建与赋值

1、怎么操作mat
2、怎么访问每一个像素点
3、怎么创建一个空图或者mat

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*8的CV8位的无符号的n通道的unsigned char//ones&zeros是初始化的方法m3 = Scalar(255, 0, 0);//给三个通道都赋值127  ,单通道赋值方法 m3 = 127;//m3初始为蓝色//数据的宽度和长度是由通道数决定的。//std::cout << "width:"<<m3.cols<<"height"<< m3.rows <<"channels"<<m3.channels()<< std::endl;//用来查看宽度,高度与通道数。/*std::cout << m3 << std::endl;*/Mat m4 = m3.clone();//赋值M4就是M3 M4改变了,M3也改变了,没有产生新的自我(M4与M3同体)//M4为M3的克隆,M3还是原来的颜色,不会改变。(M4与M3不同体,各自是各自的颜色)//m3.copyTo(m4);//把M3赋值给M4,M4就是蓝色m4 = Scalar(0, 255, 255);//改变m4的颜色为黄色 ,m4也改变imshow("图像3", m3);//标题和图像名称   显示图像m3 纯蓝色imshow("图像4", m4);//标题和图像名称
}

本节课介绍了如何创建一个Mat对象,通过创建新的Mat对象来创建用户的特定的底色画布,创建图像的基本类型有两种一种是ones一种是zeros,ones()中的第一个参数代表图像的大小,第二个参数代表创建几维的图像,UC代表无符号字符型,数组3代表通道数。克隆和赋值的区别,克隆就是产生一个新的对象,新对象改变属性,旧对象属性不变(各自为政)。赋值是二者同体,当新属性发生改变,旧属性也发生改变(二者同体)。

04 图像像素的读写操作

如何遍历和修改每个像素点的数值,分为单通道和多通道。访问模式模式也有两种。第一种是数组访问模式,用最常规的数组下标访问像素值。

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];//对彩色图像读取它的像素值,并且对像素值进行改写。}}}namedWindow("像素读写演示", WINDOW_FREERATIO);imshow("像素读写演示", 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++){uchar *current_row = image.ptr<uchar>(row);for (int col = 0; col < w; col++){if (dims == 1) //单通道的灰度图像{int pv = *current_row;//得到像素值*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);}

本节主要介绍了通过两种遍历的方式访问图像的像素值,并且改变图像的像素值。

05 图像像素的操作

对图像的各个像素点实现加减乘除的操作。介绍了常用的除爆函数saturate_cast,防止数值过界。

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);//除法操作 apinamedWindow("加法操作", WINDOW_FREERATIO);imshow("加法操作", 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]);//saturate_cast用来防爆,小于0就是0,大于255就是255dst.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]);//对彩色图像读取它的像素值,并且对像素值进行改写。}}imshow("加法操作", dst);
}

介绍了四种不同的API实现,并且演示了一种加法的算法。

06 滚动条演示操作-调整图片亮度

本节介绍怎么通过createTrackbar来设置一个进度条,实现图片的亮度调节。

Mat  src, dst, m;
int lightness = 50;//定义初始的亮度为50
static void on_track(int ,void*) 
{m = Scalar(lightness,lightness,lightness);//创建调整亮度的数值subtract(src, m, dst);//定义亮度变化为减imshow("亮度调整", dst);//显示调整亮度之后的图片
}
void QuickDemo::tracking_bar_demo(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);
}

07 滚动条演示操作-传递参数

无类型指针类型转换与参数传递!

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);//融合两张图imshow("亮度&对比度调整", 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_demo(Mat &image)
{namedWindow("亮度&对比度调整",WINDOW_AUTOSIZE);int lightness = 50;int max_value = 100;int 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);
}

08 键盘响应操作

本节介绍通过键盘输入,终端能够读取响应的信息。

void QuickDemo::key_demo(Mat &image) 
{Mat dst= Mat::zeros(image.size(), image.type());while (true) {char c = waitKey(100);//停顿100ms 做视频处理都是1if (c == 27) { //esc 退出应用程序break;}if (c == 49)//key#1{std::cout <<"you enter key #1" << std::endl;cvtColor(image, dst, COLOR_BGR2GRAY);}if (c == 50)//key#1{std::cout << "you enter key #2"  << std::endl;cvtColor(image, dst, COLOR_BGR2HSV);}if (c == 51)//key#1{std::cout << "you enter key #3" << std::endl;dst = Scalar(50, 50, 50);add(image,dst,dst);}imshow("键盘响应",dst);std::cout << c << std::endl;}
}

通过键盘输入,在终端得到响应,输入不同的键值,得到不一样的结果。

09 opencv自带颜色操作

void QuickDemo::color_style_demo(Mat &image) 
{int colormap[] = {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;while (true) {char c = waitKey(100);//停顿100ms 做视频处理都是1if (c == 27) { //esc 退出应用程序break;}if (c == 49)//key#1 按下按键1时,保存图片到指定位置{std::cout << "you enter key #1" << std::endl;imwrite("D:/gray.jpg", dst);}applyColorMap(image, dst, colormap[index%19]);//循环展示19种图片index++;imshow("循环播放", dst);}
}

伪色彩填充与颜色表匹配

10 图像像素的逻辑操作

本节介绍如何对图像的像素进行操作,包括与、或、非、异或,矩形在图像中的绘制。

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);//小于0表示填充,大于0表示绘制rectangle(m2,Rect(150,150,80,80), Scalar(0,255,255), -1, LINE_8, 0);imshow("m1", m1);imshow("m2", m2);Mat dst;bitwise_and(m1, m2, dst);//位操作与bitwise_or(m1, m2, dst);//位操作或bitwise_not(image, dst);//取反操作bitwise_xor(m1, m2, dst);//异或操作imshow("像素位操作", dst);
}
rectangle(m1,Rect(100,100,80,80),Scalar(255,255,0),-1,LINE_8,0);

这个函数参数1是图片名称,参数2是矩形的起始&末尾位置,参数3 Scalar表示将要绘制图像的颜色,参数4表示小于0表示填充,大于0表示绘制,参数5表示四邻域或者八邻域的绘制,参数6表示中心坐标或者半径坐标的小数位数。

11 通道的分离与合并

本节介绍如何把不同的通道给分离,归并,使得能显现出来不同的通道颜色。

void QuickDemo::channels_demo(Mat &image)
{    std::vector<Mat>mv;split(image, mv);//imshow("蓝色", mv[0]);//0,1,2三个通道分别代表BGR。//关闭2个通道意味着开启一个通道。//imshow("绿色", mv[1]);//imshow("红色", mv[2]);Mat dst;mv[0] = 0;mv[2] = 0;merge(mv, dst);imshow("蓝色", dst);int from_to[] = { 0,2,1,1,2,0 };//把通道相互交换,第0->第2,第一->第一,第二->第0mixChannels(&image,1,&dst,1,from_to,3);//3表示3个通道//参数1指针引用图像->参数2引用到dstimshow("通道混合", dst);
}

M[0],M[1],M[2]分别代表BGR个不同的通道。要开启某个通道只需要关闭另外的一个通道即可。第二个内容为通道的合并,将不同通道的像素值进行转换操作,使图片呈现出不同的效果。

12 图像色彩空间转换

本节内容实现任务是提取任务的轮廓,首先把RGB色彩空间的图片转换到HSV空间中,其次,提取图片的mask,通过使用inrangle提取hsv色彩空间的颜色。HSV色彩空间的颜色

void QuickDemo::inrange_demo(Mat &image)
{Mat hsv;cvtColor(image, hsv, COLOR_BGR2HSV);Mat mask;inRange(hsv,Scalar(35,43,46),Scalar(77,255,255),mask);//35,43,46根据图片中绿色最低来确定最小值。//77,255,255 提取//参数1低范围,参数2高范围//将hsv中的由低到高的像素点提取出来并且存储到mask当中。imshow("mask",hsv);Mat redback = Mat::zeros(image.size(), image.type());redback = Scalar(40, 40, 200);bitwise_not(mask, mask);imshow("mask", mask);image.copyTo(redback, mask);//把redback复制到mask,mask通过inRange得到。imshow("roi提取", hsv);
}

13 图像像素值统计

分别定义双精度型变量 minv和maxv。指针变量minLoc,maxLoc;因为这图片是多通道的,所以使用一个容器装取数值,并且用split分离图片到MV中通过for循环操作,遍历图片信息,并且打印信息到终端。图像信息包括,方差,均值,大小。

void QuickDemo::pixel_statistic_demo(Mat &image)
{double minv, maxv;//定义最值Point minLoc, maxLoc;//定义最值地址std::vector<Mat>mv;//mv是一个Mat类型的容器 装在这个容器内split(image, mv);for (int i = 0; i < mv.size(); i++) {//分别打印各个通道的数值minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());//求出图像的最大值和最小值。std::cout <<"No.channels:"<<i<<"minvalue:" << minv << "maxvalue:" << maxv << std::endl;}Mat mean, stddev;meanStdDev(image, mean, stddev);//求出图像的均值和方差std::cout << "mean:" << mean << std::endl;std::cout << "stddev:" << stddev << std::endl;
}

14 图像几何形状的绘制

本节课介绍如何绘制椭圆,矩形,直线,圆等

void QuickDemo::drawing_demo(Mat &image)
{Rect rect;rect.x = 200;rect.y = 200;rect.width = 100;rect.height = 100;Mat bg = Mat::zeros(image.size(),image.type());rectangle(image, rect, Scalar(0, 0, 255), -1, 8, 0);//参数1为绘图的底图或者画布名称,参数2位图片的起始,宽度,高度//参数3代表填充颜色。参数4大于0是线小于0是填充//参数5表示邻域填充,参数6默认值为0circle(bg, Point(350, 400), 15, Scalar(0, 0, 255), 2, LINE_AA, 0);//参数2位图片中心位置,参数3为半径为15的圆Mat dst;//addWeighted(image, 0.7, bg, 0.3, 0, dst);RotatedRect rtt;rtt.center = Point(200, 200);rtt.size = Size(100, 200);rtt.angle = 0.0;line(bg,Point(100,100),Point(350,400), Scalar(0, 0, 255), 8, LINE_AA, 0);//line_AA表示去掉锯齿ellipse(bg,rtt, Scalar(0, 0, 255), 2, 8);imshow("矩形的绘制",bg);
}

15 随机数与随机颜色

本节主要介绍如何能产生一个随机数字和随机颜色,并且用线条的方式显示出来。

void QuickDemo::random_drawing()
{Mat canvas = Mat::zeros(Size(512,512), CV_8UC3);int w = canvas.cols;int h = canvas.rows;RNG rng(12345);while (true) {int c = waitKey(10);if (c == 27) {break;}int x1 = rng.uniform(0,canvas.cols);int y1 = rng.uniform(0, h);int x2 = rng.uniform(0, canvas.cols);int y2 = rng.uniform(0, h);int b  = rng.uniform(0, 255);int g  = rng.uniform(0, 255);int r  = rng.uniform(0, 255);canvas = Scalar(0,0,0);line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b,g,r), 8, LINE_AA,0);//line_AA表示去掉锯齿 imshow("随机绘制演示", canvas);}
}

16 多边形填充与绘制

这节课介绍了2种多边形绘制的实现方式。

void QuickDemo::polyline_drawing_demo(Mat &image)
{Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);Point p1(100, 100);Point p2(350, 100);Point p3(450, 280);Point p4(320, 450);Point p5(80, 400);std::vector<Point>pts;//将5个点装入一个容器内。pts.push_back(p1);//未初始化数组容量,只能用pushback操作//如果初始化,可以用数组下标操作。pts.push_back(p2);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(0, 0, 255), 2, 8, 0);//绘制多边形/*参数1表示画布,参数2表示点集,参数3表示true,参数4颜色参数5表示线宽,参数6表示渲染方式,参数7表示相对左上角(0,0)的位置*///单个API搞定图片的绘制填充std::vector<std::vector<Point>>contours;contours.push_back(pts);drawContours(canvas,contours,-1, Scalar(0, 0, 255),-1);//参数2表示容器名称,参数3为正表示多边形的绘制,为负表示多边形的填充imshow("多边形绘制", canvas);
}

第一种方式,通过标记各个点,然后存储到容器中,之后对容器中的点进行操作。填充多边形调用fillPoly,绘制多边形调用polylines。第二种方式,使用一个API接口绘制。通过一个容器中的存储的点组成的另一个容器。

17 鼠标操作与响应

鼠标事件响应与绘制!考察基本的图形绘制编程能力。

//参数1表示鼠标事件。
Point sp(-1, -1);//鼠标的开始的位置
Point ep(-1, -1);
Mat temp;
static void on_draw(int event,int x,int y,int flags,void *userdata)
{Mat image = *((Mat*)userdata);if(event == EVENT_LBUTTONDOWN)//如果鼠标的左键按下{sp.x = x;sp.y = y;std::cout << "start point" <<sp<< std::endl;}elseif (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;//复位,为下一次做准备}}elseif (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));//设置窗口的回调函数。参数1表示名称,参数2表示调用on_drawimshow("鼠标绘制", image);temp = image.clone();
}

18 图像像素类型的转换与归一化

像素值归一化是很常见的预处理方式,OpenCV支持字节与浮点数的图象显示。

void QuickDemo::norm_demo(Mat &image)
{Mat dst;//定义一个名为dst的二值化类型的数据std::cout << image.type() << std::endl;//打印出来图片的类型image.convertTo(image,CV_32F);//将dst数据转换成浮点型float32位数据。std::cout << image.type() << std::endl;//再次打印转换后的数据类型normalize(image, dst, 1.0, 0, NORM_MINMAX);//进行归一化操作std::cout << dst.type() << std::endl;//打印归一化操作之后的数据imshow("图像的归一化", dst);//显示归一化的图像//CV_8UC3 ,CV_32FC3  //3通道每个通道8位的UC类型//转换后 3通道 每个通道32位的浮点数
}

19 图像的放缩与插值

介绍基本的图像变换大小的方法。图像的差值处理主要有线性、双线性差值、卢卡斯差值、双立方差值。

void QuickDemo::resize_demo(Mat &image)
{Mat zoomin, zoomout;int h = image.rows;int w = image.cols;resize(image, zoomin, Size(w/2, h/2),0,0,INTER_LINEAR);//线性差值操作。imshow("zoomin", zoomin);; resize(image, zoomout, Size(w*1.5, h*1.5), 0, 0, INTER_LINEAR);imshow("zoomin", zoomout);//
}

20 图像的翻转

图像的上下、左右、对角线翻转

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

21 图像的旋转

图像旋转的基本原理,变换矩阵M的计算,中心位置偏移计算等。

void QuickDemo::rotate_demo(Mat &image)
{Mat dst, M;int h = image.rows;//定义图片的高度int w = image.cols;//定义图片的宽度M = getRotationMatrix2D(Point(w / 2, h / 2),45,1.0);doublecos = abs(M.at<double>(0, 0));doublesin = 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);//参数1原来图像的中心位置。参数2角度是多少。参数3是图像本身大小的放大缩小warpAffine(image, dst, M,Size(nw,nh),INTER_LINEAR,0, Scalar(0, 0, 255));imshow("旋转演示", dst);
}

22 视频文件摄像头使用

本节介绍了如何读取一个视频,以及调用电脑的摄像头。并且对读取到的视频进行操作。

void QuickDemo::video_demo(Mat &image) 
{VideoCapture capture("D:/images/123.mp4");  //读取视频的地址Mat frame;//定义一个二值化的 framewhile (true){capture.read(frame); //读取视频//flip(frame, frame, 1);//图像镜像操作if(frame.empty())//如果视频为空的话 跳出操作{break;}imshow("frame", frame);//显示视频colorSpace_Demo(frame);//对视频调用之前的demoint c = waitKey(100);//停顿100ms 做视频处理都是1if (c == 27) { //esc 退出应用程序break;}}capture.release();//释放相机的资源
}

对读取到的视频 操作方式有镜像对称。加各种滤镜等等。

23 视频处理与保存

视频的属性,SD(标清),HD(高清),UHD(超清),蓝光。如何读取视频文件,以及读取视频文件的属性,衡量视频处理指标:FPS。保存视频时的编码格式。保存视频的实际size和create的size大小保持一致。

void QuickDemo::video_demo(Mat &image) 
{VideoCapture capture("D:/images/123.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);std::cout << "frame width" << frame_width << std::endl;std::cout << "frame height" << frame_height << std::endl;std::cout << "frame FPS" << fps << std::endl;std::cout << "frame count" << count << std::endl;VideoWriter writer("D:/test.mp4",capture.get(CAP_PROP_FOURCC),fps,Size(frame_width, frame_height),true);//参数1 保存地址。参数2 获取图片的格式 参数3 图片的帧数 参数4 视频宽高 参数5 真Mat frame;while (true){capture.read(frame);//flip(frame, frame, 1);//图像镜像操作if(frame.empty()){break;}imshow("frame", frame);colorSpace_Demo(frame);writer.write(frame);int c = waitKey(100);//停顿100ms 做视频处理都是1if (c == 27) { //esc 退出应用程序break;}}capture.release();//释放相机的资源writer.release();//释放存放的资源
}

本节课,介绍了视频的一些基本熟悉,紧接介绍如何获取视频的属性,并且通过特定的格式保存到相应的存储位置上。

24 图像的直方图

直方图是图像的统计学特征。表示了图像的各个像素在0-255出现的频率。图像的平移旋转都不会对性质进行改变。缺点:不能表征一张图像。

25 直方图的均衡化

用途:用于图像增强,人脸检测,卫星遥感。均衡化的图像只支持单通道。

void QuickDemo::histogram_eq_demo(Mat &image)
{Mat gray;cvtColor(image, gray, COLOR_BGR2GRAY);//直方图均衡化只支持灰度图像,不支持彩色图像。imshow("灰度图像", gray);Mat dst;equalizeHist(gray, dst);imshow("直方图均衡化", dst);
}

26 图像的卷积操作

卷积的作用,高的往下降,低的往上升。但是会造成信息丢失。产生模糊效果。是一种线性操作,点乘,之后相加。

void QuickDemo::blur_demo(Mat &image)
{Mat dst;blur(image, dst, Size(15, 15), Point(-1, -1));//参数1原始图像,参数2卷积之后的图像,参数3卷积的矩阵大小,支持单行或者单列的卷积操作,参数4卷积的起始点。imshow("图像卷积操作", dst);
}

27 高斯模糊

中心的数值最大,离中心距离越远,数值越小。高斯卷积数学表达式说明:

void QuickDemo::gaussian_blur_demo(Mat &image)
{Mat dst;GaussianBlur(image, dst, Size(5, 5), 15);imshow("高斯模糊", dst);//参数1表示初始图像,参数2表示处理后的图像,参数3表示高斯矩阵大小 正数而且是奇数,//参数4表示西格玛x为15 西格玛y为15 
}

28 高斯双边模糊

边缘保留的滤波算法!去噪!

void QuickDemo::bifilter_demo(Mat &image)
{Mat dst;bilateralFilter(image,dst,0,100,0);//参数1代表原图,参数2代表处理之后的图像,参数3色彩空间。参数4表示坐标空间,双边是指 色彩空间和坐标空间。namedWindow("双边模糊", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例imshow("双边模糊", dst);//表示显示在新创建的
}

29 实时视频人脸检测

OpenCV4.x中基于深度神经网络模型的高实时,稳定的人脸检测演示。

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;}Mat blob = dnn::blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false);net.setInput(blob);// NCHWMat probs = net.forward(); // Mat detectionMat(probs.size[2], probs.size[3], CV_32F, probs.ptr<float>());// 解析结果for (int i = 0; i < detectionMat.rows; i++) {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);int c = waitKey(1);if (c == 27) { // 退出break;}
}

本文仅做学术分享,如有侵权,请联系删文。

下载1

在「3D视觉工坊」公众号后台回复:3D视觉即可下载 3D视觉相关资料干货,涉及相机标定、三维重建、立体视觉、SLAM、深度学习、点云后处理、多视图几何等方向。

下载2

在「3D视觉工坊」公众号后台回复:3D视觉github资源汇总即可下载包括结构光、标定源码、缺陷检测源码、深度估计与深度补全源码、点云处理相关源码、立体匹配源码、单目、双目3D检测、基于点云的3D检测、6D姿态估计源码汇总等。

下载3

在「3D视觉工坊」公众号后台回复:相机标定即可下载独家相机标定学习课件与视频网址;后台回复:立体匹配即可下载独家立体匹配学习课件与视频网址。

重磅!3DCVer-学术论文写作投稿 交流群已成立

扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。

同时也可申请加入我们的细分方向交流群,目前主要有3D视觉CV&深度学习SLAM三维重建点云后处理自动驾驶、多传感器融合、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、求职交流、ORB-SLAM系列源码交流、深度估计等微信群。

一定要备注:研究方向+学校/公司+昵称,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,可快速被通过且邀请进群。原创投稿也请联系。

▲长按加微信群或投稿

▲长按关注公众号

3D视觉从入门到精通知识星球:针对3D视觉领域的视频课程(三维重建系列、三维点云系列、结构光系列、手眼标定、相机标定、orb-slam3等视频课程)、知识点汇总、入门进阶学习路线、最新paper分享、疑问解答五个方面进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业为一体的铁杆粉丝聚集区,近2000星球成员为创造更好的AI世界共同进步,知识星球入口:

学习3D视觉核心技术,扫描查看介绍,3天内无条件退款

 圈里有高质量教程资料、可答疑解惑、助你高效解决问题

觉得有用,麻烦给个赞和在看~  


http://www.ppmy.cn/news/786646.html

相关文章

Halcon转OpenCV实例--去除纸张中的颜色笔迹/墨迹(附源码)

导读 本文主要介绍一个去除纸张中颜色笔迹/墨迹的实例&#xff0c;并将Halcon实现转为OpenCV。 实例来源 实例来源于51Halcon论坛的讨论贴&#xff1a; https://www.51halcon.com/forum.php?modviewthread&tid4766 Halcon实现 参考回帖内容&#xff0c;将代码整理如下…

JVM知识要点脑图

说明&#xff1a; 该脑图为JVM相关知识要点统计&#xff1b;该脑图仅串联知识点&#xff0c;复习时通过该要点详细扩展&#xff0c;越详细越好&#xff1b;具体详情&#xff0c;还是参考之前做的对应部分笔记&#xff1b;

Webgis 打印实现技术细节

Webgis 打印实现技术细节 ——兼论如何实现打印预览 褫其华衮&#xff0c;示人本相系列之三 cheungmine 在我的上一篇文章《 Webgis 打印实现原理——褫其华衮&#xff0c;示人本相系列之二》&#xff08;见&#xff1a;http://blog.csdn.net/cheungmine/archive/2006/09/18/1…

C# + Ext.Net打印

近期做了一套打印的功能&#xff0c;主要实现模板套打。因为模板中每个信息项的位置和尺寸都是固定的&#xff0c;所有有些不定长的文本就需要使用图片来实现等比例缩放 我的技术解决方案就是&#xff1a; 根据要求的文本信息得出需要的画布大小&#xff0c;在根据模板区域的大…

书法字帖 PDF转化为可打印PDF

书法类的PDF&#xff0c;因为底色是黑色的&#xff0c;打印起来特别费墨&#xff0c;所以需要转化成白底黑字的文件&#xff0c; 才好打印。 1&#xff09;用 pdfbox 的 ExtractImages 命令&#xff0c;抽出所有的图片 https://pdfbox.apache.org/2.0/commandline.html java -j…

使用OpenCV自动去除背景色

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶” 重磅干货&#xff0c;第一时间送达 几天前&#xff0c;我遇到了一个项目&#xff0c;要求将草图放到某个文件夹中时删除草图的白色背景。这都是在硬件扫描仪中发生的。 下面是一个草图示例&#xff1a; 第…

从零开始开发Python程序(五)—— 把文字排版成一张图片

承接上文&#xff0c;我们写了一个爬虫小程序&#xff0c;从网上抓取新闻信息&#xff1a;从零开始开发Python程序&#xff08;四&#xff09;—— 抓取每日早报新闻 目录 一、引入图片编辑库 二、用程序画一张图 三、新闻的内容文本处理 四、将新闻文本添加到图片中 ​ 一…

1.基于S5PV210的图片解码播放器(详解)

有道云笔记详细地址&#xff1a; 文档&#xff1a;图片解码播放器小项目&#xff08;详解&#xff09;.note 链接&#xff1a;http://note.youdao.com/noteshare?id9f9a43ac5ec6828cf467940dfa10da51&subA8280EB4B5A146C9A1F6612031305071 文章目录 一、开始动手写代码1、…