案例背景
照片是来自太空望远镜的星云图像,科学家想知道它的面积和周长
方法步骤
- 图像二值化
- 形态学操作
- 轮廓查找
- 计算参数
代码
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "case5.png"
int main(void)
{
Mat src,gray_src;
//获取完整的图片路径及名称
string pic = string(PIC_PATH)+string(PIC_NAME);
//打印图片路径
cout << "pic path is :"<<pic<<endl;
//读取图片
src = imread(pic);
//判断图片是否存在
if(src.empty())
{
cout<<"pic is not exist!!!!"<<endl;
return -1;
}
//显示图片
namedWindow("src pic",WINDOW_AUTOSIZE);
imshow("src pic",src);
//图片转换为灰度 直接二值化 图片主体存在许多噪点不连续 直接使用开闭操作消除 容易把主体褶皱部分拟合掉
//测量误差比较大 这里采用高斯模糊解决噪点问题
cvtColor(src,gray_src,COLOR_BGR2GRAY);
GaussianBlur(gray_src,gray_src,Size(15,15),0,0);
imshow("GaussianBlur",gray_src);
//图片与背景有巨大的反差 先将图片二值化 方便提取主体部分
//二值化宏采用THRESH_TRIANGLE,未采用THRESH_OTSU是因为THRESH_OTSU效果不理想 噪点较多
//图片背景色占比较多 直方图属于单峰 采用THRESH_TRIANGLE 效果比较好
Mat binaryimg;
threshold(gray_src,binaryimg,0,255,THRESH_BINARY | THRESH_TRIANGLE);
imshow("binaryimg",binaryimg);
//轮廓
vector<vector<Point>> contours;
findContours(binaryimg,contours,RETR_TREE,CHAIN_APPROX_SIMPLE);
Mat contouimg = Mat::zeros(src.size(),src.type());
for(size_t i=0;i<contours.size();i++)
{
//绘制最大的轮廓
Rect rect = boundingRect(contours[i]);
if(rect.width>src.cols/2 && rect.height >src.rows/2)
{
drawContours(contouimg,contours,i,Scalar(0,0,255),1);
double length = arcLength(contours[i],true);
double area = contourArea(contours[i]);
cout << "长度是 "<< length <<endl;
cout << "面积是 "<< area<<endl;
}
}
imshow("contouimg",contouimg);
waitKey(0);
destroyAllWindows();
return 0;
}