基于C++ OpenCV的图像处理-基础篇

该博客围绕OpenCV展开图像处理相关内容。涵盖图像处理基础,如窗口创建、色彩空间转换、图像运算与变换等;还介绍图形滤波、形态学处理、轮廓检测等。此外,有车辆统计项目实战,以及特征点检测和图像分割的方法,如哈里斯焦点检测、分水岭法等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、图像处理基础篇

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<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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值