OpenCV图像操作
OpenCV
OpenCV官方网址.
非常推荐查看官方文档
Mat数据类型
参考网址.
cv::Mat 类的对象有一个成员函数 type() 用来返回矩阵元素的数据类型,返回值是 int 类型,不同的返回值代表不同的类型。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210119202705346.png?x-oss-
表头的 C1, C2, C3, C4 指的是通道(Channel)数。灰度图像只有 1 个通道,是 C1;JPEG格式 的 RGB 彩色图像就是 3 个通道,是 C3;PNG 格式的彩色图像除了 RGB 3个通道外,还有一个透明度通道,所以是 C4。
at 方法接受的是 uchar 这样的数据类型,而非 CV_8U。在已知通道数和每个通道数据类型的情况下,指定给 at 方法的数据类型如下表所示
Mat基础操作
图像遍历
基本遍历
for (int m = 0; m < pointMat.cols; m++) { // rows为竖向,cols为横向
for (int n = 0; n < pointMat.rows; n++) {
cv::Vec3f point = pointMat.at<cv::Vec3f>(n, m);
}
}
指针遍历
forEach
Mat image = Mat::zeros(3, 3, CV_8UC1);
image.forEach<uchar>([&](uchar& pixel, const int position[]) -> void {
// position 在单通道情况下,是一个包含两个元素的数组,即x, y;
pixel = position[0] + position[1];
});
cv::Mat A = image; for(int i=0;i<A.rows;i++) { // 下面都是打印用的
for(int j=0;j<A.cols;j++)
cout<<(int)A.at<uchar>(i,j)<<' ';
cout<<endl;
}
访问图像像素点
# 使用 at 方法访问数据元素的时候要指明数据类型
pointMat.at<cv::Vec3f>(n, m) // 是先横向后竖向
# 获取图像像素指针
Mat.ptr<uchar>(int i=0) /*获取像素矩阵的指针,索引i表示第几行,从0开始计行数。*/
const uchar* current = myImage.ptr<uchar>(row );/*获得当前行指针*/
p(row, col) = current[col] /*获取当前像素点P(row, col)的像素值*/
像素范围处理
// saturate_cast<uchar> // 防止溢出
saturate_cast<uchar>((g_nContrastValue*0.01)*(g_srcImage.at<Vec3b>(y, x)[c]) + g_nBrightValue)
空图像创建
cv::Mat dispImg(30 + size*h, 100 + size*w, CV_8UC3, Scalar(100, 100, 100)); //需要注意长和宽的区别
图像缩放
cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
插值方式有:
cv.INTER_NEAREST 最近邻插值
cv.INTER_LINEAR 双线性插值
cv.INTER_CUBIC 双线性插值
cv.INTER_AREA 使用像素区域关系重新采样。它可能是图像抽取的首选方法,因为它可以提供无莫尔条纹的结果。但是当图像被缩放时,它类似于INTER_NEAREST方法。
resize(imagesource, imagedist, cv::Size(rows, cols));//多用双线性差值实现缩放
resized = cv2.resize(img, None, fx=0.6, fy=0.6, interpolation=cv2.INTER_AREA)
可用于保留宽高比,fx,fy为放大或缩小的系数
寻找图像像素最大值与最小值
void cv::minMaxLoc(InputArray src, double * minVal, double * maxVal = 0, Point * minLoc = 0, Point * maxLoc = 0, InputArray mask = noArray() )
• src:需要寻找最大值和最小值的图像或者矩阵,要求必须是单通道矩阵
• minVal:图像或者矩阵中的最小值。
• maxVal:图像或者矩阵中的最大值。
• minLoc:图像或者矩阵中的最小值在矩阵中的坐标。
• maxLoc:图像或者矩阵中的最大值在矩阵中的坐标。
• mask:掩模,用于设置在图像或矩阵中的指定区域寻找最值。
计算图像的均值和标准方差
cv::Scalar cv::mean(InputArray src, InputArray mask = noArray() )
src:待求平均值的图像矩阵。
mask:掩模,用于标记求取哪些区域的平均值。
求取的是图像矩阵的每个通道的平均值
同时求取图像每个通道的平均值和标准方差
void cv::meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, InputArray mask = noArray() )
src:待求平均值的图像矩阵。
• mean:图像每个通道的平均值,参数为Mat类型变量。
• stddev:图像每个通道的标准方差,参数为Mat类型变量。
• mask:掩模,用于标记求取哪些区域的平均值和标准方差。
convertTo函数
• convertTo可以改变Mat的深度,例如可以把Mat的type从CV_8UC3改为CV_16SC3
• convertTo不可以改变Mat的通道数,例如不可以把Mat的type从CV_8UC3改为CV_8UC1,即使你填入的转换类型通道数不同,输出的通道数还是与输入的通道数相同
• convertTo支持就地(in-place)操作
cvtColor()函数
负责转换不同通道的Mat,因为该函数的第4个参数就可以设置目的Mat数据的通道数,一般情况下这个函数是用来进行色彩空间转换的
cvtColor( image, gray_image, COLOR_BGR2GRAY );
窗口相关
getWindowImageRect获取窗口大小
利用鼠标点击显示像素值或者三维坐标
void onmouse(int event, int x, int y, int flags, void *param) {
if (event == cv::EVENT_LBUTTONDOWN) {
cv::Mat pointMat = *((cv::Mat *)param);
std::cout << pointMat.at<cv::Vec3f>(y, x) << std::endl;
// circle(img,Point(x,y),50,Scalar(0,255,0),1);
}
}
cv::namedWindow("image");
setMouseCallback("image", onmouse, &pointMat);
while (true) {
cv::imshow("image", image);
int key = cv::waitKey(20);
if (key == 27) {
break;
}
}
图像与绘制
轮廓近似
采用Douglas-Peucker算法,可参考:link.
approx = cv2.approxPolyDP(contour,epsilon,True)
第一个参数是轮廓的点集。
第二个参数epsilon的含义如下所述,滤掉的线段集离新产生的线段集的距离为d,若d小于epsilon,则滤掉,否则保留。
第三个参数指示新产生的轮廓是否闭合。
返回的是一些列点组成的多边形。
取多边形边缘点
# 可用来检测二值图像的边缘轮廓
findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> contours, hierarchy
近似曲线模拟
approximate_polygon(coords, tolerance)
# coords: 坐标点序列
# tolerance: 容忍值
重要数学操作
掩膜操作
Mat kernel=(Mat_<char>(3,3)<< 0, -1, 0, -1, 5, -1 , 0, -1, 0);
filter2D( src, dst, src.depth(), kernel );
//输入,输出图像,目标图像深度(如果没写或为-1,将生成与原图像深度相同的图像),卷积核
①提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为0。
②屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
③结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。
④特殊形状图像的制作。用选定的图像、图形或物体,对待处理的图像(全部或局部)进行遮挡,来控制图像处理的区域或处理过程。用于覆盖的特定图像或物体称为掩模或模板。
膨胀、腐蚀、开操作、闭操作------形态学操作
void morphologyEx( InputArray src, OutputArray dst,
int op, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() )
//获取自定义核 第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的
Mat kernel = getStructuringElement(MORPH_RECT, Size(18, 18));
morphologyEx(img, out, MORPH_OPEN, kernel); //输入,输出图像,运算种类,核
这个函数也可实现腐蚀和膨胀,修改第三个参数即可
enum MorphTypes{
MORPH_ERODE = 0, //腐蚀
MORPH_DILATE = 1, //膨胀
MORPH_OPEN = 2, //开操作
MORPH_CLOSE = 3, //闭操作
MORPH_GRADIENT = 4, //梯度操作
MORPH_TOPHAT = 5, //顶帽操作
MORPH_BLACKHAT = 6, //黑帽操作
MORPH_HITMISS = 7
};
腐蚀
卷积核沿着图像滑动,如果与卷积核对应的原图像的所有像素值都是1,那么中心元素就保持原来的像素值,否则就变为零。分割(isolate)独立的图像元素
图像A用卷积模板B来进行腐蚀处理,通过模板B与图像A进行卷积计算,得出B覆盖区域的像素点最小值,并用这个最小值来替代参考点的像素值。如图所示,将左边的原始图像A腐蚀处理为右边的效果图A-B。
kernel = np.ones((3,3), np.uint8)
detect_res = cv2.erode(detect_res, kernel, iterations = 3)
膨胀
图像膨胀是腐蚀操作的逆操作,类似于“领域扩张”,将图像中的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更大,线条变粗了,主要用于去噪。连接(join)相邻的元素
(1) 图像被腐蚀后,去除了噪声,但是会压缩图像。
(2) 对腐蚀过的图像,进行膨胀处理,可以去除噪声,并且保持原有形状。
kernel = np.ones((3,3), np.uint8)
im = cv2.dilate(im, kernel, iterations = 1)
腐蚀、膨胀可用于去噪(低尺寸结构元素的腐蚀操作很容易去掉分散的椒盐噪声点),图像轮廓提取、图像分割、寻找图像中的明显的极大值区域或极小值区域等。
开运算
先腐蚀,后膨胀,将两块连系不紧密的图像区域分开
(1)开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不便,可清除一些小东西(亮的),放大局部低亮度的区域。
(2)开运算是一个基于几何运算的滤波器。
(3)结构元素大小的不同将导致滤波效果的不同。
(4)不同的结构元素的选择导致了不同的分割,即提取出不同的特征。
morphologyEx(img, out, MORPH_OPEN, kernel);//输入,输出图像,运算种类,核
闭运算
闭运算 = 先膨胀运算,再腐蚀运算(看上去将两个细微连接的图块封闭在一起)
(1)闭运算能够填平小湖(即小孔),弥合小裂缝,而总的位置和形状不变,可清除小黑点。
(2)闭运算是通过填充图像的凹角来滤波图像的。
(3)结构元素大小的不同将导致滤波效果的不同。
(4)不同结构元素的选择导致了不同的分割。
morphologyEx(img, out, MORPH_CLOSE, kernel);//输入,输出图像,运算种类,核
黑帽
黑帽是闭运算与原图的差值图像,可得到图像内部的小孔,或者前景色中的小黑点,可突出原图像中比周围暗的区域。
黑帽运算(img) = 闭运算图像(img) - 原始图像(img)
dst = cv2.morphologyEx(src, cv2.MORPH_BLACKHAT, kernel)
想获取更多的细节,可以将卷积设置为10*10
顶帽
顶帽是原图像与开运算的差值图像,可突出原图像中比周围亮的区域
顶帽运算(img) = 原始图像(img) - 开运算(img)
kernel = np.ones((10,10), np.uint8)
result = cv2.morphologyEx(src, cv2.MORPH_TOPHAT, kernel)
可以将外部噪声被提取出来,提高内核矩阵kernel可以提取更多元素
梯度操作
膨胀图与腐蚀图之差,保留物体的边缘轮廓