OpenCV中文网站

 找回密码
 立即注册
搜索
热搜: 安装 配置
查看: 5473|回复: 1

OpenCV Blob分析-基于FindContours联通区域分析

[复制链接]
发表于 2019-5-23 19:42:08 | 显示全部楼层 |阅读模式
本文是一个较完整的Blob分析思路解说,是用OpenCvSharp联合c#编写的。
思路如下:
1、对图像进行二值化
2、设定ROI
3、腐蚀、膨胀(可选)
4、边缘提取(有区分是否需填充孔洞)
5、进行筛选
本来是要提供图片的,但发现上传不方便就算了,可以去我文库看完整版:file:///C:/Users/Administrator/Desktop/%E5%9B%BE%E7%89%871.png

部分源代码解说:
InputImage来自输入的要处理的图片。
gray_min、gray_max二值化的上下阈值
1、对图像进行二值化(根据二值化的上下阈值来判定二值化方式)
Mat binaryImage = new Mat(InputImage.Size(), MatType.CV_8UC1, Scalar.Black);
            if (gray_min != 0 && gray_max != 255)
            {
                binaryImage = InputImage.Threshold(gray_min, 255, ThresholdTypes.Binary);
                Mat binaryImage2 = InputImage.Threshold(gray_max, 255, ThresholdTypes.BinaryInv);
                Mat binaryImage3 = new Mat(InputImage.Size(), MatType.CV_8UC1, Scalar.Black);
                binaryImage.CopyTo(binaryImage3, binaryImage2);
                binaryImage = binaryImage3.Clone();
                binaryImage2.Dispose();
                binaryImage3.Dispose();
            }
            else
            {
                if (gray_min == 0) binaryImage = InputImage.Threshold(gray_max, 255, ThresholdTypes.BinaryInv);
                if (gray_max == 255) binaryImage = InputImage.Threshold(gray_min, 255, ThresholdTypes.Binary);
            }
            Mat binaryImage1 = new Mat(InputImage.Size(), MatType.CV_8UC1, Scalar.Black); 2、设定ROI(Mask就是ROI感兴趣区域)
binaryImage.CopyTo(binaryImage1, Mask);
3、腐蚀、膨胀(可选)
if (erosion_dilation == "腐蚀")
                {
                    Cv2.Erode(binaryImage1, binaryImage1, element);
                }
                else
                {
                    Cv2.Dilate(binaryImage1, binaryImage1, element);
                }
