问题描述:
给出一张用太空望远镜检测的星云图片,测算它的面积与周长
注意事项:
我们可能一开始想到的是二值化的方法,但是在二值化后,我们会得到下图,发现结果并不理想,很难取得轮廓
或许可以通过膨胀操作将黑色部分填上,但是白色区域也势必会扩大,这样的话,测量的数据也不会准确。
为了解决以上问题,我们可以先使用高斯模糊来降低噪点的影响,这样二值化后的图像也会相对比较好
因为原图像的直方图会有单峰,因此可以尝试triangle的二值化阈值选择方法。
代码:
#include<opencv2/opencv.hpp>
#include<math.h>
#include<iostream>
using namespace cv;
using namespace std;
Mat src2;
Mat src,dst,gray_src,binary;
const char* output_win = "output_img";
RNG rng(12345);
int threshold_v = 100;
int threshold_max = 255;
int main(int argc, char** argv) {
src = imread("C:/Users/18929/Desktop/博客项目/项目图片/18.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
imshow("input_img", src);
namedWindow(output_win,WINDOW_AUTOSIZE);
//首先高斯模糊去除一些噪点
Mat blurImage;
GaussianBlur(src, blurImage, Size(15, 15), 0, 0);
imshow("blur", blurImage);
//二值化
//因为原图像的直方图会有单峰(光线变化),因此可以尝试triangle的二值化阈值选择方法
Mat gray_src, binary;
cvtColor(blurImage, gray_src,COLOR_BGR2GRAY);
threshold(gray_src, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
imshow("binary", binary);
//形态学闭操作
//闭操作为先膨胀,后腐蚀,既可以填掉小黑点,又可以减少白色扩充效果,更好的提取轮廓
Mat morphImage;
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(binary, morphImage, MORPH_CLOSE, kernel, Point(-1, -1), 2);
imshow("morphology", morphImage);
//获取最大轮廓
vector<vector<Point>> contours;
vector<Vec4i> hireachy;
findContours(morphImage, contours, hireachy, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE,Point());
Mat connImage = Mat::zeros(src.size(), CV_8UC3);
for (size_t i = 0; i < contours.size(); i++)
{
Rect rect = boundingRect(contours[i]);
//将小点和外边框排除
if (rect.width < src.cols / 2) continue;
if (rect.width > (src.cols - 20)) continue;
double area = contourArea(contours[i]);
double len = arcLength(contours[i],true);
drawContours(connImage, contours, static_cast<int>(i), Scalar(0, 0, 255), 1, 8, hireachy);
printf("area is :%f\n", area);
printf("length is :%f\n", len);
}
imshow("contours", connImage);
waitKey(0);
return 0;
}