Deteksi “Sungai” dalam teks

175

Di atas tentang pertukaran stack TeX, kami telah mendiskusikan bagaimana mendeteksi "sungai" dalam paragraf dalam pertanyaan ini .

Dalam konteks ini, sungai adalah pita ruang putih yang dihasilkan dari penyelarasan tak sengaja dari ruang kata dalam teks. Karena ini bisa sangat mengganggu pembaca, sungai yang buruk dianggap sebagai gejala tipografi yang buruk. Contoh teks dengan sungai adalah yang ini, di mana ada dua sungai yang mengalir secara diagonal.

masukkan deskripsi gambar di sini

Ada minat dalam mendeteksi sungai-sungai ini secara otomatis, sehingga mereka dapat dihindari (mungkin dengan mengedit teks secara manual). Raphink membuat beberapa kemajuan pada level TeX (yang hanya tahu posisi mesin terbang dan kotak pembatas), tapi saya merasa yakin bahwa cara terbaik untuk mendeteksi sungai adalah dengan beberapa pemrosesan gambar (karena bentuk mesin terbang sangat penting dan tidak tersedia untuk TeX) . Saya telah mencoba berbagai cara untuk mengekstrak sungai dari gambar di atas, tetapi ide sederhana saya untuk menerapkan sedikit ellipsoidal blurring tampaknya tidak cukup baik. Saya juga mencoba beberapa RadonHough mengubah pemfilteran berdasarkan, tapi saya juga tidak berhasil. Sungai-sungai sangat terlihat oleh sirkuit pendeteksian fitur mata / retina / otak manusia dan entah bagaimana saya akan berpikir ini dapat diterjemahkan ke beberapa jenis operasi penyaringan, tetapi saya tidak dapat membuatnya berfungsi. Ada ide?

Untuk lebih spesifik, saya mencari beberapa operasi yang akan mendeteksi 2 sungai pada gambar di atas, tetapi tidak memiliki terlalu banyak deteksi positif palsu lainnya.

EDIT: endolith bertanya mengapa saya mengejar pendekatan berbasis pemrosesan gambar mengingat bahwa di TeX kita memiliki akses ke posisi mesin terbang, jarak, dll, dan mungkin akan jauh lebih cepat dan lebih dapat diandalkan untuk menggunakan algoritma yang memeriksa teks yang sebenarnya. Alasan saya melakukan sesuatu dengan cara lain adalah karena bentuknyadari mesin terbang dapat mempengaruhi seberapa terlihat sungai, dan pada tingkat teks sangat sulit untuk mempertimbangkan bentuk ini (yang tergantung pada font, ligaturing, dll). Untuk contoh bagaimana bentuk mesin terbang dapat menjadi penting, pertimbangkan dua contoh berikut, di mana perbedaan di antara mereka adalah bahwa saya telah mengganti beberapa mesin terbang dengan yang hampir sama lebarnya, sehingga analisis berbasis teks akan mempertimbangkan mereka sama-sama baik / buruk. Perhatikan, bagaimanapun, bahwa sungai-sungai dalam contoh pertama jauh lebih buruk daripada yang kedua.

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Lev Bishop
sumber
5
+1 Saya suka pertanyaan ini. Pikiran pertama saya adalah Hough Transform , tetapi mungkin perlu beberapa pra-pemrosesan. Mungkin Filter Dilation terlebih dahulu.
datageist
Aku heran Radon transform tidak bekerja, sebenarnya. Bagaimana kamu melakukannya?
endolith
@endolith: Tidak ada yang canggih. Saya menggunakan ImageLines[]dari Mathematica, dengan dan tanpa beberapa preprocessing. Saya kira ini secara teknis menggunakan transformasi Hough daripada Radon. Saya tidak akan terkejut jika preprocessing yang tepat (saya tidak mencoba filter dilasi yang disarankan datageist) dan / atau pengaturan parameter dapat membuat ini berfungsi.
Lev Bishop
Pencarian Gambar Google untuk sungai juga menunjukkan sungai "berliku". Apakah Anda ingin menemukan itu? cdn.ilovetypography.com/img/text-river1.gif
endolith
@endolith Saya kira saya akhirnya ingin meniru proses sistem visual manusia yang membuat konfigurasi ruang tertentu mengganggu. Karena ini bisa terjadi juga untuk sungai yang berkelok-kelok, maka saya ingin menangkapnya, walaupun yang lurus kelihatannya lebih merupakan masalah secara umum. Bahkan yang lebih baik akan menjadi cara untuk mengukur "keburukan" sungai dengan cara yang sesuai dengan seberapa kuat mereka saat membaca teks. Tapi itu semua sangat subyektif dan sulit untuk diukur. Pertama-tama, hanya menangkap benar-benar semua sungai yang buruk tanpa terlalu banyak kesalahan positif akan dilakukan.
Lev Bishop

Jawaban:

135

Saya telah memikirkan hal ini lagi, dan berpikir bahwa yang berikut ini harusnya cukup stabil. Perhatikan bahwa saya membatasi diri pada operasi morfologis, karena ini harus tersedia di pustaka pemrosesan gambar standar.

