opencv复习笔记随记

opencv复习笔记随记

索引:

1.图像窗口大小调整

2.Scalar()函数

3.Mat的初始化方式

4.图像混合

5.vector的使用

6.TrackBar实例

7.saturate_cast()

8.线性和非线性滤波

9.opencv中三种操作像素的方式

10.canny边缘检测原理

11.其他边缘检测函数

12.形态学处理原理

13.resize()各种插值方式

14.获取图像属性

15.图像金字塔函数

16.霍夫变换

17.opencv中的vector

18.opencv的基本数据结构

19.漫水填充算法

20.控制鼠标事件的setMouseCallback()函数

21.控制键盘事件

 

【1】图像窗口大小调整:

         (1)允许手动调整:

namedWindow("image",0);     # 0表示可以调整窗口大小
imshow("image", image);

         (2)自动调整为指定大小:

namedWindow("image",0);     # 0表示可以调整窗口大小
cvResizeWindow("image", 500, 500);
imshow("image", image);

【2】Scalar()函数:

         在创建一个Mat矩阵的时候,如Mat M(7, 7, CV_8SC3, Scalar(100, 100, 100))中调用了Scalar()函数为矩阵进行初始化赋值,cv::Scalar()构造函数的前三个参数用于设置BGR通道,第四个参数设置图片的透明度。

         CV_8SC3中的C3表示创建的Mat矩阵为3通道,此时如果Scalar()函数中包含小于3个参数,则后面几个通道的初始化值为0;如果Scalar()函数中包含大于3个参数,则只取前三个参数用于为各个通道赋值。

【3】Mat的初始化方式:

(1)调用Mat构造函数;
Mat M(7, 7, CV_32FC3, Scalar(100, 100, 100));

(2)create函数:
M.create(100, 60, CV_32FC3);

(3)拷贝构造函数/赋值操作符:
1)拷贝头部:
Mat M1(M2);
Mat M2 = M1;
2)拷贝数据:
Mat M3 = M1.clone();

Mat M4;
M.copyTo(M4);

【4】图像混合:

# 【1】使用roi和mask方式,添加图标
bool  ROI_AddImage()
{
    Mat srcImage1= imread("1.jpg");
    Mat logoImage= imread("logo.jpg");

    // create roi
    Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));
    // create mask
    Mat mask= imread("logo.jpg",0);
    
    logoImage.copyTo(imageROI,mask);
    namedWindow("ROI_AddImage");
    imshow("ROI_AddImage",srcImage1);

    return true;
}



# 【2】使用addWeighted()混合两张图像。
“”“
addWeighted()函数:
     参数1:src1,第一个原数组.
     参数2:alpha,第一个数组元素权重
     参数3:src2第二个原数组
     参数4:beta,第二个数组元素权重
     参数5:gamma,图1与图2作和后添加的数值,取值不要太大
     参数6:dst,输出图片
”“”
bool  LinearBlending()
{
	double alphaValue = 0.5; 
	double betaValue = 1.0 - alphaValue;
	Mat srcImage2, srcImage3, dstImage;
	srcImage2 = imread("1.jpg");
	srcImage3 = imread("2.jpg");
 
	addWeighted( srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);
	imshow( "raw_image", srcImage2 );
	imshow( "LinearBlending", dstImage );

	return true;
}



# 【3】使用roi和addWeighted()方式,添加图标
bool  ROI_LinearBlending()
{
	Mat srcImage4= imread("1.jpg",1);
	Mat logoImage= imread("logo.jpg");

	Mat imageROI = srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));

	addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);
	imshow("ROI_LinearBlending",srcImage4);

	return true;
}

【5】vector的使用:

vector channels;
...
image channel = channels.at(0);   # 提取其中一个通道

【6】TrackBar实例:

         https://blog.csdn.net/qq_37596943/article/details/80387209

         createTrackbar()参数列表:

          a.轨迹条名字;

          b.窗口名字;

          c.指向整型的指针(滑块位置);

          d.滑块的最大值;

          e.指向回调函数的指针(函数原型必须为void...(int,void*));

          f.用户传给滑块的数据(可无本参数)。

【7】saturate_cast():

         saturate_cast()函数的功能是防止数据溢出,当运算结果小于0时记为0,当运算结果大于255时记为255.

【8】线性和非线性滤波:

# 方框滤波
Mat boxFilterDst;
boxFilter(src, boxFilterDst, -1, cv::Size(5, 5));
 
