問題描述:統計圖像中玉米粒的數目。主要解決的問題的是有玉米粒重疊部分,如何準確的統計出重疊玉米粒的數目。
思路描述:二值化處理+形態學圖像處理+距離變換+連通域計算
代碼
#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
結果