OpenCV基础API函数一
OpenCV基础API函数二
OpenCV基础API函数三
OpenCV基础API函数四
OpenCV基础API函数五
connectedComponents 联通组件扫描
int connectedComponents(InputArray image, OutputArray labels,int connectivity, int ltype, int ccltype);
返回值:轮廓的个数(包括图像本身轮廓)
image:输入的二值图像
labels:标记图像(同一个轮廓的编号一样)
connectivity: 4邻域算法或8邻域算法
ltype:输出结果图像的类型 CV_32S 或者CV_16U
ccltype:使用连接组件的算法
例如 :给轮廓图像填充颜色并输出轮廓的个数
void Demo::myConnectedComponents(Mat &src)
{
Mat dst = Mat::zeros(src.size(), src.type());
srand(time(NULL));
//先把图像转化成灰度图像
if (src.channels() >= 2)
{
cvtColor(src, src, COLOR_BGR2GRAY);
}
//在进行二值化之前进行稍微的模糊效果会更好
GaussianBlur(src, dst, Size(0, 0), 3);
namedWindow("模糊", WINDOW_FREERATIO);
imshow("模糊", src);
//二值化,联通组件需要背景是黑色
threshold(src, src, 0, 255, THRESH_BINARY | cv::THRESH_OTSU);
namedWindow("二值化", WINDOW_FREERATIO);
imshow("二值化", src);
//adaptiveThreshold(src, dst, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 11, 14);
//获得联通组件的信息
int labelCount = connectedComponents(src, dst, 8);
cout << "边缘个数 " << labelCount - 1 << endl;
//给边缘上色
vector<Vec3b> colorLabel(labelCount - 1);
colorLabel[0] = Vec3b(0, 0, 0);
int row = src.rows;
int col = src.cols;
//生成随机颜色
for (int i = 1; i < labelCount; ++i)
{
colorLabel[i] = Vec3b(rand() % 255, rand() % 255, rand() % 255);
}
Mat colorSrc = Mat::zeros(src.size(), CV_8UC3);
//进行着色
for (int i = 0; i < row; ++i)
{
for (int j = 0; j < col; ++j)
{
colorSrc.at<Vec3b>(i, j) = colorLabel[dst.at<int>(i, j)];
}
}
putText(colorSrc, to_string(labelCount - 1), Point(50, 50), FONT_HERSHEY_PLAIN, 1.2, Scalar(0, 255, 255), 2);
namedWindow("结果图像", WINDOW_FREERATIO);
imshow("结果图像", colorSrc);
}
connectedComponentsWithStats 联通组件的统计信息
int connectedComponentsWithStats(InputArray image, OutputArray labels,
OutputArray stats, OutputArray centroids,
int connectivity, int ltype, int ccltype);
返回值:轮廓的个数(包括图像本身轮廓)
image:输入的二值图像
labels:标记图像(同一个轮廓的编号一样)
stats:统计信息,一共有五个值 前四个包括左上角的X,Y坐标 长和高,最后一个表示面积
centroids:轮廓的中心点
connectivity: 4邻域算法或8邻域算法
ltype:输出结果图像的类型 CV_32S 或者CV_16U
ccltype:使用连接组件的算法
例子:统计图像的轮廓个数,画出外界矩形
void Demo::myConnectStatistic(Mat &src){
Mat labels, stats, centroids, dst;
if(src.channels()>2)
{
cvtColor(src, dst, COLOR_BGR2GRAY);
}
labels = Mat::zeros(src.size(), CV_32S);
stats = Mat::zeros(src.size(), CV_32S);
centroids= Mat::zeros(src.size(), CV_32F);
//在进行二值化之前进行稍微的模糊效果会更好
GaussianBlur(dst, dst, Size(0, 0), 3);
namedWindow("模糊", WINDOW_FREERATIO);
imshow("模糊", dst);
//二值化,联通组件需要背景是黑色
threshold(dst, dst, 0, 255, THRESH_BINARY | cv::THRESH_OTSU);
namedWindow("二值化", WINDOW_FREERATIO);
imshow("二值化", dst);
int labelCount = connectedComponentsWithStats(dst, labels, stats, centroids, 8, CV_32S, CCL_DEFAULT);
for (int i = 1; i < labelCount; ++i)
{
//获得轮廓的中心
double cx = centroids.at<double>(i, 0);
double cy = centroids.at<double>(i, 1);
//画出圆
circle(src, Point(cx, cy), 10, Scalar(0, 0, 255), 2);
//获得外接矩形
int x = stats.at<int>(i, CC_STAT_LEFT);
int y = stats.at<int>(i, CC_STAT_TOP);
int h = stats.at<int>(i, CC_STAT_HEIGHT);
int w = stats.at<int>(i, CC_STAT_WIDTH);
//绘制外界矩形
Rect rect(Point(x, y), Size(w, h));
rectangle(src, rect, Scalar(0, 255, 0),2);
}
namedWindow("结果图像", WINDOW_FREERATIO);
imshow("结果图像", src);
}
Moment HuMoment 集合矩与Hu矩
Moments moments( InputArray array, bool binaryImage = false );
返回值:Moments类型数据
array:输入图像 黑色背景的二值图像
binaryImage :输出的图像是否为二值图像
void HuMoments( const Moments& m, OutputArray hu );
返回值:空
m:几何矩
hu输出的结果 Hu矩
matchShapes 形状匹配
double matchShapes( InputArray contour1, InputArray contour2,
int method, double parameter );
返回值:两个形状的相似度
contour1:Hu矩
contour2:Hu矩
method:计算两个Hu矩的方法
parmeter:目前还不支持 直接传入0
例子: 进行图像匹配
//发现轮廓信息 并传回轮廓信息
void findContour(Mat src, vector<vector<Point>> &contour)
{
Mat dst;
if (src.channels() >= 2)
{
cvtColor(src, dst, COLOR_BGR2GRAY);
}
//进行高斯模糊
GaussianBlur(dst, dst, Size(3, 3), 0);
//二值化
threshold(dst, dst, 0, 255, THRESH_BINARY|THRESH_OTSU );
vector<Vec4i> hierarchy;
//发现图形轮廓
findContours(dst, contour, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
}
void myContourMatch(Mat &src, Mat &src1)
{
//记录轮廓信息
vector<vector<Point>> contour1;
vector<vector<Point>> contour2;
findContour(src, contour1);
findContour(src1, contour2);
//计算几何矩
Moments mmt = moments(contour1[0], true);
Mat hu1;
//计算hu矩
HuMoments(mmt, hu1);
for (int i = 0; i < contour2.size(); ++i)
{
Mat hu2;
HuMoments(moments(contour2[i], true), hu2);
//计算两个Hu矩之差 图像匹配
double dist= matchShapes(hu1,hu2,CONTOURS_MATCH_I1,0);
cout << "图片的距离" << dist << endl;
if(dist<1)
{
Rect box = boundingRect(contour2[i]);
rectangle(src1, box, Scalar(0, 0, 255), 1);
}
}
imshow("结果", src1);
}
HoughLines , HoughLinesP 霍夫直线检测
void HoughLines( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double srn = 0, double stn = 0,
double min_theta = 0, double max_theta = CV_PI );
返回值:空
image: 二值化图像
line:输出点的集合
rho:以rho为单位的半径进行检测
thrta:以theta为单位的角度进行检测
threshold: 累计阈值参数
srn::对于多尺度的霍夫变换,这是第三个参数进步尺寸rho的除数距离
stn:对于多尺度的霍夫变换,srn表示第四个参数进步尺寸的单位角度theta的除数距离
void HoughLinesP( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double minLineLength = 0, double maxLineGap = 0 );
返回值:空
image:输入二值图像
lines:点的集合 类型为vector<Vec4f>
threshold:累加值,只有累加值达到threshold才认为是直线
minLineLength : 检测到的线段最小长度
maxLineGap :两条线段间隔大于 maxLineGap 认为是两条线段
例子:检测直线
void Demo::myHoughLines(Mat &src)
{
Mat dst;
if (src.channels() >= 2)
{
cvtColor(src, dst, COLOR_BGR2GRAY);
}
threshold(dst, dst, 0, 255, THRESH_OTSU | cv::THRESH_BINARY);
namedWindow("二值", WINDOW_FREERATIO);
imshow("二值", src);
//记录点的信息 每一个lines有三个值都是浮点数类型
//第一个代表rho半径
//第二个代表theta角度
//第三个代表累加值
vector<Vec3f> lines;
HoughLines(dst, lines, 1, CV_PI / 180, 100, 0, 0);
for (int i = 0; i < lines.size(); ++i)
{
double rho = lines[i][0]; //半径 rho
double theta = lines[i][1]; //角度
double acc = lines[i][2];//累加值
cout << "rho " << rho << " theta " << theta << " acc " << acc << endl;
double cosX = cos(theta);
double sinX = sin(theta);
Point point1, point2;
double x0=rho * cosX;
double y0 = rho * sinX;
point1.x = cvRound(x0 + 1000 * (-sinX));
point1.y = cvRound(y0 + 1000 * ( cosX));
point2.x = cvRound(x0 - 1000 * (-sinX));
point2.y = cvRound(y0 - 1000 * ( cosX));
double angle = round((theta / CV_PI) * 180);
cout << "angle " << angle << endl;
if (angle == 90)
{//水平
line(src, point1, point2, Scalar(0, 255, 0), 4);
} else if (angle == 0)
{//垂直
line(src, point1, point2, Scalar(255, 0, 0), 4);
} else
{
line(src, point1, point2, Scalar(0, 0, 255), 4);
}
}
imshow("jieguo", src);
//HoughLinesP检测线段
Mat dst;
Canny(src, dst, 50, 80, 3);
vector<Vec4f> lines;
HoughLinesP(dst, lines, 1, CV_PI / 180, 100, 50, 30);
Mat result = Mat::zeros(src.size(), src.type());
for (int i = 0; i < lines.size(); ++i)
{
line(result, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(0, 0, 255), 1);
}
imshow("结果", result);
}
HoughCircles 霍夫圆检测
void HoughCircles( InputArray image, OutputArray circles,
int method, double dp, double minDist,
double param1 = 100, double param2 = 100,
int minRadius = 0, int maxRadius = 0 );
返回值:空
image:输入图像 灰度图像
circles:输出的圆心和半径集合vector<Vec3f> 第一个和第二个为圆心坐标 第三个为半径
dp: 提升这个值会使检测圆的能力大大大增强 为第一阶段所使用的霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半,以此类推;
minDist:两个圆心之间的最小距离,这个值太小可能会检测出重复的圆,太大可能导致检测不到圆
param1:Canny阈值的最大值 最小值为这个值得一半
param2: 检测到圆的累加值 只有大于这个数的才算是圆
minRadius:检测圆的最小半径
maxRadius:检测圆的最大半径
例子:检测所有的圆
void myHoughCircle(Mat &src){
Mat gray, dst;
cvtColor(src, gray, COLOR_BGR2GRAY);
vector<Vec3f> circles;
HoughCircles(gray,circles,HOUGH_GRADIENT,1.4,10,100,100,10,50);
for (int i = 0; i < circles.size(); ++i)
{
Point2f circleCenter(circles[i][0],circles[i][1]);
double r = circles[i][2];
circle(src, circleCenter, r, Scalar(0, 0, 255),2);
}
namedWindow("结果", WINDOW_FREERATIO);
imshow("结果", src);
}
erode And dilate 腐蚀和膨胀
腐蚀API
void erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
返回值:空
src:输入二值图像 以黑色为背景的二值图像
dst:腐蚀过后的结果图像
kernel:结构元素
anchor:锚定点的中心位置
iterations :腐蚀重复的次数 建议用小窗口多次腐蚀 比用大窗口一次腐蚀效率更高
borderType :边缘填充的方式
borderValue :边缘的颜色
腐蚀是黑色侵蚀二值图像白色的面积
膨胀API
void dilate( InputArray src, OutputArray dst, InputArray kernel,
Point anchor = Point(-1,-1), int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() );
返回值:空
src:输入的二值图像 以黑色为背景的二值图像
dst:膨胀过后的二值图像
kernel:结构元素
anchor:锚定点的中心位置
iterations :腐蚀重复的次数 建议用小窗口多次腐蚀 比用大窗口一次腐蚀效率更高
borderType :边缘填充的方式
borderValue :边缘的颜色
膨胀是扩张二值图像白色的面积
例子:消除图像中的噪声
void Demo::myErode(Mat &src)
{
Mat dst;
Mat binary;
Mat result = Mat::ones(src.size(), src.type());
result = Scalar(255, 255, 255);
if (src.channels() >= 2)
{
cvtColor(src, dst, COLOR_BGR2GRAY);
} else
{
dst = src.clone();
}
threshold(dst, binary, 0, 255, THRESH_BINARY_INV | cv::THRESH_OTSU);
namedWindow("二值", WINDOW_FREERATIO);
imshow("二值", binary);
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
erode(binary, dst, kernel, Point(-1, -1), 1, BORDER_DEFAULT);
namedWindow("腐蚀", WINDOW_FREERATIO);
imshow("腐蚀", dst);
dilate(dst,dst,kernel,Point(-1,-1),1,BORDER_DEFAULT);
namedWindow("膨胀", WINDOW_FREERATIO);
imshow("膨胀", dst);
src.copyTo(result, dst);
namedWindow("结果", WINDOW_FREERATIO);
imshow("结果", result);
}
形态学基本梯度,内梯度,外梯度
基本梯度:膨胀减去腐蚀之后的结果
内梯度:原图减去腐蚀之后的结果
外梯度:膨胀减去原图之后的结果
例子:形态学三种梯度
我们可以看出内梯度和外梯度提取边缘轮廓的效果更胜一筹
void Demo::morphologyOperation(Mat &src)
{
Mat dst;
Mat inside_gra, external_gra;
Mat gray;
if (src.channels() >= 2)
{
cvtColor(src, gray, COLOR_BGR2GRAY);
} else
{
dst = src.clone();
}
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(gray, dst, MORPH_GRADIENT, kernel, Point(-1, -1));
threshold(dst, dst, 0, 255, THRESH_BINARY|THRESH_OTSU);
namedWindow("基本梯度", WINDOW_FREERATIO);
imshow("基本梯度", dst);
// 内梯度
erode(gray, inside_gra, kernel, Point(-1, -1), 1);
subtract(gray, inside_gra, inside_gra);
threshold(inside_gra, inside_gra, 0, 255, THRESH_BINARY|THRESH_OTSU);
namedWindow("内梯度", WINDOW_FREERATIO);
imshow("内梯度", inside_gra);
//外梯度
dilate(gray, external_gra, kernel, Point(-1, -1), 1);
subtract(external_gra, gray, external_gra);
threshold(external_gra, external_gra, 0, 255, THRESH_BINARY|THRESH_OTSU);
namedWindow("外梯度", WINDOW_FREERATIO);
imshow("外梯度", inside_gra);
}
morphologyEx 形态学操作
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() );
返回值:空
dst:结果图像
op:形态学操作
kernel:结构元素
anchor:锚定点的中心
borderType:边缘填充类型
borderValue:边缘填充的颜色
op的类型
op | 意思 |
---|---|
MORPH_ERODE | 腐蚀 |
MORPH_DILATE | 膨胀 |
MORPH_OPEN | 开操作 |
MORPH_CLOSE | 闭操作 |
MORPH_GRADIENT | 形态学梯度 |
MORPH_TOPHAT | 顶帽操作 |
MORPH_BLACKHAT | 黑帽操作 |
MORPH_HITMISS | 击中击不中操作 |
开操作: 消除白色小点 去除噪声(先腐蚀 后膨胀)
闭操作:扩大白色小点:填充空洞(先膨胀后腐蚀)
顶帽: 提取微小的噪声(原图减去开操作)
黑帽:提取微小的噪声(闭操作减去原图)
击中击不中:用来提取指定的形状(通过指定元素结构)
例子:黑帽
Mat dst;
Mat inside_gra, external_gra;
Mat gray;
if (src.channels() >= 2)
{
cvtColor(src, gray, COLOR_BGR2GRAY);
} else
{
dst = src.clone();
}
//Size越大提取的噪点越大
threshold(gray, dst, 0, 255, THRESH_BINARY | THRESH_OTSU);
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(15, 15), Point(-1, -1));
// 黑帽 顶帽 击中击不中 二值图像效果更好
morphologyEx(dst, dst, MORPH_BLACKHAT, kernel, Point(-1, -1));
namedWindow("黑帽", WINDOW_FREERATIO);
imshow("黑帽", dst);
例子:顶帽
Mat dst;
Mat inside_gra, external_gra;
Mat gray;
if (src.channels() >= 2)
{
cvtColor(src, gray, COLOR_BGR2GRAY);
} else
{
dst = src.clone();
}
threshold(gray, dst, 0, 255, THRESH_BINARY | THRESH_OTSU);
//Size越小提取的提取的噪点越小
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3), Point(-1, -1));
// 黑帽 顶帽 击中击不中 二值图像效果更好
morphologyEx(dst, dst, MORPH_TOPHAT, kernel, Point(-1, -1));
namedWindow("顶帽", WINDOW_FREERATIO);
imshow("顶帽", dst);
例子:击中击不中 提取十字结
Mat dst;
Mat inside_gra, external_gra;
Mat gray;
if (src.channels() >= 2)
{
cvtColor(src, gray, COLOR_BGR2GRAY);
} else
{
dst = src.clone();
}
threshold(gray, dst, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
//Size越小提取的提取的噪点越小
Mat kernel = getStructuringElement(MORPH_CROSS, Size(13, 13), Point(-1, -1));
// 黑帽 顶帽 击中击不中 二值图像效果更好
morphologyEx(dst, dst, MORPH_HITMISS, kernel, Point(-1, -1));
namedWindow("击中击不中", WINDOW_FREERATIO);
imshow("击中击不中", dst);