# 均值滤波
Mat blurDst;
blur(src, blurDst, cv::Size(5, 5));

# 高斯滤波
Mat GaussianDst;
GaussianBlur(src, blurDst, cv::Size(5, 5),0.8,0.8);

# 中值滤波
“”“
输入为1,3,4通道的图像
孔径尺寸=3/5时,图像深度为CV_8U/CV_16U/CV_32F
大孔径尺寸的图像只能为CV_8U
”“”
Mat MedianDst;
medianBlur(src, MedianDst, 7);

# 双边滤波
Mat BilateralDst;
bilateralFilter(src, BilateralDst, 25, 25 * 2, 25 / 2);

【9】opencv中三种操作像素的方式:

           https://blog.csdn.net/a8039974/article/details/80914958

          1)指针访问:

int rowNumber = image.rows;//行数
int colNumber = image.cols * image.channels();//每一行元素个数 = 列数 x 通道数
for (int i = 0; i < rowNumber; i++)//行循环
{
uchar* data = image.ptr(i);//获取第i行的首地址
for (int j = 0; j < colNumber; j++)//列循环
{data[j] = 255;}
}

          2)迭代器iterator:

Mat_::iterator it = image.begin();//初始位置的迭代器
Mat_::iterator itend = image.end();//终止位置的迭代器
for (; it != itend; it++)
{
//处理BGR三个通道
(*it)[0] = 255;//B
(*it)[1] = 255;//G
(*it)[2] = 0;//R
}

          3)动态地址计算:

rowNumber = image.rows;
colNumber = image.cols;
for (int i = 0; i < rowNumber; i++)
{
   for (int j = 0; j < colNumber; j++)
     {
     //处理BGR三个通道
     image.at(i, j)[0] = 0;//B
     image.at(i, j)[1] = 255;//G
     image.at(i, j)[2] = 0;//R
     }
}

【10】canny边缘检测原理:

         https://blog.csdn.net/weixin_40647819/article/details/91411424

         1)对输入图像进行高斯平滑,降低错误率;

         2)Sobel计算梯度幅度和方向来估计每一点处的边缘强度与方向;

         3)根据梯度方向,对梯度幅值进行非极大值抑制,本质上是对Sobel、Prewitt等算子结果的进一步细化;

         4)用双阈值处理和连接边缘。

【11】其他边缘检测函数:

         https://www.cnblogs.com/skyfsm/p/6879265.html

【12】形态学处理原理:

         https://blog.csdn.net/weixin_39504171/article/details/94614445

【13】resize()各种插值方式:

         https://blog.csdn.net/guyuealian/article/details/85097633         

         resize()函数的参数中包含dsize表示输出图像的大小 ,也包含fx和fy表示weight和height方向的缩放比例。需要注意的是,dsize和fx/fy不能同时为0,要么指定好dsize的值,让fx和fy空置直接使用默认值;要么设置dsize为0,指定好fx和fy的值。

# 【1】
resize(img, imgDst, Size(30,30));

# 【2】最近邻插值(默认值为线性插值)
resize(image, image2X_INTER_NEAREST, Size(), 2, 2,INTER_NEAREST);

         测试过程中几种插值方法的速度排序为:INTER_NEAREST(最近邻插值)>INTER_CUBIC  (三次样条插值)>INTER_LINEAR(线性插值)>INTER_AREA  (区域插值)。
         对图像进行缩小时,为了避免出现波纹现象,推荐采用INTER_AREA 区域插值方法;而要放大图像,通常使用INTER_CUBIC(速度较慢,但效果最好),或者使用INTER_LINEAR(速度较快,效果还可以);一般不推荐最近邻插值INTER_NEAREST。

【14】获取图像属性:

         https://blog.csdn.net/mars_xiaolei/article/details/88637099

//标志位
image.flags
//图像尺寸
image.size
//列宽
image.cols
//行高
image.rows
//维度
image.dims

