问题描述:统计图像中玉米粒的数目。主要解决的问题的是有玉米粒重叠部分,如何准确的统计出重叠玉米粒的数目。
思路描述:二值化处理+形态学图像处理+距离变换+连通域计算
代码
#include<iostream>
#include<opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
//加载图像
Mat src = imread("4.jpg");
if (src.empty())
{
cout << "no image!" << endl;
return -1;
}
imshow("src", src);
//二值化
Mat gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow("gray", gray);
threshold(gray, binary, 0, 255, THRESH_TRIANGLE);
imshow("binary", binary);
//图像形态学操作
Mat kern1 = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1,-1));
morphologyEx(binary, binary, MORPH_DILATE, kern1,Point(-1,-1),3);
imshow("dilate", binary);
//距离变换
Mat dist;
bitwise_not(binary, binary);//将白色背景变黑
imshow("not", binary);
distanceTransform(binary, dist, DIST_L2, 3);
normalize(dist, dist, 0.0, 1.0, NORM_MINMAX);
dist.convertTo(dist, CV_8UC1);
imshow("dist", dist);
//阈值分割
Mat img;
//threshold(dist, img, 0, 255, THRESH_BINARY | THRESH_OTSU);
adaptiveThreshold(dist, img, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 85, 0.0);
imshow("img", img);
//腐蚀操作
morphologyEx(img, img, MORPH_DILATE, kern1, Point(-1,-1),1);
imshow("dilate-img", img);
//寻找连通域
vector<vector<Point>>contours;
findContours(img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
Mat mask = Mat::zeros(src.size(), CV_8UC3);
for (size_t i = 0; i < contours.size(); i++)
{
drawContours(mask, contours, static_cast<int>(i), Scalar(0, 0, 255), -1, 8);
}
cout << "玉米粒个数:" << contours.size() << endl;
imshow("result", mask);
waitKey(0);
return 0;
}
代码解释:
(1)二值化的方式为什么使用threshold_triangle,因为对于单峰图像来说,使用这种分割模式其效果更好,简单来说就是直接看上去就有一种颜色。
(2)二值化后为什么需要进行多次膨胀处理,这是为了加强玉米粒重叠部分的边缘联系,便于后续的分割操作。
(3)距离变换是统计图像中像素点到距它最近的像素值为0的距离,而像素值为0表现出来就是黑色,对于这幅图像来说其二值化后的背景是白色,这样的白色背景对于距离变换会产生影响,需要将背景变为黑色,目标变为白色,从而达到计算目标到边界的距离。
(4)在距离变换后,计算的结果有大有小,需要进行归一化操作,并且产生的矩阵是CV_32F类型的,而opencv的imshow函数只支持显示8通道或者16通道类型的图像,因此需要使用converTo函数进行数据转换一下。
(5)自适应阈值分割比较适合于进行局部分割,案例中的二值图像需要进行局部阈值分割可以较好地将重叠部分的玉米粒分割出来,blocksize的大小最好是在图像尺寸的1/4~1/6之间。
(6)自适应阈值分割后,需要在使用一次膨胀处理,强化一下每一个玉米粒的联系,防止因为局部分割使得玉米粒出现断裂。
(7)这里只需要检测每一个玉米粒的最外侧轮廓就行了,关于findContours函数的使用说明https://www.cnblogs.com/GaloisY/p/11062065.html
结果