C#+OpenCV实战(三)_玉米粒计数
/// <summary>
/// 标注物体 -物体计数标注
/// 比如玉米粒计数并标注每个玉米
/// </summary>
/// <param name="imgFile1"></param>
/// <returns>物体位置;数量=contours.Length</returns>
public static Point[][] ImageDetector_CountAndLabel(Mat srcMat, out Mat dstMat)
{
dstMat = new Mat();
srcMat.CopyTo(dstMat);
// 二值化操作
Mat grayimg = new Mat();
Cv2.CvtColor(srcMat, grayimg, ColorConversionCodes.BGR2GRAY);
Mat binaryImg = new Mat();
Cv2.Threshold(grayimg, binaryImg, 240, 255, ThresholdTypes.Binary);
// 腐蚀
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(15, 15));
Mat morhImage = new Mat();
Cv2.Dilate(binaryImg, morhImage, kernel, null, 2);
// 距离变换:用于二值化图像中的每一个非零点距自己最近的零点的距离,距离变换图像上越亮的点,代表了这一点距离零点的距离越远
Mat dist = new Mat();
Cv2.BitwiseNot(morhImage, morhImage);
// 计算物体之间的距离
Cv2.DistanceTransform(morhImage, dist, DistanceTypes.L1, DistanceTransformMasks.Mask3); // 曼哈顿距离,
Cv2.Normalize(dist, dist, 0, 1.0, NormTypes.MinMax); //范围在0~1之间
// 形态学处理
Mat morphImg = new Mat();
dist.ConvertTo(morphImg, MatType.CV_8U);
Cv2.Threshold(morphImg, morphImg, 0.99, 255, ThresholdTypes.Binary); //上图像素值在0~1之间
kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(7, 3), new Point(-1, -1));
Cv2.MorphologyEx(morphImg, morphImg, MorphTypes.Open, kernel); //开操作
// 找到种子的轮廓区域
/*
* 找轮廓(输入图像,out 轮廓集合,out 级别,轮廓检索模式,近似法,偏移量)
* 输入图像:单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;
* 轮廓集合:contours
* 历史轮廓:hierarchy:0:后一个轮廓,1:前一个轮廓,2:父轮廓,3:内嵌轮廓
* 轮廓检索模式:轮廓的检索模式
* 取值一:CV_RETR_EXTERNAL 只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
* 取值二:CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1,具体下文会讲到
* 取值三:CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层
* 取值四:CV_RETR_TREE 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
* 近似方法:轮廓的近似方法
* 取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内
* 取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留
* 取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
* 偏移量:Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,且Point可以是负值。不填为默认不偏移Point()
*/
Cv2.FindContours(morphImg, out Point[][] contours, out HierarchyIndex[] hierarchly, RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));
// 标识位置
for (int i = 0; i < contours.Length; i++)
{
Rect rect = Cv2.BoundingRect(contours[i]);
int x = rect.X;
int y = rect.Y;
int w = rect.Width;
int h = rect.Height;
Cv2.Circle(dstMat, x + w / 2, y + h / 2, 20, new Scalar(0, 0, 255), -1);
if (i >= 9)
{
Cv2.PutText(dstMat, (i + 1).ToString(), new Point(x + w / 2 - 18, y + h / 2 + 8), HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 255, 0), 2);
}
else
{
Cv2.PutText(dstMat, (i + 1).ToString(), new Point(x + w / 2 - 8, y + h / 2 + 8), HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 255, 0), 2);
}
}
return contours;
}
本文来自博客园,作者:꧁执笔小白꧂,转载请注明原文链接:https://www.cnblogs.com/qq2806933146xiaobai/p/18295839