有没有一种算法可以很好地像样本图像那样填充空洞?膨胀效果不好,因为在我最终设法连接这些曲线的两端之前,曲线变得非常粗。我不想让线条变粗。谢谢你的帮助。
是的,图像中的任何字母或形状都可以有这样的孔。
发布于 2014-10-28 06:26:11
另一种更简单的方法可能会更好地转换为OpenCV
,因为它使用卷积而不是顺序的Perl/C代码。
基本上将所有黑色像素设置为10
值,将所有白色像素设置为0
值,然后将图像与以下3x3内核进行卷积:
1 1 1
1 10 1
1 1 1
现在,内核中间的黑色像素将得到100 (10x10),而附近的任何其他黑色像素都将得到10 (10x1)。因此,如果我们想要有一个中心黑像素和一个相邻黑像素的点,它的值将是110 (100+10)。因此,让我们用红色对所有值为110的像素进行着色。这给出了这个命令:
convert EsmKh.png -colorspace gray -fill gray\(10\) -opaque black -fill gray\(0\) -opaque white -morphology convolve '3x3: 1,1,1 1,10,1 1,1,1' -fill red -opaque gray\(110\) out.png
生成的图像(您可能需要放大间隙才能看到红色):
如果需要红色像素的列表,请将输出文件名替换为txt:
,然后按如下方式进行搜索:
convert EsmKh.png -colorspace gray -fill rgb\(10,10,10\) -opaque black -fill rgb\(0,0,0\) -opaque white -morphology convolve '3x3: 1,1,1 1,10,1 1,1,1' txt: | grep "110,110,110"
这就给出了:
86,55: (110,110,110) #6E6E6E grey43
459,55: (110,110,110) #6E6E6E grey43
83,56: (110,110,110) #6E6E6E grey43
507,59: (110,110,110) #6E6E6E grey43
451,64: (110,110,110) #6E6E6E grey43
82,65: (110,110,110) #6E6E6E grey43
134,68: (110,110,110) #6E6E6E grey43
519,75: (110,110,110) #6E6E6E grey43
245,81: (110,110,110) #6E6E6E grey43
80,83: (110,110,110) #6E6E6E grey43
246,83: (110,110,110) #6E6E6E grey43
269,84: (110,110,110) #6E6E6E grey43
288,85: (110,110,110) #6E6E6E grey43
315,87: (110,110,110) #6E6E6E grey43
325,87: (110,110,110) #6E6E6E grey43
422,104: (110,110,110) #6E6E6E grey43
131,116: (110,110,110) #6E6E6E grey43
524,116: (110,110,110) #6E6E6E grey43
514,117: (110,110,110) #6E6E6E grey43
122,118: (110,110,110) #6E6E6E grey43
245,122: (110,110,110) #6E6E6E grey43
76,125: (110,110,110) #6E6E6E grey43
456,128: (110,110,110) #6E6E6E grey43
447,129: (110,110,110) #6E6E6E grey43
245,131: (110,110,110) #6E6E6E grey43
355,135: (110,110,110) #6E6E6E grey43
80,146: (110,110,110) #6E6E6E grey43
139,151: (110,110,110) #6E6E6E grey43
80,156: (110,110,110) #6E6E6E grey43
354,157: (110,110,110) #6E6E6E grey43
144,160: (110,110,110) #6E6E6E grey43
245,173: (110,110,110) #6E6E6E grey43
246,183: (110,110,110) #6E6E6E grey43
76,191: (110,110,110) #6E6E6E grey43
82,197: (110,110,110) #6E6E6E grey43
126,200: (110,110,110) #6E6E6E grey43
117,201: (110,110,110) #6E6E6E grey43
245,204: (110,110,110) #6E6E6E grey43
248,206: (110,110,110) #6E6E6E grey43
297,209: (110,110,110) #6E6E6E grey43
309,210: (110,110,110) #6E6E6E grey43
现在,您可以处理红点列表,对于每个红点,找到最近的其他红点并用直线连接它们-或者如果您真的很热衷于曲线拟合,则进行一些曲线拟合。当然,可能会有一些改进工作要做,并且您可能希望设置填充线的最大长度。
发布于 2014-10-28 01:03:03
我对此做了一点尝试。它可能需要一些调整,但它是一个想法。我的算法如下:
找到恰好有1个黑色相邻像素的所有黑色像素,将其着色为红色,并将其放在pixels at ends
列表中。
浏览所有红色像素的列表,找到距离最近的其他红色像素,并在两者之间画直线。
顺便说一句,我只实现了第一部分--给读者留下了一些事情要做;-)
#!/usr/bin/perl
use strict;
use warnings;
use Image::Magick;
use Data::Dumper;
my $im=Image::Magick->new();
$im->Read('EsmKh.png');
my ($width,$height)=$im->Get('width','height');
my $out=Image::Magick->new();
$out->Read('EsmKh.png');
my @pixels;
# Iterate over pixels
for my $y (0..($height-1)){
for my $x (0..($width-1)){
my (@pixel) = split(/,/, $im->Get("pixel[$x,$y]"));
$pixels[$x][$y]=$pixel[0];
}
}
# Find black pixels that have precisely 1 black neighbour
for my $y (1..($height-2)){
for my $x (1..($width-2)){
next if $pixels[$x][$y]!=0;
my $neighbours=0;
for(my $i=$x-1;$i<=$x+1;$i++){
for(my $j=$y-1;$j<=$y+1;$j++){
$neighbours++ if $pixels[$i][$j]==0;
}
}
$neighbours--; # Uncount ourself !
if($neighbours==1){
$out->Set("pixel[$x,$y]"=>'red');
}
}
}
$out->Write(filename=>'out.png');
结果
你必须右放大才能看到红色的像素。
缩放图像
发布于 2014-10-29 05:18:45
在你得到加厚的图像后,你可以使用skeletonization恢复你的“瘦”形状。我找到了一个骨架化here的实现。
如果你想避免太多的加厚(因为它扭曲了图像和形状的一部分合并在一起),使用轻度腐蚀和骨架化交替使用,直到你的洞被填满。
https://stackoverflow.com/questions/26586123
复制相似问题