use*_*986 6 opencv image-processing
是否有一种算法在填充样本图像上的孔方面表现良好?膨胀效果不好,因为在我最终设法连接这些曲线的末端之前,曲线变得非常厚.我想避免加粗线条.感谢您的任何帮助.
是的,图像中可能只有任何字母或形状有这样的孔.
另一种更简单的方法,可能会更好地转换OpenCV
为使用卷积而不是顺序Perl/C代码.
基本上将所有黑色像素设置为值10
,将所有白色像素设置为值0
,然后将图像与以下3x3内核进行卷积:
1 1 1
1 10 1
1 1 1
Run Code Online (Sandbox Code Playgroud)
现在,内核中间的黑色像素将给出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
Run Code Online (Sandbox Code Playgroud)
使用生成的图像(您可能需要放大间隙才能看到红色):
如果你想要一个红色像素列表,用输出文件名替换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"
Run Code Online (Sandbox Code Playgroud)
这使:
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
Run Code Online (Sandbox Code Playgroud)
现在你可以处理红点列表,并为每一个红点找到最近的其他红点并用直线连接它们 - 或者如果你感觉非常敏锐的话,做一些曲线拟合.当然,可能需要进行一些改进,您可能希望设置间隙填充线的最大长度.
我对此进行了一些尝试。它可能需要一些调整,但它是一个想法。我的算法如下:
找到所有恰好有 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');
Run Code Online (Sandbox Code Playgroud)
结果
您必须向右放大才能看到红色像素......
缩放图像