基于C++ OpenCV的图像处理-基础篇
目录
一、图像处理基础篇
1.1创建和显示窗口
1.1.1常用API
1.1.2读图片并显示
1.1.3获取视频并显示
1.1.4视频读取与播放
1.1.5视频录制
1.1.6鼠标事件
1.1.7滑动条控件
1.2 OpenCV必备核心知识
1.2.1 色彩空间的转换
1.2.2数据结构Mat
1.2.2.1定义
1.2.2.2 属性
1.2.2.3拷贝
1.2.2.4对象的属性:行数、列数及通道数
1.2.2.5通道的分离
1.2.2.6通道的合并
1.2.2.7指针访问像素
1.3 绘制基本图像
1.3.1绘制直线
1.3.2绘制矩形
1.3.3绘制圆形
1.3.4绘制椭圆
1.3.5绘制多边形
1.3.6 多边形填充
1.3.7绘制文本
1.3.8绘制图形的综合应用实战
1.4 图像的运算
1.4.1加法运算
1.4.2图像的减法
1.4.3乘法运算
1.4.4除法运算
1.4.5图像的融合
1.4.6图像的逻辑运算:与或非
1.4.7图像运算的应用实战
1.5图像的基本变换
1.5.1图像的缩放
1.5.2图像的翻转
1.5.3图像的旋转
1.5.4图像的仿射变换
1.5.4.1仿射变化矩阵求解:矩阵法
1.5.4.2仿射变换矩阵求解:三点法
1.5.5透视变换
1.6图形的滤波(卷积)
1.6.1滤波器分类
1.6.2低通滤波
1.6.2.1方盒滤波及均值滤波
1.6.2.2高斯滤波(中心滤波)
1.6.2.3中值滤波
1.6.2.4双边滤波(适合于美颜)
1.6.3高通滤波
1.6.3.1Sobel(索贝尔)(高斯)滤波
1.6.3.2Scharr算子滤波
1.6.3.3拉普拉斯算子滤波
1.6.4边缘检测Canny
1.7图形形态学
1.7.1图形的二值化
1.7.2腐蚀
1.7.3膨胀
1.7.4开&闭运算
1.7.5形态学梯度
1.7.6顶帽运算
1.7.7黑帽运算
1.8轮廓与矩形
1.8.1查找轮廓
1.8.2绘制轮廓
1.8.3轮廓的面积
1.8.4轮廓的周长
1.8.5多边形逼近与凸包
1.8.6外接多边形
1.9车辆统计项目实战
1.9.1视频去背景
1.9.2相关代码部分
二、特征检测与分割
2.1特征点检测
2.1.1哈里斯焦点检测
2.1.2Shi-Tomasi角点检测
2.2图像的分割
2.2.1分水岭法
2.2.2GrabCut法
2.3距离变换
2.4连通域
一、图像处理基础篇
1.1创建和显示窗口
1.1.1常用API
API定义:namedWindow(const String &winname,int flags); 显示窗口:imshow(); 销毁窗口:destroyAllWindows(); 窗口大小:resizeWindow();
1.1.2读图片并显示
Mat mImage=imread("C:/Users/xtf_a/Desktop/QTLearn/OpenCVLearn/01/pear.jpg"); namedWindow("图片",WINDOW_NORMAL); imshow("图片",mImage); int iKey=waitKey(0); destroyAllWindows();
1.1.3获取视频并显示
//打开摄像头常用的API: //open()—打开视频文件或者摄像头; //isOpen()—判断读取视频文件是否正确,正确返回true; //release()—关闭视频流文件; //Grab() VideoCapture cap(0); //打开摄像头,0表示摄像头地址 Mat mImage1; cap.set(CAP_PROP_FRAME_WIDTH, 1920); //设置摄像头的像素 cap.set(CAP_PROP_FRAME_HEIGHT, 1080); while(true){ cap.read(mImage1); imshow("video",mImage1); int ikey=waitKey(5); if(ikey==13){ //13表示回车键,按下回车键退出 break; } } cap.release(); destroyAllWindows();
1.1.4视频读取与播放
VideoCapture cap("C:/Users/xtf_a/Desktop/QTLearn/OpenCVLearn/01/video.mp4"); Mat mImage1; cap.set(CAP_PROP_FRAME_WIDTH, 1920); cap.set(CAP_PROP_FRAME_HEIGHT, 1080); while(true){ cap.read(mImage1); mshow("video",mImage1); int ikey=waitKey(50); if(ikey==13){ break; } } cap.release(); destroyAllWindows(); return;
1.1.5视频录制
视频录制用到的关键API是VideoWriter、write、release(释放数据并强制输出)。
VideoCapture cap(0); Mat mImage1; cap.set(CAP_PROP_FRAME_WIDTH, 1920); cap.set(CAP_PROP_FRAME_HEIGHT, 1080); QString qsFileName=QString("./myvideo.avi"); int iRcc=VideoWriter::fourcc('M','J','P','G'); VideoWriter vWriter(qsFileName.toStdString(),iRcc,25,Size(1920,1080)); while(cap.isOpened()) //摄像头是否被打开 { bool rect=cap.read(mImage1); //写数据到都多媒体 if(rect) { imshow("video",mImage1); vWriter.write(mImage1); int ikey=waitKey(5); if(ikey==13){ break; } } } cap.release(); vWriter.release(); destroyAllWindows();
1.1.6鼠标事件
//设置鼠标回调函数:setMosureCallback(winname,callback,userdata); //自定义回调函数:callback(event,x,y,flags,userdata); //参数必须一致 //(1)event:鼠标的移动、按下等; //(2)x,y:鼠标的坐标 //(3)flags:鼠标记录 //头文件定义(全局变量,不属于任何类): void onMousreCallBack(int iEvent,int iX,int iY,int iFlags,void *param); static Mat mImagess; static Point startPoint(0,0); static Point endPoint(0,0); static int m_iFlags=0; //Cpp文件:main函数 mImagess=Mat::zeros(Size(600,400),CV_8UC3); namedWindow("line"); setMouseCallback("line",onMousreCallBack,(void *)&mImagess); while(true) { imshow("line",mImagess); int iKey=waitKey(10); if(iKey==13) { break; } else if(iKey==108) //l { m_iFlags=1; } else if(iKey==114) //r { m_iFlags=2; } else if(iKey==99) //c { m_iFlags=3; } } destroyAllWindows(); void onMousreCallBack(int iEvent, int iX, int iY, int iFlags, void *param) { if(iEvent==EVENT_LBUTTONDOWN) { startPoint.x=iX; startPoint.y=iY; } else if(iEvent==EVENT_LBUTTONUP) { endPoint.x=iX; endPoint.y=iY; switch(m_iFlags) { case 1: line(mImagess,startPoint,endPoint,Scalar(0,0,255),1); break; case 2: rectangle(mImagess,startPoint,endPoint,Scalar(0,0,255),1); break; case 3: int r=ceil(sqrt((startPoint.x-endPoint.x)*(startPoint.x-endPoint.x)+ (startPoint.y-endPoint.y)*(startPoint.y-endPoint.y))); circle(mImagess,startPoint,r,Scalar(0,0,255),1); break; } } }
1.1.7滑动条控件
/*>>函数名称:createTrackbar (1)参数1: trackbarname, winname (2)参数2: value,当前值 (3)参数3: count, 最小值为0,最大值为count (4)参数4: callback, 用户数据 >>getTrackBarPos (1)参数1: trackbarname, (2)参数2: winname (3)返回值*/ namedWindow("trackbar"); //创建trackbar createTrackbar("R","trackbar",0,255); createTrackbar("G","trackbar",0,255); createTrackbar("B","trackbar",0,255); Mat image=Mat::zeros(Size(800,600),CV_8UC3); int lastR=0; int lastG=0; int lastB=0; while(true) { imshow("trackbar",image); if(waitKey(10)==13) { break; } int r=getTrackbarPos("R","trackbar"); int g=getTrackbarPos("G","trackbar"); int b=getTrackbarPos("B","trackbar"); if(lastB !=b || lastG !=g || lastR !=r) { lastB=b; lastR=r; lastG=g; int height=image.rows; int width=image.cols; for(int row=0;row>>>>HSV空间
- Hue:色相,即色彩,如红色、蓝色。不同角度代表不同的颜色
- Saturation:饱和度,颜色的纯度,圆心白、边缘深
- Value:明度
1.2.2数据结构Mat
1.2.2.1定义
1.2.2.2 属性
字段
说明
字段
说明
dims
维度
channels
通道数,RGB是3
rows
行数
size
矩阵大小
cols
列数
type
Dep+dt+chs CV_8UC3
depth
像素的位深(8位)
data
存放数据
1.2.2.3拷贝
//浅拷贝:Mat A=imread(file); Mat B(A); //深拷贝:Mat clone(); Mat::copyTo(); Mat aImage=imread("C:/Users/xtf_a/Desktop/QTLearn/OpenCVLearn/01/pear.jpg"); //浅拷贝 Mat bImage(aImage); rectangle(aImage,Rect(0,0,200,200),Scalar(0,0,255),1); imshow("a",aImage); imshow("b",bImage); waitKey(0); destroyAllWindows();
1.2.2.4对象的属性:行数、列数及通道数
Mat aImage=imread("C:/Users/xtf_a/Desktop/QTLearn/OpenCVLearn/01/pear.jpg"); //图像的大小,行列 int iRow=aImage.size().height; int iCol=aImage.size().width; int iType=aImage.type();
1.2.2.5通道的分离
Mat aImage=imread("C:/Users/xtf_a/Desktop/QTLearn/OpenCVLearn/01/pear.jpg"); //图像的大小,行列 std::vector splitImage; split(aImage,splitImage); int iSize=splitImage.size(); if(iSize!=3){ return; } imshow("b",splitImage.at(0)); imshow("g",splitImage.at(1)); imshow("r",splitImage.at(2)); waitKey(0); destroyAllWindows();
1.2.2.6通道的合并
Mat aImage=imread("C:/Users/xtf_a/Desktop/QTLearn/OpenCVLearn/01/pear.jpg"); //图像的大小,行列 std::vector splitImage; split(aImage,splitImage); int iSize=splitImage.size(); if(iSize!=3){ return; } Mat mergeImage; std::vector mergeImages; mergeImages.push_back(splitImage.at(2)); mergeImages.push_back(splitImage.at(1)); mergeImages.push_back(splitImage.at(0)); merge(mergeImages,mergeImage); imshow("RGB",mergeImage); waitKey(0); destroyAllWindows();
1.2.2.7指针访问像素
//用指针访问像素的这种方式是利用C语言的操作符[]。这种方法最快,但是略微有点抽象。 Mat aImage=imread("C:/Users/xtf_a/Desktop/QTLearn/OpenCVLearn/01/pear.jpg"); int iRow=aImage.size().height; int iCol=aImage.size().width; int iChanels=aImage.channels(); int iTotalCol=iCol*iChanels; int div=16; //数据位数 for(int i=0;i