在TeX stackexchange上,我们一直在讨论如何在此问题的段落中检测“河流”。

在这种情况下,河流是空白区域,是文本中单词间空格的意外对齐导致的。由于这可能会使读者分心,因此糟糕的河流被认为是排版不佳的征兆。一个带有河流的文本示例就是这样,其中有两条河流沿对角线流动。 (可能是通过手动编辑文本)。 Raphink在TeX级别(仅知道字形位置和边界框)上取得了一些进展,但是我相信检测河流的最佳方法是进行某些图像处理(因为字形形状非常重要,而且TeX无法使用)。 。我尝试了多种方法从上述图像中提取河流,但是我的简单想法是应用少量椭圆形模糊效果似乎不够好。我也尝试了一些基于Radon Hough变换的过滤,但是这些都没有。河流对于人眼/视网膜/大脑的特征检测电路非常明显,因此我认为可以将其转换为某种过滤操作,但我无法使其工作。有任何想法吗?

具体来说,我正在寻找可以检测上图中的两条河流的操作,但是没有太多其他误报检测。编辑:endolith问我为什么要采用基于图像处理的方法,因为在TeX中我们可以访问字形的位置,间距等,并且使用检查实际文本的算法可能更快,更可靠。我这样做的另一个原因是,字形的形状会影响河流的可见性,并且在文本级别上很难考虑这种形状(取决于字体,绑扎等)。有关字形形状如何重要的示例,请考虑以下两个示例,它们之间的区别在于,我已用几乎相同宽度的其他字形替换了一些字形,以便进行基于文本的分析他们同样好/坏。但是请注意,第一个示例中的河流比第二个示例中的河流严重得多。





评论

+1我喜欢这个问题。我的第一个想法是霍夫变换,但可能需要进行一些预处理。也许首先使用膨胀过滤器。

我很惊讶Radon转换实际上没有用。你是怎么做到的?

@endolith:没什么复杂的。我使用了Mathematica的ImageLines [],并进行了一些预处理。我猜想这在技术上是使用霍夫变换而不是拉顿变换。如果适当的预处理(我没有尝试过datageist建议的膨胀过滤器)和/或参数设置可以使这项工作奏效,我不会感到惊讶。

Google Image Search for rivers也显示“蜿蜒”的河流。您想找到那些吗? cdn.ilovetypography.com/img/text-river1.gif

@endolith我想我最终想复制人类视觉系统的处理过程,该过程会使空间的某些配置分散注意力。由于蜿蜒的河流也可能发生这种情况,所以我想抓住它们,尽管一般来说直河似乎更成问题。更好的方法是以一种与河流在阅读文字时能看到的强烈程度相对应的方式来量化河流的“恶劣”程度。但这都是非常主观的,很难量化。首先,只需捕获所有不好的河流,而不会产生太多误报。

#1 楼

我对此进行了更多考虑,并认为以下内容应该相当稳定。请注意,我仅限于进行形态学操作,因为这些操作在任何标准图像处理库中都可以使用。字母之间的距离

#% read image
img = rgb2gray('http://i.stack.imgur.com/4ShOW.png');

%# threshold and open with a rectangle
%# that is roughly letter sized
bwImg = img > 200; %# threshold of 200 is better than 128

opImg = imopen(bwImg,ones(13,1));




(3)删除由于段落之间的空间或凹痕而导致的水平“河流和湖泊”。为此,我们删除所有真实的行,并使用已知不会影响之前发现的河流的nPix-by-1掩码打开。

要删除湖泊,我们可以使用一个比nPix-by-nPix稍大的开口蒙版。

在此步骤中,我们还可以丢弃所有太小而不能成为真实河流的东西,即,所有面积小于( nPix + 2)*(mPix + 2)* 4(这将给我们〜3行)。之所以加上+2,是因为我们知道所有对象的高度至少为nPix,宽度至少为mPix,并且我们想在其上略高一点。

opImg = imopen(opImg,ones(1,5));




(4)如果我们不仅对河流的长度感兴趣,还对河流的宽度感兴趣,可以将距离变换与骨架相结合。

