OpenCV
2018-04-07 16:34:29 19 举报
AI智能生成
opencv基础
作者其他创作
大纲/内容
基本操作
图像的读取,显示和储存
imread(,正数为彩色)
16U和32S imshow()会把值都除以255,浮点的会乘以255
flip(img,out,正数表示水平,0表示垂直,负数表示水平和垂直)
拓展:void onMouse( int event, int x, int y, int flags, void* param)
cv::setMouseCallback("window", onMouse,reinterpret_cast<void*>(&image));
Mat
Mat img2(img1)和img2=img1,浅复制;img.copyTo(),img.clone(),img.convertTo()深度复制
image1.create(200,200,CV_8U) 重新分配一个新图像(仅在大小或类型不同时)
可以定义由一些行或列组成的roi:image.rowRange(start,end);
操作像素
vec3b三个uchar,用Vec<T,N>模板类定义,其中T是类型,N是向量元素的数量。
用Mat_模板操作图像,cv::Mat_<uchar> im2(image);im2(50,100)= 0;
template《typename _Tp》 class Mat_ : public Mat
用指针扫描图像
为了提高性能,会在图像的每行末尾用额外的像素进行填充。
用cv::Mat的isContinuous方法可方便地判
断出图像有没有被填充。如果图像中没有填充像素,它就返回
true。我们还能这样测试矩阵的连续性:
// 检查行的长度(字节数)与“列的个数 × 单个像素”的字节数是否相等
image.step == image.cols*image.elemSize();
断出图像有没有被填充。如果图像中没有填充像素,它就返回
true。我们还能这样测试矩阵的连续性:
// 检查行的长度(字节数)与“列的个数 × 单个像素”的字节数是否相等
image.step == image.cols*image.elemSize();
根据图像是否填充
可以这样优化
还可以
低层次指针
cv::Mat_<cv::Vec3b> cimage(image);
cv::Mat_<cv::Vec3b>::iterator it= cimage.begin();
cv::Mat_<cv::Vec3b>::iterator itend= cimage.end();
用迭代器扫描图像
MatIterator<cv::Vec3b> it
Mat_<cv::Vec3b>::iterator it
然后直接for循环begin,end
// 在初始位置获得迭代器
cv::Mat_<cv::Vec3b>::iterator it=
image.begin<cv::Vec3b>();
// 获得结束位置
cv::Mat_<cv::Vec3b>::iterator itend=
image.end<cv::Vec3b>();
或
cv::Mat_<cv::Vec3b> cimage(image);或
cv::Mat_<cv::Vec3b>::iterator it= cimage.begin();
cv::Mat_<cv::Vec3b>::iterator itend= cimage.end();
拓展1:cv::saturate_cast<tp>(),以确保结果在该数据类型定义的范围之内
拓展2:setTo(),方法对矩阵中所有元素赋值
result.row(0).setTo(cv::Scalar(0)),这个语句把结果图像第一行的所有像素设置为0。
拓展3:滤波函数:filter2D();调用函数并传入图像和内核,即可返回滤波后的图像。
简单图像运算
cv::add
// c[i]= a[i]+b[i];
cv::add(imageA,imageB,resultC);
// c[i]= a[i]+k;
cv::add(imageA,cv::Scalar(k),resultC);
// c[i]= k1*a[1]+k2*b[i]+k3;
cv::addWeighted(imageA,k1,imageB,k2,k3);
// c[i]= k*a[1]+b[i];
cv::scaleAdd(imageA,k,imageB,resultC);
cv::add(imageA,imageB,resultC);
// c[i]= a[i]+k;
cv::add(imageA,cv::Scalar(k),resultC);
// c[i]= k1*a[1]+k2*b[i]+k3;
cv::addWeighted(imageA,k1,imageB,k2,k3);
// c[i]= k*a[1]+b[i];
cv::scaleAdd(imageA,k,imageB,resultC);
还可以加掩码
1.cv::subtract、cv::absdiff、cv::multiply和cv::divide等函数的多种格式。
2.此外还有位运算符(对像素的二进制数值进行按位运算):
cv::bitwise_and、cv::bitwise_or、cv::bitwise_xor和cv::bitwise_not。
3.cv::min和cv::max运算符也非常实用,它们可找到每个元素中最大或最小的像素值。
2.此外还有位运算符(对像素的二进制数值进行按位运算):
cv::bitwise_and、cv::bitwise_or、cv::bitwise_xor和cv::bitwise_not。
3.cv::min和cv::max运算符也非常实用,它们可找到每个元素中最大或最小的像素值。
4.在所有场合都要使用cv::saturate_cast函数,以确保结果在预定的像素值范围之内(避免上溢或下溢)。
这些图像必定有相同的大小和类型(如果与输入图像大小不匹配,输出图像会重新分配)。
5.还有一些运算符使用单个输入图像:cv::sqrt、cv::pow、cv::abs、cv::cuberoot、cv::exp和cv::log。
6.事实上,无论需要对图像像素做任何运算,OpenCV几乎都有相应的函数
6.事实上,无论需要对图像像素做任何运算,OpenCV几乎都有相应的函数
拓展:
重载图像运算符
大多数运算函数都有对应的重载运算符。因此调用cv::addWeighted的语句可以写成:
result= 0.7*image1+0.9*image2;
这种代码也会调用cv::saturate_cast函数。
大部分C++运算符都已被重载。其中包括:位运算符&、 |、 ^和~;
函数min、max和abs;比较运算符<、 <=、 ==、 !=、>和>=,它
们返回一个8位的二值图像。此外还有矩阵乘法m1*m2(其中m1和m2
都是cv::Mat实例)、矩阵求逆m1.inv()、 变位m1.t()、行列
式m1.determinant()、求范数v1.norm()、叉
乘v1.cross(v2)、点乘v1.dot(v2),等等。在理解这点后,你
就会使用相应的组合赋值符了(例如+=运算符)
图像split()和merge()
// (i,j)像素的新位置
srcX.at<float>(i,j)= j; // 保持在同一列
// 原来在第i行的像素,现在根据一个正弦曲线移动
srcY.at<float>(i,j)= i+5*sin(j/10.0);
cv::remap(image, result, srcX, srcY, cv::INTER_LINEAR); 彩色图像
图片操作
图像变换
图像检测
提取轮廓
canny算子
介绍:通常基于sobel算子,利用低阈值(只保留连续线条)和高阈值(边缘和低阈值的线段相连)混合使用sobel,检测得到高质量的边缘图像。
提取直线
霍夫变换
介绍:枚举每个像素点经过的直线(参数方程形式),根据最低投票数选出相应直线。
缺点:只能检测出直线。
函数:HoughLines()
拓展:霍夫变换可以检测任何可以用参数方程表示的物体,例如圆形,使用HoughCircles()
概率霍夫变换
介绍:随机选取像素点,一旦有线段达到最下投票数则根据线段长度,线段间隙要求排除相关像素。
特点:可以检测线段。
函数:HoughLinesP()
点集的直线拟合
条件:canny检测边缘后的图像与上提取出的某一条直线(可以调整线粗细)可得到点集
函数:fiteLine()
介绍:根据点集模拟一条直线,可选择不同的方式(不同的距离函数)
拓展:利用fitEllipse()可以返回一个旋转矩形,内切一个ellipse
提取连通区域轮廓
函数:findContours()
介绍:可对二值图像提取连通轮廓
运用1:通过面积筛选出需要的轮廓
运用2:计算轮廓的形状描述子
计算方法
1.边界框:boundingRect()
2.最小覆盖圆:minEnclosingCircle()
3.多边形逼近:polylines()
1.带角度,第二个参数使用approxPolyDp()获得
2.带弧度(凸包),第二个参数使用convexHull()获得
4.中心距函数:moments()
介绍:中心距,原点矩,moments计算公式介绍
运用:m10/m00,m01/m00为质心坐标
5.其它:
minAreaRect()最小覆盖自由矩形
contourArea()估算轮廓内部像素
pointPolygonTest()判断点在轮廓内外
matchShapes()判断连个轮廓的相似度
拓展:四边形检测
思路:用多边形逼近轮廓,判断边数
感兴趣点
检测
检测图像的角点
Harris特征检测
步骤1:函数:cornerHarris(),计算出每个像素的Harris值
步骤2:非最大值抑制:
步骤1.使用compare处理膨胀之后的Harris矩阵,得到极大值范围矩阵
步骤2.对Harris矩阵阈值化(只取最大Harris值*比例)得到角点分布图
步骤3.使用与运算处理极大值范围矩阵和角点分布图,得到最大Harris值*比例的极大分布,排除掉相邻的角点
拓展
1.适合跟踪的特征,goodFeaturesToTrack()
介绍:显示的计算协方差矩阵的特征值,而不是用传统的通过(给定k值然后根据行列式值和矩阵的迹来评定特征值的大小关系)
有一个参数可以选择采用传统的角点评定
输出是Vec2f的数组
2.特征检测方法的通用接口
抽象类FeatureDetector
子类:GoodFeaturesToTrackDetector,效果和1一样
快速检测特征
FAST算子
步骤1
利用特征检测通用接口和FAST检测器,FastFeatureDetector(用的是FAST-9角点检测器)
利用FAST()函数,第四个参数可以决定是否进行非最大值抑制
步骤2:利用drawKeypoints()在输入图像上画出关键点(用负数作为颜色会随机选择每个圆的颜色)
尺度不变的特征检测
SURF
SIFT
多尺度FAST特征的检测
BRISK
ORB
描述和匹配
局部模板匹配
获取keypoints
利用matchTemplate()找到每个keypoint的最相似匹配
drawMatches()
描述局部强值模式
使用SURF或SIFT
1.检测keypoints
2.计算关键点的描述子
3-1.BFmatcher匹配最佳对,matcher(NORM_L2,true),true代表去掉不互相为最佳匹配的
3-2.比率检验,使用knnMatch(),找出每个点的前n个最佳匹配项,若第一个和第二个相差很小,则舍去
3-3.匹配差值的阈值化,把描述点差值较大的匹配项排除,radiusMatch()
4.策略之间可以相互组合
用二值特征描述关键点
使用ORB或BRISK
1.检测keypoints
2.计算关键点的描述子
3.BFmatcher匹配最佳对,matcher(NORM_HAMMING(只能用这个),true),true代表去掉不互相为最佳匹配的
拓展:FREAK,只能计算描述子
投影关系
相机校准,使用多个棋盘图像获取calibrateCamera()的参数,然后remap()
计算图像对的基础矩阵(用来把一个视图上的点映射到另一个视图上的对极线上)
使用findFundamentalMat()计算
KeyPoints::convert()可以把KeyPoints转换成Point2f
computeCorrespondEpilines()可以计算出对极线的向量(ax+by+c=0),(a,b,c)
RANSAC算法匹配图像
计算出matches,把匹配出来的点都存在points1,points2中
使用使用findFundamentalMat(points1, points2, inliers)计算,然后根据inliers把matches筛选
拓展1.可以根据新的matches,继续通过findFundamentalMat()计算出更精确的基础矩阵
拓展2.使用correctMatches(),用更精确的基础矩阵,把points1,和points2变得更加符合对极线
计算两幅图像的单应矩阵
使用findHomography()
使用warpPerspective()扭曲输入图像到另一个图像
把img2拷贝到img1的roi区域
拓展:检测图像中的平面目标
继续使用RANSAC算法,只不过使用findHomography(),获得单应矩阵
利用perspectiveTransform(corners,detectedCorners,homography)把源角点投射到目标图像
getPerspectiveTransform()可以直接得到四对点(按顺时针)的homography,可以用来修改平面物体的透视图
学习资料
基本操作
Mat
opencv用这个来存储图片,是一个矩阵(行、列)
Mat M(2,2, CV_8UC3, Scalar(0,0,255));
CV_8UC3
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
行数mat.rows(), 列数: mat.rows()
第几行: mat.row(1)
读取图片
Mat image = imread(argv[1], CV_LOAD_IMAGE_COLOR);
loads the image in the BGR format
展示图片
namedWindow( "Display window", WINDOW_AUTOSIZE );
imshow( "Display window", image );
保存图片
imwrite( "./Gray_Image.jpg", gray_image );
修改图片
cvtColor( image, gray_image, CV_BGR2GRAY );
调整对比度和亮度:Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0 )
灰度化
cvtColor(src, src_gray, CV_BGR2GRAY);
CV_BGR2HSV
Hue, 色调(0°~360)
Saturation,饱和度(0.0~1.0)
Value 亮度(0.0 ~ 1.0
图片通道的分离
vector<Mat> bgr_planes;
split( src, bgr_planes );
图片通道的合并
vector<Mat> bgr_planes;
split( bgr_planes, dst );
裁剪图片
自定义区域
正方形: region of interest(ROI)
Rect roi (x, y, width, height)
src(roi).copyTo(dst)
wiki
0 条评论
下一页