文章目录
- 预计效果
- 效果演示
- 实现过程
- 程序
- 参数调试笔记
1.预计效果
能够从杂乱背景的鸡窝中找出鸡蛋并且计算鸡蛋的数量。
2.效果演示
3. 实现过程
-
blur均值滤波,让画面变得平滑一些。
-
canny边缘检测,将边缘二值化展示出来。
-
morphologyEx形态学闭操作,调整kernel卷积和大小,消除一些比较小的黑块,这样留下来的都是一些较大大的黑块。
4.findContours找出所有的闭合轮廓。
5.可以看出鸡蛋的伦托和噪点的轮廓大小有明显差别,通过限定轮廓的大小,来判断出那些轮廓属于鸡蛋,从而框选出鸡蛋并进行计数。
4. 程序
void Demo::egg_count()
{
namedWindow("egg", WINDOW_NORMAL);
Mat src = imread("D:/DESKTOP/picture/egg.jpg");
Mat src1;
blur(src, src1, Size(5, 5),Point(-1,-1),BORDER_DEFAULT);//均值滤波
cvtColor(src1, src1, COLOR_BGR2GRAY);
Canny(src1, src1, 25, 35, 3, false);//canny边缘检测
imshow("边缘", src1);
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(5, 5), Point(-1, -1));//椭圆形5x5内核
morphologyEx(src1, src1, MORPH_CLOSE, kernel, Point(-1, -1), 3);//形态学闭操作
imshow("形态学闭操作", src1);
vector<vector<Point>> contours;
vector<Vec4i> hireachy;
findContours(src1, contours, hireachy, RETR_TREE, CHAIN_APPROX_NONE, Point());//找出所有轮廓
cvtColor(src1, src1, COLOR_GRAY2BGR);
int egg = 0;
for (int i = 0; i < contours.size(); i++)//通过大小限定计算出鸡蛋的轮廓
{
Rect rect = boundingRect(contours[i]);
if (rect.width > src1.cols/15 && rect.width < src1.cols - 20&&rect.height>src1.rows/15) {
drawContours(src, contours, static_cast<int>(i), Scalar(0, 0, 255), 2, 8, hireachy, 0, Point());
egg++;
}
}
putText(src, "eggs:"+to_string(egg),Point(0,100), FONT_HERSHEY_PLAIN, 5, Scalar(0, 255, 255), 2, 8, false);
imshow("egg", src);
waitKey(0);
}
5.参数调试笔记
- 第一步blur滤波可以减少canny检测出来的边缘的数量,如图是没有家均值滤波的:
2.canny边缘检测的两个阈值设置,如果过高,可能会导致连鸡蛋都检测不出来,过低会导致边缘过多。
3.kernel这里选用的是椭圆内核,出来的闭合曲线也有点椭圆的形状了。内核的大小不要选太小了,不然会检测出来过多的闭合曲线(虽然通过最后的大小限定也能过滤掉)。
4.最后的鸡蛋大小要选着一个合适的范围,能够包括鸡蛋,也能排除噪点。