Metinde “Nehir” tespiti


175

TeX yığın değişiminde, bu sorudaki paragraflarda "nehirleri" nasıl tespit edeceğimizi tartışıyoruz .

Bu bağlamda nehirler, metindeki interword boşluklarının yanlışlıkla hizalanmasından kaynaklanan beyaz boşluk bantlarıdır. Bu bir okuyucunun dikkatini dağıtabildiğinden, kötü nehirler kötü tipografi belirtisi olarak kabul edilir. Akarsu içeren bir metin örneği, çapraz akan iki akarsu olduğu yerdir.

görüntü tanımını buraya girin

Bu nehirlerin otomatik olarak algılanmasına ilgi vardır, bu sayede bunlardan kaçınılabilir (muhtemelen metnin elle düzenlenmesi ile). Raphink (yalnızca glif konumlarını ve sınırlayıcı kutularını bilen) TeX düzeyinde bir miktar ilerleme kaydetmektedir, ancak nehirleri tespit etmenin en iyi yolunun bazı görüntü işlemelerinde olduğundan (glif şekilleri çok önemli ve TeX için mevcut olmadığından) eminim. . Nehirleri yukarıdaki görüntüden çıkarmanın çeşitli yollarını denedim, ancak basit bir miktar elipsoidal bulanıklaştırma uygulama fikrim yeterince iyi gözükmüyor. Ben de biraz Radon denedimHough dönüşüm tabanlı filtreleme, ama onlardan hiçbiriyle anlamadım. Nehirler, insan gözü / retina / beynin özellik tespit devrelerinde çok görünür ve bir şekilde bunun bir çeşit filtreleme işlemine çevrilebileceğini düşünürdüm, ancak çalışmasını sağlayamıyorum. Herhangi bir fikir?

Daha açık olmak gerekirse, yukarıdaki resimde bulunan 2 nehiri tespit edecek, ancak çok fazla yanlış pozitif tespit bulunmayan bir işlem arıyorum.

EDIT: endolith, TeX'te glif konumlarına, aralıklarına vb. Erişebildiğimiz ve gerçek metni inceleyen bir algoritmayı kullanmanın çok daha hızlı ve daha güvenilir olabileceği göz önüne alındığında neden görüntü işleme tabanlı bir yaklaşım peşinde olduğumu sordu. Başka şeyler yapmamın sebebi bu şekildegliflerin bir nehrin ne kadar belirgin olduğunu etkileyebileceğini ve metin düzeyinde (bu yazı tipine, bitiş harfine, vb. Gliflerin şeklinin nasıl önemli olabileceğinin bir örneği için, aşağıdaki iki örneği göz önünde bulundurun; aralarındaki fark, birkaç glifi neredeyse aynı genişliğe sahip diğerleriyle değiştirdiğimde, böylece metin tabanlı bir analiz düşünebilir. Onları eşit derecede iyi / kötü. Bununla birlikte, birinci örnekteki nehirlerin ikinciden çok daha kötü olduğuna dikkat edin.

görüntü tanımını buraya girin

görüntü tanımını buraya girin


5
+1 Bu soruyu beğendim. İlk düşüncem bir Hough Dönüşümü , ama muhtemelen bir miktar ön işleme ihtiyacı olacak. Belki de önce bir Diyet Filtresi .
datageist

Aslında Radon dönüşümünün işe yaramadığına şaşırdım. Bunu nasıl yaptın?
Endolit

@endolith: Gelişmiş bir şey yok. Ben kullanılan ImageLines[]ve bazı ön işleme olmadan, Mathematica dan. Sanırım bu teknik olarak Radon dönüşümü yerine bir Hough kullanıyor. Doğru ön işleme (datageistin önerdiği dilasyon filtresini denemedim) ve / veya parametre ayarları bu işi yapabilirse şaşırmayacağım.
Lev Bishop

Nehirler için Google Görsel Arama, nehirleri de "sarma" gösterir. Bunları bulmak ister misin? cdn.ilovetypography.com/img/text-river1.gif
Endolit

@ endolith Sanırım nihayetinde, belirli alanların dikkatini dağıtıcı yapılandırmalarını yapan insan görsel sisteminin işlenmesini çoğaltmak istiyorum. Bu kıvrımlı nehirler için de olabileceğinden, o zamanlar genel olarak daha problemli gibi görünse de onları yakalamak isterim. Daha da iyisi, nehirlerin "kötülüklerini" metni okurken ne kadar güçlü göründüklerine karşılık gelecek şekilde ölçmenin bir yolu olabilir. Fakat bunların hepsi öznel ve nicel olarak belirlenmesi zor. Birincisi, sadece çok fazla yanlış pozitif olmadan gerçekten tüm kötü nehirleri yakalamak yeterli olacaktır.
Lev Bishop,

Yanıtlar:


135

Bunun hakkında biraz daha düşündüm ve aşağıdakilerin oldukça istikrarlı olması gerektiğini düşünüyorum. Kendimi morfolojik işlemlerle sınırladığımı unutmayın, çünkü bunlar herhangi bir standart görüntü işleme kütüphanesinde mevcut olmalıdır.