【15】图像金字塔函数:

         https://blog.csdn.net/davebobo/article/details/51885043

         常见的两种图像金字塔为高斯金字塔和拉普拉斯金字塔高斯金字塔向下降采样图像 ;拉普拉斯金字塔从低层图像中向上采样重建图像。

         高斯金字塔从i层生成第i+1层的过程中,先用高斯核对图像进行卷积,然后删除所有偶数行和偶数列,这样新得到的图像面积会变为原图的四分之一;拉普拉斯金字塔的图像首先在每个维度上扩大为原来的两倍,新增的行以0填充,然后给指定的滤波器进行卷积去估计“丢失”像素的近似值,得到后的图像与原来的图像相比较会发觉比较模糊,为了恢复出原来的图像需要获得这些丢失的信息,这些信息构成了拉普拉斯金字塔。

         PyrDown()的功能是从金字塔上一级图像生成下一级图像,函数中的参数dsize指定了目标图像的尺寸,默认情况下它是计算所得的尺寸((Image.cols+ 1)/ 2、(Image.rows+ 1)/ 2)。但在任何情况下,应满足以下条件:

         PyrUp()的功能是将已知图像在每一个维度上都扩大两倍,函数中的参数dsize指定了目标图像的尺寸,默认情况下它是计算所得的尺寸((Image.cols+ 1)/ 2、(Image.rows+ 1)/ 2)。但在任何情况下,应满足以下条件:

【16】霍夫变换:

         https://blog.csdn.net/zhu_hongji/article/details/81632611

         opencv中霍夫变换的几个函数为:

(1)标准霍夫直线变换:
“”“
 从平面坐标转换到霍夫空间,输出为极坐标,一般情况是有经验的开发者使用,需要自己反变换到平面空间。
”“”
cv::HoughLines(
InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长,一般
CV_PI/180
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
double srn=0,// 是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
double stn=0,//是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换
double min_theta=0, // 表示角度扫描范围 0 ~180之间, 默认即可
double max_theta=CV_PI) 


(2)霍夫变换直线概率:
“”“
 最终输出直线的两个点。