%# horizontal river: just look for rows that are all true
opImg(all(opImg,2),:) = false;
%# open with line spacing (nPix)
opImg = imopen(opImg,ones(13,1));

%# remove lakes with nPix+2
opImg = opImg & ~imopen(opImg,ones(15,15)); 

%# remove small fry
opImg = bwareaopen(opImg,7*15*4);



(颜色对应于河流的宽度(尽管颜色条的偏移量是2的倍数))

现在您可以通过计数来获得河流的大致长度每个连接的组件中的像素数,以及通过平均像素值得到的平均宽度。


下面是对第二个“无河流”图像的完全相同的分析:



评论


$ \ begingroup $
谢谢。我有Matlab,所以我将在其他一些文章上尝试一下,看看它会多么强大。
$ \ endgroup $
–莱夫·毕晓普(Lev Bishop)
2011年10月5日在20:08

$ \ begingroup $
除非将其以某种方式移植到Lua,否则将其重新集成到TeX中可能是另一个问题。
$ \ endgroup $
–ℝaphink
2011年10月5日20:32

$ \ begingroup $
@LevBishop:我认为我对该问题的理解要好一些。新的解决方案应该相当健壮。
$ \ endgroup $
–乔纳斯(Jonas)
2011年10月6日,下午2:09

$ \ begingroup $
@levBishop:还有一个更新。
$ \ endgroup $
–乔纳斯(Jonas)
2011年10月6日12:56

$ \ begingroup $
@LevBishop:刚注意到第二张图片。事实证明,基于形态的分析可以完成工作。
$ \ endgroup $
–乔纳斯(Jonas)
2011年10月6日13:16

#2 楼

在Mathematica中,使用腐蚀和霍夫变换:

(*Get Your Images*)
i = Import /@ {"http://i.stack.imgur.com/4ShOW.png", 
               "http://i.stack.imgur.com/5UQwb.png"};

