索引:
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