”“”
cv::HoughLinesP(
InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180
Int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
double minLineLength=0,// 最小直线长度
double maxLineGap=0// 最大间隔)
 

(3)霍夫圆变换:
“”“
 因为霍夫圆检测对噪声比较敏感,所以首先要对图像做滤波处理。
 基于效率考虑,Opencv中实现的霍夫变换圆检测是基于图像梯度的实现,分为两步:
  1. 检测边缘,发现可能的圆心
  2. 基于第一步的基础上从候选圆心开始计算最佳半径大小
”“”
cv::HoughCircles(
InputArray image, // 输入图像 ,必须是8位的单通道灰度图像
OutputArray circles, // 输出结果,发现的圆信息
Int method, // 方法 - HOUGH_GRADIENT
Double dp, // dp = 1; 
Double mindist, // 10 最短距离-可以分辨是两个圆的,否则认为是同心圆- src_gray.rows/8
Double param1, // canny edge detection low threshold
Double param2, // 中心点累加器阈值 – 候选圆心
Int minradius, // 最小半径
Int maxradius//最大半径 )

         应用举例如下:

(1)霍夫线检测实例:
Mat gray_src, dst;
cvtColor(dst, gray_src, CV_GRAY2BGR);
Canny(gray_src, dst, 100, 200, 3);
vectorplines;//定义一个存放直线信息的向量
HoughLinesP(dst, plines, 1, CV_PI / 180, 70, 100, 50);
for (size_t i = 0; i < plines.size(); i++)
{
	Vec4f point1 = plines[i];
	line(src, Point(point1[0], point1[1]), Point(point1[2], point1[3]), Scalar(255, 255, 0), 2, LINE_AA);
}

(2)霍夫圆检测实例:
Mat gray_src, dst, dst1;
medianBlur(src, dst, 5);//因为霍夫圆检测对噪声比较敏感,故须先做中值滤波
cvtColor(dst, gray_src, CV_BGR2GRAY);

vector circles;
HoughCircles(gray_src, circles, HOUGH_GRADIENT, 1, 10, 40, 40, 5, 100);
for (size_t i = 0; i 

【17】opencv中的vector:

          https://blog.csdn.net/Ahuuua/article/details/80593388

         https://blog.csdn.net/weixin_44511592/article/details/87070652         

(1)vector>:
    vector容器里面放了一个vector容器,子容器里放点;
    一般在轮廓查找和轮廓绘制的参数contours中使用;
(2)vector:
    vector容器里面放了4维int向量;
    一般在轮廓查找和轮廓绘制的参数hierarchy中使用;
(3)vector:
    width * height from (x,y)
(4)vector:
    angle,center[x,y], size[w*h]

         应用举例如下所示:

int main()
 {
	Mat src, gray_src, drawImg, bin_output;
 
	src = imread("1.png");
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	namedWindow("output", CV_WINDOW_AUTOSIZE);

	cvtColor(src, gray_src, CV_BGR2GRAY);
	blur(gray_src, gray_src, Size(10, 10), Point(-1, -1), BORDER_DEFAULT);
 
    # 【1】
	vector> contours;
	vector hierarchy;
	threshold(gray_src, bin_output, 144, 255, 0);				
	findContours(bin_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));		
 
	# 【2】
	vector> contours_poly(contours.size());
	vector poly_rects(contours.size());
	vector minRect(contours.size());
	for (size_t i = 0; i < contours.size(); i++)
	{
		approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//减少轮廓点数
		poly_rects[i]=boundingRect(contours_poly[i]);             //获取绘制矩形数据
		if (contours_poly[i].size() > 5) {				
			minRect[i] = minAreaRect(contours_poly[i]);       //获取绘制旋转矩形数据
		}
	}
 
	# 【3】绘制
	src.copyTo(drawImg);
	Point2f pst[4];        //储存单个旋转矩形的四个点
	for (size_t i = 0; i < contours.size(); i++)
	{
		rectangle(drawImg, poly_rects[i],  Scalar(255, 0, 0), 2, 8);//绘制矩形框
		minRect[i].points(pst);//用线段画矩形,将RotatedRect类型转化为四个点	
		for (size_t u = 0; u < 4; u++)
		{line(drawImg, pst[u], pst[(u + 1) % 4], Scalar(0, 255, 0), 2, 8);}
		Rect brect = minRect[i].boundingRect(); //返回包含旋转矩形的最小矩形  
		rectangle(drawImg, brect,Scalar(0, 0, 255));
	}
	 
	waitKey(0);
	return 0;
}

【18】opencv的基本数据结构:

          https://blog.csdn.net/a8039974/article/details/80554492

         https://www.cnblogs.com/zengcv/p/6283095.html

【19】漫水填充算法:

          https://blog.csdn.net/poem_qianmo/article/details/28261997

【20】控制鼠标事件的setMouseCallback()函数:

void setMouseCallback(conststring& winname, MouseCallback onMouse, void* userdata=0 )
参数1:const string&类型的winname,为窗口的名字;
参数2:MouseCallback类型的onMouse,指定窗口里每次鼠标时间发生的时候,被调用的函数指针。
     这个函数的原型应该为voidFoo(int event, int x, int y, int flags, void* param),其中:
        event是 CV_EVENT_*变量之一;
        x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系);
        flags是CV_EVENT_FLAG的组合;
        param是用户定义的传递到cvSetMouseCallback函数调用的参数,默认值为0;
参数3:void*类型的userdata,用户定义的传递到回调函数的参数,有默认值0。

          在OnMouse()函数中对当前的鼠标事件进行判断,比如CV_EVENT_MOUSEMOVE /CV_EVENT_LBUTTONDOWN /CV_EVENT_RBUTTONDOWN   /CV_EVENT_LBUTTONUP    /CV_EVENT_RBUTTONUP   /CV_EVENT_FLAG_LBUTTON 。

【21】控制键盘事件:

          在main()函数中用while()循环轮询按键可以控制键盘事件。

int main()
{
    while(1)
     {
        # 获取键盘按键
        int c = waitKey(0);
        # 退出键
        if((c&255)==27)
        {break;}
        # 其他按键
        switch((char)c)
        {
         case'1':
             ......
             break;
         case'2':
             ......
             break;
         case'3':
             ......
             break;
         case'4':
             ......
             break;
         case'5':
             ......
             break;
        }
     }
}

【22】remap()函数:

          https://www.cnblogs.com/HL-space/p/10546595.html

          remap()函数的调用步骤为:首先创建两个CV_32FC1类型的Mat分别用于存放图像X方向和Y方向的映射方向;然后遍历输入图像的每一个像素,对对应的MatX和MatY赋变换后的坐标值;最后调用remap()函数,其中输出图像要求大小与MatX和MatY相同,通道数目及数据类型和输入图像相同。

          remap()函数可以用来实现halcon中的mirror_image()等函数,在重映射过程中图像的大小也可以发生改变,此时像素与像素之间的关系就不是一一对应关系,因此在重映射过程中可能会涉及到像素值的插值计算。

【23】SURF算法:

          https://blog.csdn.net/qq_31531635/article/details/73798398

          

 

你可能感兴趣的:(opencv)