OpenCV - 迭代二进制图像中的每个 blob 并将其用作掩码 [英] OpenCV - iterate over each blob in a binary image and use it as mask

查看:43
本文介绍了OpenCV - 迭代二进制图像中的每个 blob 并将其用作掩码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个二值图像和一个相同大小的彩色图像.我需要迭代二进制图像的每个 blob(白色像素块)并将其用作掩码,然后从彩色图像中找到该 blob 区域的平均颜色.

I have a binary image and a color image of the same size. I need to iterate each blob (white pixel blocks) of the binary image and use it as a mask and find the mean color of this blob region from the color image.

我试过了:

HierarchyIndex[] hierarchy;
Point[][] contours;
binaryImage.FindContours(out contours, out hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxNone);

    using (Mat mask = Mat.Zeros(matColor.Size(), MatType.CV_8UC1))
        foreach (var bl in contours)
            if (Cv2.ContourArea(bl) > 5)
            {
                mask.DrawContour(bl, Scalar.White, -1);                                                    
                Rect rect = Cv2.BoundingRect(bl);
                Scalar mean = Cv2.Mean(colorImage[rect], mask[rect]);

                mask.DrawContour(bl, Scalar.Black, -1);
            }

适用于没有孔的斑点.但是,在我的情况下,我有许多斑点区域具有影响均值计算的巨大孔洞.

which works for the blobs not having holes. However in my case I have many blob regions having huge holes that affects the mean calculation.

我不知道如何使用层次结构信息来解决它;或使用其他方法.

I couldn't figure it out how to solve it using the hierarchy info; or with another approach.

(我的代码适用于 OpenCVSharp,但可以使用任何其他包装器或语言回答.)

(My code is for OpenCVSharp but answer in any other wrapper or language is wellcome.)

我添加了一个示例图像.交通标志部分是问题.

I've added an example image. The traffic signs part is the problem.

其实我觉得我已经用这个方法解决了这个问题:

Actually I think I have solved this problem with this method:

using PLine = List<Point>;
using Shape = List<List<Point>>;
internal static IEnumerable<Tuple<PLine, Shape>> FindContoursWithHoles(this Mat mat)
        {
            Point[][] contours;
            HierarchyIndex[] hierarchy;
            mat.FindContours(out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone);

            Dictionary<int, bool> dic = new Dictionary<int, bool>();
            for (int i = 0; i < contours.Length; i++)
                if (hierarchy[i].Parent < 0)
                    dic[i] = true;

            bool ok = false;
            while (!ok)
            {
                ok = true;
                for (int i = 0; i < contours.Length; i++)
                    if (dic.ContainsKey(i))
                    {
                        bool isParent = dic[i];
                        var hi = hierarchy[i];
                        if (hi.Parent >= 0) dic[hi.Parent] = (!isParent);
                        if (hi.Child >= 0) dic[hi.Child] = (!isParent);
                        while (hi.Next >= 0)
                        {
                            dic[hi.Next] = isParent;
                            hi = hierarchy[hi.Next];
                            if (hi.Parent >= 0) dic[hi.Parent] = (!isParent);
                            if (hi.Child >= 0) dic[hi.Child] = (!isParent);
                        }
                        hi = hierarchy[i];
                        while (hi.Previous >= 0)
                        {
                            dic[hi.Previous] = isParent;
                            hi = hierarchy[hi.Previous];
                            if (hi.Parent >= 0) dic[hi.Parent] = (!isParent);
                            if (hi.Child >= 0) dic[hi.Child] = (!isParent);
                        }
                    }
                    else
                        ok = false;
            }
            foreach (int i in dic.Keys.Where(a => dic[a]))
            {
                PLine pl = contours[i].ToList();
                Shape childs = new Shape();
                var hiParent = hierarchy[i];
                if (hiParent.Child >= 0)
                {
                    childs.Add(contours[hiParent.Child].ToList());
                    var hi = hierarchy[hiParent.Child];
                    while (hi.Next >= 0)
                    {
                        childs.Add(contours[hi.Next].ToList());
                        hi = hierarchy[hi.Next];
                    }
                    hi = hierarchy[hiParent.Child];
                    while (hi.Previous >= 0)
                    {
                        childs.Add(contours[hi.Previous].ToList());
                        hi = hierarchy[hi.Previous];
                    }
                }

                yield return Tuple.Create(pl, childs);
            }
        }

通过将孔绘制为黑色,我们可以将每个斑点用作单个掩码:

By drawing the holes as black, we can use each blob as a single mask:

var blobContours = blobs.FindContoursWithHoles().ToList();
using (Mat mask = Mat.Zeros(mat0.Size(), MatType.CV_8UC1))
    for (int i = 0; i < blobContours.Count; i++)
    {
        var tu = blobContours[i];
        var bl = tu.Item1;
        if (Cv2.ContourArea(bl) > 100)
        {
            mask.DrawContour(bl, Scalar.White, -1);
            foreach (var child in tu.Item2)
                mask.DrawContour(child, Scalar.Black, -1);
            Rect rect = Cv2.BoundingRect(bl);
            Scalar mean = Cv2.Mean(mat0[rect], mask[rect]);
        }
    }

我认为应该有更简单的方法.

I think there should be an easier way.

还有一个问题.在某些情况下,标志的单个红色部分(它是一个单独的白色斑点)不是圆外的父项和圆内的子项,而是外部的大父级轮廓,两个圆作为子项(即另一个圆内的孔)孔,形成一个单独的 blob,它不是作为父对象找到的).是的,它在层次上是正确的,但对我没有帮助.我希望我能说清楚,对不起我的英语.

And yet there is another problem. In some cases, an individual red part of the sign (which is a seperate white blob) does not found as a parent outside circle and a child inside circle, but a large parent contour outside with two circles as children (ie. hole inside another hole, makes a seperate blob which is not found as a parent). Yes it is hierarchically correct but does not help me. I hope I could make my self clear, sorry for my English.

推荐答案

@Miki 非常感谢.我能够使用 ConnectedComponents 实现我想要的.它简单快捷:

@Miki thank you very much. I was able to achieve what I want using ConnectedComponents. Its simple and fast:

var cc = Cv2.ConnectedComponentsEx(binaryImage, PixelConnectivity.Connectivity8);
foreach (var bl in cc.Blobs)
    using (Mat mask = new Mat())
    {
        cc.FilterByBlob(binaryImage, mask, bl);
        Rect rect = bl.Rect;
        Scalar mean = Cv2.Mean(colorImage[rect], mask[rect]);
    }

这篇关于OpenCV - 迭代二进制图像中的每个 blob 并将其用作掩码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