4、边缘提取(有区分是否需填充孔洞)
if (fill_up_flag == true)
            {
                Cv2.FindContours(binaryImage1, out contours, hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
            }
            else
            {
                Cv2.FindContours(binaryImage1, out contours, hierarchy, RetrievalModes.CComp, ContourApproximationModes.ApproxSimple);
            }
5、进行筛选
Mat uu = hierarchy.GetMat();

            // 筛选那些面积小的
            List<MyCenter> centers = new List<MyCenter>();
            List<RotatedRect> regions = new List<RotatedRect>();

            var detectorParams = new SimpleBlobDetector.Params
            {
                MinDistBetweenBlobs = 10, // 10 pixels between blobs
                MinRepeatability = 1,

                MinThreshold = 0,
                MaxThreshold = 128,
                ThresholdStep = 2,

                FilterByArea = area_bool,
                MinArea = area_min, // 10 pixels squared
                MaxArea = area_max,

                //圆度
                FilterByCircularity = circularity_bool,
                MinCircularity = circularity_min,
                MaxCircularity = circularity_max,

                // 凸包形状分析 - 过滤凹包
                FilterByConvexity = false,
                //FilterByConvexity = true,
                MinConvexity = 0.001f,
                MaxConvexity = 10,

                FilterByInertia = false,
                //FilterByInertia = true,
                MinInertiaRatio = 0.001f,

                FilterByColor = false,
                //FilterByColor = true,
                BlobColor = 255 // to extract light blobs

            };

            MyCenter center;

            int j = 0;
            Vec4i value;
            Mat cnt = new Mat();
            foreach (Mat cnt0 in contours)
            {
                value = uu.Get<Vec4i>(0, j);
                j++;
                //int i = hierarchy;
                // 根据轮廓面积进行筛选      
                if (value[3] != -1)
                {
                    cnt = contours[value[3]];
                }
                else
                {
                    cnt = cnt0;
                }

                center.confidence = 1;
                Moments moms = Cv2.Moments(cnt);
                if (detectorParams.FilterByArea)    //斑点面积的限制
                {
                    double area = moms.M00;    //零阶矩即为二值图像的面积
                    //如果面积超出了设定的范围,则不再考虑该斑点
                    if (area < detectorParams.MinArea || area >= detectorParams.MaxArea)
                        continue;
                }

                if (detectorParams.FilterByCircularity)    //斑点圆度的限制
                {
                    double area = moms.M00;    //得到斑点的面积
                    //计算斑点的周长
                    double perimeter = Cv2.ArcLength(cnt, true);
                    //由公式3得到斑点的圆度
                    double ratio = 4 * Cv2.PI * area / (perimeter * perimeter);
                    //如果圆度超出了设定的范围,则不再考虑该斑点
                    if (ratio < detectorParams.MinCircularity || ratio >= detectorParams.MaxCircularity)
                        continue;
                }

                if (detectorParams.FilterByInertia)    //斑点惯性率的限制
                {

                    //计算公式13中最右侧等式中的开根号的值
                    double denominator = Math.Sqrt(Math.Pow(2 * moms.Mu11, 2) + Math.Pow(moms.Mu20 - moms.Mu02, 2));
                    const double eps = 1e-2;    //定义一个极小值
                    double ratio;
                    if (denominator > eps)
                    {
                        //cosmin和sinmin用于计算图像协方差矩阵中较小的那个特征值λ2
                        double cosmin = (moms.Mu20 - moms.Mu02) / denominator;
                        double sinmin = 2 * moms.Mu11 / denominator;
                        //cosmin和sinmin用于计算图像协方差矩阵中较大的那个特征值λ1
                        double cosmax = -cosmin;
                        double sinmax = -sinmin;
                        //imin为λ2乘以零阶中心矩μ00
                        double imin = 0.5 * (moms.Mu20 + moms.Mu02) - 0.5 * (moms.Mu20 - moms.Mu02) * cosmin - moms.Mu11 * sinmin;
                        //imax为λ1乘以零阶中心矩μ00
                        double imax = 0.5 * (moms.Mu20 + moms.Mu02) - 0.5 * (moms.Mu20 - moms.Mu02) * cosmax - moms.Mu11 * sinmax;
                        ratio = imin / imax;    //得到斑点的惯性率
                    }
                    else
                    {
                        ratio = 1;    //直接设置为1,即为圆
                    }
                    //如果惯性率超出了设定的范围,则不再考虑该斑点
                    if (ratio < detectorParams.MinInertiaRatio || ratio >= detectorParams.MaxInertiaRatio)
                        continue;
                    //斑点中心的权值定义为惯性率的平方
                    center.confidence = ratio * ratio;
                }

                if (detectorParams.FilterByConvexity)    //斑点凸度的限制
                {
                    Mat hull = new Mat();  //定义凸壳变量
                    //调用convexHull函数,得到该斑点的凸壳
                    Cv2.ConvexHull(cnt, hull);
                    //分别得到斑点和凸壳的面积,contourArea函数本质上也是求图像的零阶矩
                    double area = Cv2.ContourArea(cnt);
                    double hullArea = Cv2.ContourArea(hull);
                    double ratio = area / hullArea;    //公式5,计算斑点的凸度
                    //如果凸度超出了设定的范围,则不再考虑该斑点
                    if (ratio < detectorParams.MinConvexity || ratio >= detectorParams.MaxConvexity)
                        continue;
                }

                //根据公式7,计算斑点的质心
                center.location = new Point2d(moms.M10 / moms.M00, moms.M01 / moms.M00);

                // 根据轮廓近似进行筛选,作用很小
                double epsilon = 0.001 * Cv2.ArcLength(cnt, true);
                Mat approx = new Mat();
                Cv2.ApproxPolyDP(cnt, approx, epsilon, true);

                // 根据最小矩形进行筛选,该矩形可能有方向
                RotatedRect rect = Cv2.MinAreaRect(approx);                        
                if (width_bool)
                {
                    int width = rect.BoundingRect().Width;
                    if (width < width_min || width > width_max) continue;
                }
                if (height_bool)
                {
                    int height = rect.BoundingRect().Height;
                    if (height < height_min || height > height_max) continue;
                }
                //根据质心来判断颜色不合理,但是我觉得这个不合理就把它禁用了
                centers.Add(center);
                outcontours.Add(cnt0);
            }





回复

使用道具 举报

 楼主| 发表于 2019-5-23 19:44:11 | 显示全部楼层
本帖最后由 千年傲冰 于 2019-5-23 19:51 编辑

可到我的百度文库看完整版:wenku.baidu.com/view/19660440370cba1aa8114431b90d6c85ec3a88fc
同时也给大家推荐一本书:《OpenCV计算机视觉编程攻略(第3版)》高清中文版PDF+英文版PDF+源代码
pan.baidu.com/s/10R9C_Mv638DOk8z-X_p2jg 提取码:akdy
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|OpenCV中文网站

GMT+8, 2024-4-19 09:46 , Processed in 0.009685 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表