【发布时间】:2017-03-03 13:50:22
【问题描述】:
我有一个二值图像和一个相同大小的彩色图像。我需要迭代二进制图像的每个 blob(白色像素块)并将其用作掩码,并从彩色图像中找到该 blob 区域的平均颜色。
我试过了:
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);
}
这适用于没有孔的斑点。但是,在我的情况下,我有许多具有影响平均计算的大洞的 blob 区域。
我不知道如何使用层次结构信息解决它;或其他方法。
(我的代码适用于 OpenCVSharp,但欢迎使用任何其他包装器或语言回答。)
其实我想我已经用这个方法解决了这个问题:
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);
}
}
通过将孔绘制为黑色,我们可以将每个斑点用作单个蒙版:
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]);
}
}
我认为应该有更简单的方法。
还有另一个问题。在某些情况下,标志的单个红色部分(这是一个单独的白色斑点)不是作为父外圆和子内圆,而是在外面有两个圆作为子圆的大父轮廓(即,另一个圆内的洞)孔,生成一个单独的 blob,它没有作为父对象找到)。是的,它在层次上是正确的,但对我没有帮助。我希望我能说清楚,对不起我的英语。
【问题讨论】:
-
你能上传你正在使用的图像和面具吗?我不明白你提到的“漏洞”
-
你能附上一张带孔的斑点的样本图像,计算不准确吗?
-
在您的二进制图像中,您认为什么是 blob?
-
我将每个白色像素岛视为一个斑点。对不起,如果文献中没有这样说。
-
使用 cv::connectedComponents(嗯,它相当于 C#)
标签: opencv