·问题描述
有一张图片,计算图片中种子的数量
主要需要解决的是如何将种子粘连的部分去掉,生成一个个独立的对象
·解决方案
1.二值化
首先进行二值分割
在进行对象计数时,推荐使用Triangle的方法来寻找阈值
2.形态学–膨胀操作
使用形态学的膨胀操作,可以细化图像对象之间的粘连区域但是对于一些粘连较强的部分,可能难以细化,可以留到后面解决
3.距离变换
距离变化可以找出各个对象的中心点,并且变现为亮点,有效找出各个对象
4.自适应阈值算法
根据图像不同区域亮度分布,计算其部分阈值,所以对于图像不同区域,能够自适应计算不同阈值,能够很好的检测到边缘信息,分离个目标区域
5.轮廓寻找及绘制
至此,各个图像已被分割。开始绘制轮廓,并输出对象个数,连通区域计数
·完整代码
#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/博客项目/项目图片/16.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
imshow("input_img", src);
namedWindow(output_win,WINDOW_AUTOSIZE);
//首先进行二值分割
//在进行对象计数时,推荐使用Triangle的方法来寻找阈值
cvtColor(src, gray_src, COLOR_BGR2GRAY);
threshold(gray_src, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
imshow("binary_img", binary);
//形态学操作
//使用形态学的膨胀操作,可以细化图像对象之间的粘连区域
//但是对于一些粘连较强的部分,可能难以细化,可以留到后面解决
Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
dilate(binary, binary, kernel, Point(-1, -1), 2);
imshow("dilate_img", binary);
//距离变换
//距离变化可以找出各个对象的中心点,并且变现为亮点,有效找出各个对象
Mat dist;
bitwise_not(binary, binary);
distanceTransform(binary, dist, CV_DIST_L2, 3);
//距离变换后要进行归一化操作,否则会有区域超越边界值
normalize(dist, dist, 0, 1.0, NORM_MINMAX);
imshow("dist_img", dist);
//再进行了距离变换后,便可以找到各个对象的最亮区域
//自适应阈值法
//根据图像不同区域亮度分布,计算其部分阈值,所以对于图像不同区域,能够自适应计算不同阈值
//能够很好的检测到边缘信息,分离个目标区域
Mat dist_8u;
dist.convertTo(dist_8u, CV_8U);//自适应阈值算法图片格式要是8u格式
adaptiveThreshold(dist_8u, dist_8u, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 85, 0.0);
//完成了自适应阈值法后,可以用膨胀操补上一些黑色部分
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(dist_8u, dist_8u, kernel, Point(-1, -1), 2);
imshow("dist-binary", dist_8u);
//至此,各个图像已被分割。开始绘制轮廓,并输出对象个数
//连通区域计数
//寻找轮廓
vector<vector<Point>> contours;
findContours(dist_8u, contours, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
//画出轮廓
Mat markers = Mat::zeros(src.size(), CV_8UC3);
RNG rng(12345);
int count = 0;
for (size_t i = 0; i < contours.size(); i++)
{
drawContours(markers, contours, static_cast<int>(i), Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), -1, 8, Mat());
imshow("Final result", markers);
count++;
}
cout<< count;
waitKey(0);
return 0;
}