我该如何在 Emgu CV 中填充二进制图像中的空洞?
在 Aforge.net 中,使用 Fillholes 类很容易实现。
虽然这个问题有点旧,但我想为这个问题提供一个替代解决方案。
如果你使用以下代码,就可以得到与Chris相同的结果,而且不会有内存问题:
private Image<Gray,byte> FillHoles(Image<Gray,byte> image)
{
var resultImage = image.CopyBlank();
Gray gray = new Gray(255);
using (var mem = new MemStorage())
{
for (var contour = image.FindContours(
CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
RETR_TYPE.CV_RETR_CCOMP,
mem); contour!= null; contour = contour.HNext)
{
resultImage.Draw(contour, gray, -1);
}
}
return resultImage;
}
上述方法的好处在于您可以有选择性地填补符合您标准的空洞。例如,您可能希望填补像素计数(斑点内黑色像素的数量)低于50的空洞等。
private Image<Gray,byte> FillHoles(Image<Gray,byte> image, int minArea, int maxArea)
{
var resultImage = image.CopyBlank();
Gray gray = new Gray(255);
using (var mem = new MemStorage())
{
for (var contour = image.FindContours(
CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE,
RETR_TYPE.CV_RETR_CCOMP,
mem); contour!= null; contour = contour.HNext)
{
if ( (contour.Area < maxArea) && (contour.Area > minArea) )
resultImage.Draw(contour, gray, -1);
}
}
return resultImage;
}
OpenFileDialog OpenFile = new OpenFileDialog();
if (OpenFileDialog.ShowDialog() == DialogResult.OK)
{
Image<Bgr, byte> image = new Image<Bgr, byte>(OpenFile.FileName);
for (int i = 0; i < image.Width; i++)
{
for (int j = 0; j < image.Height; j++)
{
if (image.Data[j, i, 0] != 255)
{
Image<Bgr, byte> image_copy = image.Copy();
Image<Gray, byte> mask = new Image<Gray, byte>(image.Width + 2, image.Height + 2);
MCvConnectedComp comp = new MCvConnectedComp();
Point point1 = new Point(i, j);
//CvInvoke.cvFloodFill(
CvInvoke.cvFloodFill(image_copy.Ptr, point1, new MCvScalar(255, 255, 255, 255),
new MCvScalar(0, 0, 0),
new MCvScalar(0, 0, 0), out comp,
Emgu.CV.CvEnum.CONNECTIVITY.EIGHT_CONNECTED,
Emgu.CV.CvEnum.FLOODFILL_FLAG.DEFAULT, mask.Ptr);
if (comp.area < 10000)
{
image = image_copy.Copy();
}
}
}
}
}
以下是您可以期望的结果:
原始图像
结果
这种方法的问题在于它非常占用内存,并且在200x200图像上吃掉了6GB的RAM,当我尝试200x300时,它吃掉了所有8GB的RAM,并使一切都崩溃了。除非您的大部分图像都是白色并且想要填补微小的间隙,或者您可以最小化应用该方法的位置,否则我建议避免使用它。如果您不希望编写自己的类,则建议使用Aforge FillHoles类,因为它是专门为此目的设计的。
祝好
克里斯
image.FillConvexPoly(externalContours.ToArray(), new Gray(255));