目录
一、图像处理基础篇
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<height;row++)
{
for(int col=0;col<width;col++)
{
image.at<Vec3b>(row,col)[0]=b;
image.at<Vec3b>(row,col)[1]=g;
image.at<Vec3b>(row,col)[2]=r;
}
}
}
}
destroyAllWindows();
示意图
1.2 OpenCV必备核心知识
1.2.1 色彩空间的转换
- RGB:人眼的色彩空间
- OpenCV默认的色彩空间BGR
- HSV/HSB/HSL
- 视频空间YUV
------>>>>>>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<Mat> 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<Mat> splitImage;
split(aImage,splitImage);
int iSize=splitImage.size();
if(iSize!=3){
return;
}
Mat mergeImage;
std::vector<Mat> 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<iRow;i++)
{
uchar *data=aImage.ptr<uchar>(i); //获取第i行数据的首地址
for(int j=0;j<iTotalCol;j++)
{
data[j]=data[j]/div*div+div/2;
}
}
1.2.2.8 动态地址访问像素
//使用动态地址运算配合at方法的colorReduce函数的代码,简介明了,很直观。
int iRow=aImage.size().height;
int iCol=aImage.size().width;
//int iRow=aImage.rows; //获取行数的方法2
//int iCol=aImage.cols; //获取列数的方法2
int iChanels=aImage.channels();
for(int i=0;i<iRow;i++)
{
for(int j=0;j<iCol;j++)
{
int b=aImage.at<Vec3b>(i,j)[0];
int g=aImage.at<Vec3b>(i,j)[1];
int r=aImage.at<Vec3b>(i,j)[2];
}
}
/*说明:
(1) Vec3b:读取一个RGB像素点的像素值,uchar类型,是一个数组;8U 类型的 RGB 彩色图像可以使用Vec3b。
(2) Vec3f::读取一个RGB像素点的像素值,float类型,是一个数组;
(3)单通道值获取:mMask.at<uchar>(i,j)=255;
*/
Vec3f Intensity=image.at<Vec3f>(x,y);
float bule=Intensity.val[0];
float green=Intensity.val[1];
float red=Intensity.val[2];
1.3 绘制基本图像
1.3.1绘制直线
//API定义:
line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
int thickness = 1, int lineType = LINE_8, int shift = 0);
Mat mImage=Mat::zeros(Size(600,400),CV_8UC3);
line(mImage,Point(100,100),Point(300,300),Scalar(255,255,255),2);
i