(1) Buka gambar dengan topeng nPix-by-1, di mana nPix adalah tentang jarak vertikal antara huruf

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

masukkan deskripsi gambar di sini

(2) Buka gambar dengan topeng 1-by-mPix untuk menghilangkan apa pun yang terlalu sempit untuk menjadi sungai.

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

masukkan deskripsi gambar di sini

(3) Hapus "sungai dan danau" horisontal yang disebabkan oleh jarak antar paragraf, atau lekukan. Untuk ini, kami menghapus semua baris yang semuanya benar, dan membuka dengan topeng nPix-by-1 yang kami tahu tidak akan memengaruhi sungai yang telah kami temukan sebelumnya.

Untuk menghapus danau, kita bisa menggunakan topeng pembuka yang sedikit lebih besar dari nPix-by-nPix.

Pada langkah ini, kita juga dapat membuang segala sesuatu yang terlalu kecil untuk menjadi sungai sungguhan, yaitu segala sesuatu yang luasnya kurang dari (nPix + 2) * (mPix + 2) * 4 (yang akan memberi kita ~ 3 baris). +2 ada di sana karena kita tahu bahwa semua objek setidaknya memiliki ketinggian nPix, dan lebar mPix, dan kami ingin sedikit lebih tinggi dari itu.

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

masukkan deskripsi gambar di sini

(4) Jika kita tertarik tidak hanya panjangnya, tetapi juga lebar sungai, kita dapat menggabungkan transformasi jarak dengan kerangka.

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

   riversWithWidth = dt.*sk;