(1) Görüntüyü nPix'e 1 maskeyle açın; burada nPix, harfler arasındaki dikey mesafedir.

#% 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));

görüntü tanımını buraya girin

(2) Bir nehir olmak için çok dar olanı ortadan kaldırmak için görüntüyü 1-mPix maskesiyle açın.

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

görüntü tanımını buraya girin

(3) Paragraflar veya girintiler arasındaki boşluktan kaynaklanan yatay “nehirleri ve gölleri” kaldırın. Bunun için doğru olan tüm satırları kaldırdık ve daha önce bulduğumuz nehirleri etkilemeyeceğini bildiğimiz nPix-by-1 maskesi ile açtık.

Gölleri kaldırmak için, nPix-by-nPix'ten biraz daha büyük olan bir açılış maskesi kullanabiliriz.

Bu aşamada, gerçek bir nehir olamayacak kadar küçük olan her şeyi de çıkarabiliriz, yani (nPix + 2) * (mPix + 2) * 4'ten daha az alanı kapsayan her şey (bize ~ 3 satır verecek). +2 oradadır çünkü tüm nesnelerin en az nPix yüksekliğinde ve mPix genişliğinde olduğunu biliyoruz ve bunun üzerinde biraz gitmek istiyoruz.

%# 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);

görüntü tanımını buraya girin

(4) Eğer sadece uzunlukla değil, nehrin genişliğiyle de ilgileniyorsak, mesafe dönüşümünü iskelet ile birleştirebiliriz.

   dt = bwdist(~opImg);
   sk = bwmorph(opImg,'skel',inf);
   %# prune the skeleton a bit to remove branches
   sk = bwmorph(sk,'spur',7);

   riversWithWidth = dt.*sk;

görüntü tanımını buraya girin (renkler nehrin genişliğine karşılık gelir (renk çubuğu 2 kat kapalı olsa da)

Artık, bağlanan her bileşendeki piksel sayısını sayarak nehirlerin yaklaşık uzunluğunu ve piksel değerlerinin ortalamasını alarak ortalama genişliği elde edebilirsiniz.


İşte ikinci "nehirsiz" resme uygulanan aynı analiz:

görüntü tanımını buraya girin


Teşekkürler. Matlab'ım var, bunun ne kadar sağlam olacağını görmek için bunu diğer bazı metinlerde deneyeceğim.
Lev Bishop,

Onu bir şekilde TeX'e entegre etmek, bir şekilde Lua'ya gönderemediğimiz sürece başka bir sorun olabilir.
32'de

@LevBishop: Sanırım sorunu biraz daha iyi anlıyorum. Yeni çözüm oldukça sağlam olmalı.
Jonas

@ levBishop: Bir güncelleme daha.
Jonas

1
@LevBishop: İkinci görüntüyü farkettim. Morfoloji temelli analizin işini yaptığını ortaya koyar.
Jonas

56

Mathematica'da erozyon ve Hough dönüşümü kullanarak:

(*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}]

görüntü tanımını buraya girin

Düzenleme Bay Büyücü yorumunu cevaplama

Yatay çizgilerden kurtulmak istiyorsanız, bunun yerine böyle bir şey yapın (muhtemelen biri bunu daha basit hale getirebilir):

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

görüntü tanımını buraya girin


1
Neden tüm yatay çizgilerden kurtulmuyorsunuz? (+1)
Bay Sihirbazı

@Bay. Sadece tüm satırların tespit edildiğini göstermek için ...
Dr. belisarius 22:11 12

1
Ancak bu sorunun bir parçası değil mi?
Sihirbaz

@Bay. İstenildiği gibi düzenlendi
Dr. belisarius 22:11