(*Erode and binarize*)
i1 = Binarize /@ (Erosion[#, 2] & /@ i);

(*Hough transform*)
lines = ImageLines[#, .5, "Segmented" -> True] & /@ i1;

(*Ready, show them*)
Show[#[[1]],Graphics[{Thick,Orange, Line /@ #[[2]]}]] & /@ Transpose[{i, lines}]




编辑回答向导先生的评论

如果您想要摆脱水平线,只需执行以下操作即可(可能有人可以简化它):

Show[#[[1]], Graphics[{Thick, Orange, Line /@ #[[2]]}]] & /@ 
 Transpose[{i, Select[Flatten[#, 1], Chop@Last@(Subtract @@ #) != 0 &] & /@ lines}]

评论


$ \ begingroup $
为什么不摆脱所有水平线? (+1)
$ \ endgroup $
–向导先生
2011-11-22 8:25

$ \ begingroup $
@先生。只是为了显示所有线都被检测到...
$ \ endgroup $
– belisarius博士
2011年11月22日在12:16

$ \ begingroup $
那不是问题的一部分,对吗?
$ \ endgroup $
–向导先生
2011年11月22日在12:17

$ \ begingroup $
@先生。根据要求编辑
$ \ endgroup $
– belisarius博士
2011-11-22 12:54

$ \ begingroup $
@belisarius在Hough变换中使用的坐标系在8.0.0之后更改为与Radon变换之一匹配。反过来,这改变了ImageLines的行为。总体而言,这是一种改进,尽管在这种情况下,您会更喜欢以前的行为。如果您不想尝试峰值检测,可以将输入图像的宽高比更改为接近1,并获得类似于8.0.0的结果:lines = ImageLines [ImageResize [#,{300,300} ] 、. 6,“细分”-> True]和/ @ i1;。综上所述,对于这个问题,形态学方法似乎更可靠。
$ \ endgroup $
–马特西亚·奥迪西奥(Matthias Odisio)
2011年11月28日15:06



#3 楼

嗯...我想Radon变换并不是那么容易提取。 (Radon变换基本上在边“边看”的同时旋转图像。这是CAT扫描的原理。)图像的变换会产生此正弦图,“河流”形成明亮的峰,并圈出:



沿着水平轴的此图的左侧图中,可以清楚地看到旋转70度的那个峰:

特别是如果文本首先是高斯模糊的:的噪音。正弦图的明亮的顶端和底端代表了文本水平线之间的“河流”,您显然并不在乎。

简单的余弦加权功能在此图像上效果很好:



在90度处找到垂直河,这是正弦图中的全局最大值:


在图像上找到一个在104度处的河,尽管模糊了首先使它更准确:
(qci2010q
(SciPy的radon()函数有点愚蠢,或者我将这个峰映射为原始线,作为一条直线穿过)在河中。)

经过模糊和加权后,它在图像的正弦图中找不到两个主要峰中的一个:



它们在那里,但是它们被加权函数中间峰值附近的东西所淹没。通过正确的加权和调整,此方法可能可行,但是我不确定什么是正确的调整。这也可能取决于页面扫描的属性。也许需要从切片中的总能量或诸如归一化之类的东西中得出权重。



from pylab import *
from scipy.misc import radon
import Image

filename = 'rivers.png'
I = asarray(Image.open(filename).convert('L').rotate(90))

# Do the radon transform and display the result
a = radon(I, theta = mgrid[0:180])

# Remove offset
a = a - min(a.flat)

# Weight it to emphasize vertical lines
b = arange(shape(a)[1]) #
d = (0.5-0.5*cos(b*pi/90))*a

figure()
imshow(d.T)
gray()
show()

# Find the global maximum, plot it, print it
peak_x, peak_y = unravel_index(argmax(d),shape(d))
plot(peak_x, peak_y,'ro')
print len(d)- peak_x, 'pixels', peak_y, 'degrees'


评论


$ \ begingroup $
如果先用不对称的高斯模糊,该怎么办?即在水平方向上较窄,在垂直方向上较宽。
$ \ endgroup $
–乔纳斯(Jonas)
2011年10月11日19:05

$ \ begingroup $
@Jonas:这可能会有所帮助。主要问题是当背景随旋转变化很大时会自动从背景中挑选峰。不对称模糊可以使水平条纹逐行平滑。
$ \ endgroup $
– Endolith
2011年10月11日19:20

$ \ begingroup $
至少可以很好地检测文本中线条的旋转:gist.github.com/endolith/334196bac1cac45a4893
$ \ endgroup $
– Endolith
2014年8月1日在20:02

#4 楼

我使用了不同比例的导数特征(最多2阶)对像素进行了判别式分类器训练。

我的标签:关于训练图像:



对其他两个图像的预测:





我认为这看起来很有希望,并且在获得更多训练数据和更智能功能的情况下,可能会产生可用的结果。另一方面,我只花了几分钟就得到了这些结果。您可以使用开源软件ilastik自己重现结果。 [免责声明:我是主要开发人员之一。]

#5 楼

(对不起,这篇文章中没有精彩的演示。)

如果您想使用TeX已经拥有的信息(字母和位置),可以手动将字母和字母对归类为“倾斜”。在一个方向或另一个方向上。例如,“ w”具有SW和SE角坡度,“ al”组合具有NW角坡度,“ k”具有NE角坡度。 (别忘了标点符号-引号后面跟一个字母,填充该字形框的下半部分,建立了一个不错的斜率;引号后面跟着q特别强。)空间相对两侧的相应坡度-SW到NE的河流为“ w al”,NW到SE的河流为“ k T”。当您在一行中找到一个时,请查看在上方/下方的行中是否发生了类似的事件(适当地向左或向右移动);

此外,很显然,只需寻找几乎垂直堆叠的空间,就可以找到平原的垂直河流。

您可以得到通过测量坡度的“强度”,可以稍微复杂一点:由于坡度,有多少提前量盒为“空”,从而对河流的宽度有所贡献。 “ w”相当小,因为它的前进箱只有一个小角可用于河道,但“ V”非常强。 “ b”比“ k”略强;更柔和的曲线使河流边缘更具视觉上的连续性,使其更强壮并在视觉上更宽。