masukkan deskripsi gambar di sini (warna sesuai dengan lebar sungai (meskipun bilah warna tidak aktif karena faktor 2)

Sekarang Anda bisa mendapatkan perkiraan panjang sungai dengan menghitung jumlah piksel di setiap komponen yang terhubung, dan lebar rata-rata dengan rata-rata nilai pikselnya.


Inilah analisis yang persis sama yang diterapkan pada gambar "no-river" yang kedua:

masukkan deskripsi gambar di sini

Jonas
sumber
Terima kasih. Saya punya Matlab jadi saya akan mencoba ini pada beberapa teks lain untuk melihat seberapa kuat itu akan.
Imamat Uskup
Untuk mengintegrasikannya kembali ke TeX mungkin ada masalah lain, kecuali kita bisa porting itu ke Lua.
ℝaphink
@LevBishop: Saya rasa saya memahami masalah ini sedikit lebih baik. Solusi baru harus cukup kuat.
Jonas
@levBishop: Satu lagi pembaruan.
Jonas
1
@LevBishop: Baru saja perhatikan gambar kedua. Ternyata analisis berbasis morfologi melakukan tugasnya.
Jonas
56

Dalam Mathematica, menggunakan erosi dan transformasi Hough:

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

masukkan deskripsi gambar di sini

Edit Menjawab komentar Pak Wisaya

Jika Anda ingin menghilangkan garis horizontal, lakukan saja hal seperti ini (mungkin seseorang bisa membuatnya lebih sederhana):

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

masukkan deskripsi gambar di sini

Belisarius
sumber
1
Mengapa tidak menyingkirkan semua garis horizontal? (+1)
Mr.Wizard
@Pak. Hanya untuk menunjukkan semua jalur terdeteksi ...
Dr. belisarius
1
Namun itu bukan bagian dari masalah, bukan?
Mr.Wizard
@Pak. Diedit sesuai permintaan
Dr. belisarius
4
@belisarius Sistem koordinat yang digunakan dalam transformasi Hough berubah setelah 8.0.0 agar sesuai dengan salah satu dari transformasi Radon. Ini pada gilirannya telah mengubah perilaku ImageLines. Secara keseluruhan ini merupakan peningkatan, meskipun dalam hal ini orang akan lebih suka perilaku sebelumnya. Jika Anda tidak ingin bereksperimen dengan deteksi puncak, Anda dapat mengubah rasio aspek gambar input untuk lebih dekat dengan 1 dan mendapatkan hasil yang serupa dengan 8.0.0: lines = ImageLines[ImageResize[#, {300, 300}], .6, "Segmented" -> True] & /@ i1;. Semua yang dikatakan, untuk masalah ini pendekatan morfologis tampaknya lebih kuat.
Matthias Odisio
29

Hmmm ... Saya kira transformasi Radon tidak mudah untuk diekstrak. (Transformasi Radon pada dasarnya merotasi gambar sambil "melihat menembusnya". Ini adalah prinsip di balik pemindaian CAT.) Transformasi gambar Anda menghasilkan sinogram ini, dengan "sungai" membentuk puncak cerah, yang dilingkari:

masukkan deskripsi gambar di sini

Yang pada rotasi 70 derajat dapat dilihat cukup jelas sebagai puncak di sebelah kiri plot potongan ini sepanjang sumbu horizontal:

masukkan deskripsi gambar di sini

Terutama jika teksnya Gaussian kabur terlebih dahulu:

masukkan deskripsi gambar di sini

Tapi saya tidak yakin bagaimana cara mengekstrak puncak-puncak ini dari kebisingan. Ujung atas dan bawah sinogram yang terang mewakili "sungai" di antara garis-garis horizontal teks, yang jelas tidak Anda pedulikan. Mungkin fungsi bobot vs sudut yang lebih menekankan garis vertikal dan meminimalkan yang horizontal?

Fungsi pembobotan kosinus sederhana bekerja dengan baik pada gambar ini:

masukkan deskripsi gambar di sini

menemukan sungai vertikal pada 90 derajat, yang merupakan puncak global dalam sinogram:

masukkan deskripsi gambar di sini

dan pada gambar ini menemukan satu pada 104 derajat, meskipun kabur pertama membuatnya lebih akurat:

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

( radon()Fungsi SciPy agak bodoh , atau saya akan memetakan puncak ini kembali ke gambar asli sebagai garis yang melewati tengah sungai.)

Tapi itu tidak menemukan salah satu dari dua puncak utama dalam sinogram untuk gambar Anda, setelah kabur dan berat:

masukkan deskripsi gambar di sini

Mereka ada di sana, tetapi mereka kewalahan oleh hal-hal di dekat puncak tengah dari fungsi pembobotan. Dengan pembobotan yang tepat dan penyesuaian metode ini mungkin bisa berhasil, tetapi saya tidak yakin apa yang benar. Mungkin juga tergantung pada properti pemindaian halaman. Mungkin pembobotan perlu berasal dari energi keseluruhan dalam irisan atau sesuatu, seperti normalisasi.

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'
endolit
sumber
Bagaimana jika Anda mengaburkan Gaussian asimetris terlebih dahulu? Yaitu menyempit dalam arah horizontal, lebar dalam arah vertikal.
Jonas
@ Jonas: Itu mungkin akan membantu. Masalah utama adalah secara otomatis mengambil puncak dari latar belakang ketika latar belakang sangat bervariasi dengan rotasi. Buram asimetris dapat menghaluskan garis-garis horizontal dari garis ke garis.
endolith
Ini berfungsi dengan baik untuk mendeteksi rotasi garis dalam teks, setidaknya: gist.github.com/endolith/334196bac1cac45a4893
endolith
16

Saya melatih classifier diskriminatif pada piksel menggunakan fitur turunan (hingga urutan ke-2) pada skala yang berbeda.

Label saya:

Pelabelan

Prediksi pada gambar pelatihan:

masukkan deskripsi gambar di sini

Prediksi pada dua gambar lainnya:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Saya kira ini terlihat menjanjikan dan dapat menghasilkan hasil yang dapat digunakan mengingat lebih banyak data pelatihan dan mungkin fitur yang lebih cerdas. Di sisi lain saya hanya butuh beberapa menit untuk mendapatkan hasil ini. Anda dapat mereproduksi hasil sendiri dengan menggunakan ilastik perangkat lunak sumber terbuka . [Penafian: Saya salah satu pengembang utama.]

Bernhard Kausler
sumber
2

(Maaf, pos ini tidak disertai demonstrasi yang luar biasa.)

Jika Anda ingin bekerja dengan informasi yang sudah dimiliki TeX (huruf dan posisi), Anda dapat secara manual mengklasifikasikan pasangan surat dan huruf sebagai "miring" dalam satu arah atau lainnya. Sebagai contoh, "w" memiliki sudut sudut SW dan SE, kombo "al" memiliki kemiringan sudut NW, "k" memiliki kemiringan sudut sudut NE. (Jangan lupa tanda baca - kutipan yang diikuti oleh surat yang mengisi bagian bawah kotak mesin terbang menghasilkan kemiringan yang bagus; kutipan yang diikuti oleh q sangat kuat.)

Kemudian, cari kejadian kemiringan yang sesuai pada sisi berlawanan dari suatu ruang - "dengan" untuk sungai SW-ke-NE atau "k T" untuk sungai NW-ke-SE. Ketika Anda menemukan satu di garis, lihat apakah yang serupa terjadi, bergeser ke kanan atau kanan, pada garis di atas / di bawah; ketika Anda menemukan jalannya, mungkin ada sungai.

Juga, jelas, hanya mencari ruang yang ditumpuk hampir vertikal, untuk sungai vertikal polos.

Anda bisa mendapatkan sedikit lebih canggih dengan mengukur "kekuatan" lereng: berapa banyak kotak muka "kosong" karena kemiringan dan dengan demikian berkontribusi pada lebar sungai. "w" cukup kecil, karena hanya memiliki sudut kecil kotak muka untuk berkontribusi ke sungai, tetapi "V" sangat kuat. "b" sedikit lebih kuat dari "k"; kurva yang lebih lembut memberikan tepi sungai yang lebih kontinyu secara visual, menjadikannya lebih kuat dan lebih luas secara visual.

Xanthir
sumber