4
@belisarius Hough dönüşümünde kullanılan koordinat sistemi, 8.0.0'dan sonra Radon dönüşümü ile aynı olacak şekilde değiştirildi. Bu da ImageLines'in davranışını değiştirdi. Genel olarak bu bir gelişmedir, ancak bu durumda bir önceki davranışı tercih edersiniz. Pik algılamalarla deneme yapmak istemiyorsanız, giriş görüntüsünün en boy oranını 1'e yakınlaştırabilir ve 8.0.0: 'a benzer bir sonuç elde edebilirsiniz lines = ImageLines[ImageResize[#, {300, 300}], .6, "Segmented" -> True] & /@ i1;. Bütün bunlar söyleniyor, bu problem için morfolojik bir yaklaşım daha sağlam görünüyor.
Matthias Odisio

29

Hmmm ... Radon dönüşümünü çıkarmak o kadar kolay değil sanırım . (Radon dönüşümü temel olarak görüntüyü “içine bakarken” döndürür. CAT taramalarının arkasındaki prensiptir.) Görüntünüzün dönüşümü, bu sinogramı oluşturur;

görüntü tanımını buraya girin

70 derece dönüşte olan, yatay olarak bir dilimin bu grafiğinin solundaki tepe noktası olarak açıkça görülebilir:

görüntü tanımını buraya girin

Özellikle, metin önce Gaussca bulanıksa:

görüntü tanımını buraya girin

Ancak bu tepeleri gürültünün geri kalanından nasıl güvenilir bir şekilde çıkaracağımı bilmiyorum. Sinogramın parlak üst ve alt uçları, açık şekilde umursamadığınız yatay metin satırları arasındaki "nehirleri" temsil eder. Belki daha dikey çizgileri vurgulayan ve yatay olanları en aza indiren açıya karşı ağırlıklandırma işlevi?

Basit bir kosinüs ağırlıklandırma işlevi bu görüntüde iyi çalışır:

görüntü tanımını buraya girin

sinogramdaki küresel maksimum değer olan düşey nehri 90 derecede bulma:

görüntü tanımını buraya girin

ve bu görüntüde birini 104 derecede bulmakla birlikte, bulanıklaştırma ilk önce daha doğru hale getirir:

görüntü tanımını buraya girin görüntü tanımını buraya girin

(SciPy'nin radon()işlevi biraz aptalca , yoksa bu zirveyi, ormanın ortasından geçen bir çizgi olarak orijinal görüntünün üzerine geri koyardım.)

Ancak, bulanıklaştırma ve ağırlıklandırma sonrasında sinogramdaki iki ana tepe noktasından hiçbirini bulamıyor:

görüntü tanımını buraya girin

Oradalar, ancak ağırlıklandırma fonksiyonunun orta zirvesine yakın olan şeyler karşısında bunaldılar. Doğru ağırlıklandırma ve ince ayar yapma ile bu yöntem muhtemelen işe yarayabilirdi, ancak doğru ince ayarların ne olduğundan emin değilim. Muhtemelen sayfanın tarama özelliklerine de bağlıdır. Belki de ağırlıklandırma, dilimdeki toplam enerjiden veya normalizasyon gibi bir şeyden türetilmelidir.

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'

Ya önce asimetrik bir Gauss'la bulanıklaştıysanız? Yani yatay yönde, dikey yönde geniş.
Jonas

@Jonas: Bu muhtemelen yardımcı olur. Asıl sorun, arka plan rotasyona göre çok fazla değiştiğinde, arka plandaki tepe noktalarını otomatik olarak seçmektir. Asimetrik bulanıklaştırma, yatay çizgileri çizgiden çizgiye düzeltebilir.
endolith

Bu metinde, en azından çizgilerin dönüşünü tespit etmek için iyi çalışıyor gist.github.com/endolith/334196bac1cac45a4893
Endolit

16

Farklı ölçeklerde türev özellikleri (2. dereceye kadar) kullanarak piksellerde ayırt edici bir sınıflandırıcı yetiştirdim.

Etiketlerim:

etiketleme

Eğitim görüntüsüne ilişkin tahmin:

görüntü tanımını buraya girin

Diğer iki görüntünün tahmini:

görüntü tanımını buraya girin

görüntü tanımını buraya girin

Sanırım bu umut verici görünüyor ve daha fazla eğitim verisi ve belki daha akıllı özellikler nedeniyle kullanılabilir sonuçlar üretebilir. Öte yandan, bu sonuçları almak sadece birkaç dakikamı aldı. Açık kaynak kodlu yazılımı ilastik kullanarak sonuçları kendiniz de çoğaltabilirsiniz . [Feragatname: Ben ana geliştiricilerden biriyim.]


2

(Üzgünüz, bu gönderi harika gösterilerle gelmiyor.)

TeX'in zaten sahip olduğu bilgilerle çalışmak istiyorsanız (harfler ve pozisyonlar), harfleri ve harf çiftlerini bir yönde veya başka bir yönde "eğimli" olarak manuel olarak sınıflandırabilirsiniz. Örneğin, "w" SW ve SE köşe eğimlerine sahiptir, "al" combo bir NW köşe eğimine, "k" bir NE köşe eğimine sahiptir. (Noktalama işaretini unutma - ardından glif kutusunun alt yarısını dolduran bir mektuptan sonra gelen bir alıntı güzel bir eğim oluşturur; q ile gelen alıntı özellikle güçlüdür.)

Ardından, bir SW-to-NE nehri için "w al" veya bir NW-SE nehri için "k T" bulunan bir alanın karşı taraflarında karşılık gelen eğimlerin oluşumlarını arayın. Bir çizgide bir tane bulduğunuzda, benzer bir çizginin, yukarıdaki sola veya sağa doğru kaydırılarak benzer çizgilerin olup olmadığına bakın; bunlardan bir kaçış bulduğunuzda, muhtemelen bir nehir var.

Ayrıca, açıkçası, düz dikey nehirler için neredeyse dikey olarak yığılmış alanları arayın.

Eğimin "kuvvetini" ölçerek biraz daha sofistike olabilirsiniz: eğimden dolayı ilerletme kutusunun ne kadarı "boş" olur ve böylece nehrin genişliğine katkıda bulunur. "w", nehre katkıda bulunmak için avans kutusunun sadece küçük bir köşesine sahip olduğu için oldukça küçüktür, ancak "V" çok güçlüdür. "b", "k" den biraz daha güçlüdür; Daha yumuşak olan eğri, görsel olarak daha sürekli bir nehir kenarı sağlayarak onu daha güçlü ve görsel olarak daha geniş hale getirir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.