पाठ में "नदी" का पता लगाना


175

टीईएक्स स्टैकएक्सचेंज पर, हम इस प्रश्न में पैराग्राफ में "नदियों" का पता लगाने के बारे में चर्चा कर रहे हैं ।

इस संदर्भ में, नदियाँ श्वेत स्थान की पट्टी होती हैं, जो पाठ में अंतरजाल के आकस्मिक संरेखण से उत्पन्न होती हैं। चूंकि यह एक पाठक को काफी विचलित कर सकता है खराब नदियों को खराब टाइपोग्राफी का एक लक्षण माना जाता है। नदियों के साथ पाठ का एक उदाहरण यह है, जहां दो नदियाँ तिरछे रूप से बहती हैं।

यहां छवि विवरण दर्ज करें

इन नदियों का स्वचालित रूप से पता लगाने में रुचि है, ताकि उन्हें टाला जा सके (संभवतः पाठ के मैनुअल संपादन द्वारा)। रैफिंक टीएक्स स्तर पर कुछ प्रगति कर रहा है (जो केवल ग्लिफ़ पदों और बाउंडिंग बॉक्स के बारे में जानता है), लेकिन मुझे विश्वास है कि नदियों का पता लगाने का सबसे अच्छा तरीका कुछ छवि प्रसंस्करण के साथ है (चूंकि ग्लिफ़ आकार बहुत महत्वपूर्ण हैं और टीएक्स के लिए उपलब्ध नहीं हैं) । मैंने उपरोक्त छवि से नदियों को निकालने के विभिन्न तरीकों की कोशिश की है, लेकिन एलीपिपोलाइडल धुंधलापन की एक छोटी मात्रा को लागू करने का मेरा सरल विचार अच्छा नहीं लगता है। मैंने कुछ राडोण भी आजमाएपर्याप्त रूप से फ़िल्टरिंग आधारित रूपांतरण, लेकिन मैं कहीं भी उन लोगों के साथ नहीं मिला। मानव आंख / रेटिना / मस्तिष्क के फीचर-डिटेक्शन सर्किट में नदियां बहुत दिखाई देती हैं और किसी तरह मुझे लगता है कि इसका अनुवाद किसी प्रकार के फ़िल्टरिंग ऑपरेशन में किया जा सकता है, लेकिन मैं इसे काम करने में सक्षम नहीं हूं। कोई विचार?

विशिष्ट होने के लिए, मैं कुछ ऑपरेशन की तलाश कर रहा हूं जो उपरोक्त छवि में 2 नदियों का पता लगाएगा, लेकिन बहुत अधिक झूठे सकारात्मक सकारात्मक नहीं हैं।

EDIT: एंडोलिथ ने पूछा कि मैं एक छवि-प्रसंस्करण-आधारित दृष्टिकोण का अनुसरण क्यों कर रहा हूं, यह देखते हुए कि TeX में हमारे पास ग्लिफ़ पोज़िशन, स्पेसिंग आदि हैं, और वास्तविक टेक्स्ट की जांच करने वाले एल्गोरिथ्म का उपयोग करने के लिए यह बहुत तेज़ और अधिक विश्वसनीय हो सकता है। चीजों को दूसरे तरीके से करने का मेरा कारण यह है कि आकारग्लिफ़ प्रभावित कर सकते हैं कि एक नदी कितनी ध्यान देने योग्य है, और पाठ स्तर पर इस आकृति पर विचार करना बहुत मुश्किल है (जो फ़ॉन्ट पर निर्भर करता है, लिगेटिंग पर, आदि)। एक उदाहरण के लिए कि ग्लिफ़ का आकार कैसे महत्वपूर्ण हो सकता है, निम्नलिखित दो उदाहरणों पर विचार करें, जहाँ उनके बीच का अंतर यह है कि मैंने कुछ समान चौड़ाई वाले अन्य लोगों के साथ कुछ ग्लिफ़ों को प्रतिस्थापित किया है, ताकि एक पाठ-आधारित विश्लेषण पर विचार किया जा सके। उन्हें समान रूप से अच्छा / बुरा। हालाँकि, ध्यान दें कि पहले उदाहरण में नदियाँ दूसरे की तुलना में बहुत खराब हैं।

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें


5
+1 मुझे यह सवाल पसंद है। मेरा पहला विचार एक Hough Transform है , लेकिन इसे शायद कुछ पूर्व-प्रसंस्करण की आवश्यकता होगी। हो सकता है कि पहले एक Dilation फ़िल्टर
datageist

मुझे आश्चर्य है कि रेडॉन ट्रांसफॉर्म वास्तव में काम नहीं कर रहा है। तुमने ये कैसे किया?
एंडोलिथ

@endolith: कुछ भी नहीं परिष्कृत। मैंने ImageLines[]मैथेमेटिका से, कुछ प्रीप्रोसेसिंग के साथ और बिना उपयोग किया । मुझे लगता है कि यह तकनीकी रूप से रैडॉन ट्रांसफ़ॉर्म के बजाय हॉफ का उपयोग कर रहा है। मुझे आश्चर्य नहीं होगा यदि उचित प्रीप्रोसेसिंग (मैंने डाटेजिस्ट के सुझाए गए फैलाव फिल्टर की कोशिश नहीं की) और / या पैरामीटर सेटिंग्स यह काम कर सकती हैं।
लेव बिशप

नदियों के लिए Google छवि खोज "घुमावदार" नदियों को भी दिखाती है। क्या आप उन्हें ढूंढना चाहते हैं? cdn.ilovetypography.com/img/text-river1.gif
endolith

@endolith मुझे लगता है कि मैं अंततः मानव दृश्य प्रणाली के प्रसंस्करण को दोहराना चाहता हूं जो रिक्त स्थान के कुछ विन्यास को विचलित करता है। चूँकि यह नदियों के गलन के लिए भी हो सकता है, तो मैं उन लोगों को पकड़ना चाहूँगा, हालाँकि सीधे लोग सामान्य रूप से एक समस्या के अधिक प्रतीत होते हैं। इससे भी बेहतर यह है कि एक तरह से नदियों की "बदबू" को निर्धारित किया जाए जो कि पाठ को पढ़ते समय कितनी दृढ़ता से दिखाई दे। लेकिन यह सब बहुत व्यक्तिपरक और कठिन है। पहली जगह में, वास्तव में बहुत सारी गलत नदियों के बिना सभी बुरी नदियों को पकड़ना होगा।
लेव बिशप

जवाबों:


135

मैंने इसके बारे में कुछ और सोचा है, और सोचता हूं कि निम्नलिखित काफी स्थिर होना चाहिए। ध्यान दें कि मैंने खुद को रूपात्मक कार्यों तक सीमित कर लिया है, क्योंकि ये किसी भी मानक छवि प्रसंस्करण पुस्तकालय में उपलब्ध होना चाहिए।

(1) एक nPix-by-1 मुखौटा के साथ खुली छवि, जहां nPix अक्षरों के बीच ऊर्ध्वाधर दूरी के बारे में है

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

यहां छवि विवरण दर्ज करें

(2) एक नदी होने के लिए जो कुछ भी संकीर्ण है, उसे खत्म करने के लिए 1-बाय-mPix मास्क के साथ खुली छवि।

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

यहां छवि विवरण दर्ज करें

(3) क्षैतिज "नदियों और झीलों" को हटा दें जो पैराग्राफ या इंडेंटेशन के बीच की जगह के कारण हैं। इसके लिए, हम उन सभी पंक्तियों को हटाते हैं जो सभी सत्य हैं, और nix-by-1 मास्क के साथ खुली हैं जो हमें पता है कि हम उन नदियों को प्रभावित नहीं करेंगे जो हमने पहले पाई हैं।

झीलों को हटाने के लिए, हम एक शुरुआती मास्क का उपयोग कर सकते हैं जो nix-by-nPix से थोड़ा बड़ा है।

इस कदम पर, हम वह सब कुछ भी निकाल सकते हैं जो वास्तविक नदी होने के लिए बहुत छोटा है, अर्थात वह सब कुछ जो (nix + 2) * (mPix + 2) * 4 से कम क्षेत्र को कवर करता है (जो हमें ~ 3 पंक्तियाँ देगा)। +2 वहाँ है क्योंकि हम जानते हैं कि सभी ऑब्जेक्ट्स ऊंचाई में कम से कम nix हैं, और चौड़ाई में mix, और हम उससे थोड़ा ऊपर जाना चाहते हैं।

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

यहां छवि विवरण दर्ज करें

(४) यदि हम न केवल लंबाई, बल्कि नदी की चौड़ाई में भी रुचि रखते हैं, तो हम कंकाल के साथ दूरी परिवर्तन को जोड़ सकते हैं।

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

   riversWithWidth = dt.*sk;

यहां छवि विवरण दर्ज करें (रंग नदी की चौड़ाई के अनुरूप हैं (हालांकि रंग पट्टी 2 के कारक से बंद है)

अब आप प्रत्येक जुड़े घटक में पिक्सेल की संख्या और उनके पिक्सेल मूल्यों के औसत से औसत चौड़ाई की गणना करके नदियों की अनुमानित लंबाई प्राप्त कर सकते हैं।


यहाँ सटीक वही विश्लेषण है जो दूसरी, "नो-रिवर" छवि पर लागू होता है:

यहां छवि विवरण दर्ज करें


धन्यवाद। मेरे पास माटलैब है इसलिए मैं कुछ अन्य ग्रंथों पर यह देखने की कोशिश करूंगा कि यह कितना मजबूत होगा।
लेव बिशप

यह TeX में वापस एकीकृत करने के लिए एक और समस्या हो सकती है, जब तक कि हम लुआ को किसी तरह पोर्ट नहीं कर सकते।
.अफिंक

@LevBishop: मुझे लगता है कि मैं इस मुद्दे को थोड़ा बेहतर समझता हूं। नया समाधान काफी मजबूत होना चाहिए।
जोनास

@levBishop: एक और अपडेट।
जोनास 12

1
@LevBishop: बस दूसरी छवि देखी। आकृति विज्ञान आधारित विश्लेषण अपना काम करता है।
जोनास

56

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

यहां छवि विवरण दर्ज करें


1
सभी क्षैतिज रेखाओं से छुटकारा क्यों नहीं? (+1)
श्री। छिपकली

@श्री। बस सभी लाइनों को दिखाने के लिए पता लगाया जा रहा है ...
डॉ। बेलिसियस

1
हालांकि यह समस्या का हिस्सा नहीं है, क्या यह है?
मि। छिपकली

@श्री। अनुरोध के अनुसार संपादित किया गया
डॉ। बेलिसियस

4
@belisarius होफ ट्रांसफॉर्म में इस्तेमाल की जाने वाली समन्वय प्रणाली 8.0.0 के बाद बदलकर रेडॉन ट्रांसफॉर्म में से एक से मेल खाती है। यह बदले में ImageLines के व्यवहार को बदल दिया है। कुल मिलाकर यह एक सुधार है, हालांकि इस मामले में कोई भी पिछले व्यवहार को पसंद करेगा। यदि आप पीक डिटेक्शन के साथ प्रयोग नहीं करना चाहते हैं, तो आप इनपुट छवि के पहलू अनुपात को 1 के करीब और 8.0.0 के समान परिणाम प्राप्त कर सकते हैं lines = ImageLines[ImageResize[#, {300, 300}], .6, "Segmented" -> True] & /@ i1;:। कहा जा रहा है कि इस समस्या के लिए एक रूपात्मक दृष्टिकोण अधिक मजबूत है।
मथायस ओडिसियो

29

हम्म् ... मुझे लगता है कि रैडॉन ट्रांसफ़ॉर्म से निकालना आसान नहीं है। (रैडॉन ट्रांसफ़ॉर्म मूल रूप से छवि को घुमाता है, जबकि "इसके माध्यम से देख रहा है" किनारे पर। यह कैट स्कैन के पीछे का सिद्धांत है।) आपकी छवि का परिवर्तन इस साइनोग्राम का निर्माण करता है, जिसमें "नदियां" उज्ज्वल चोटियों का निर्माण करती हैं, जो चक्कर लगाती हैं:

यहां छवि विवरण दर्ज करें

70 डिग्री पर घूमने वाले को क्षैतिज अक्ष के साथ एक स्लाइस के इस भूखंड के बाईं ओर चोटी के रूप में स्पष्ट रूप से देखा जा सकता है:

यहां छवि विवरण दर्ज करें

खासकर अगर पाठ पहले गॉसियन धुंधला था:

यहां छवि विवरण दर्ज करें

लेकिन मुझे यकीन नहीं है कि आराम से इन चोटियों को बाकी शोर से कैसे निकाला जाए। साइनोग्राम के उज्ज्वल ऊपर और नीचे के छोर पाठ की क्षैतिज रेखाओं के बीच "नदियों" का प्रतिनिधित्व करते हैं, जिनके बारे में आपको स्पष्ट रूप से परवाह नहीं है। हो सकता है कि एक भारित कार्य बनाम कोण जो अधिक ऊर्ध्वाधर रेखाओं पर जोर देता है और क्षैतिज को कम करता है?

एक साधारण कोसाइन वेटिंग फंक्शन इस छवि पर अच्छा काम करता है:

यहां छवि विवरण दर्ज करें

वर्टिकल रिवर को 90 डिग्री पर खोजना, जो कि साइनोग्राम में ग्लोबल मैक्सिमा है:

यहां छवि विवरण दर्ज करें

और इस छवि को 104 डिग्री पर खोजने पर, हालांकि पहले धुंधला होना इसे और अधिक सटीक बनाता है:

यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें

(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'

क्या होगा यदि आप पहले एक असममित गौसियन के साथ धुंधला हो गए थे? क्षैतिज दिशा में संकीर्ण, ऊर्ध्वाधर दिशा में चौड़ा।
जोनास

@ जोनास: जो शायद मदद करेगा। मुख्य समस्या स्वचालित रूप से पृष्ठभूमि से चोटियों को उठा रही है जब पृष्ठभूमि रोटेशन के साथ बहुत भिन्न होती है। असममित धुंधलापन लाइन से लाइन तक क्षैतिज पट्टियों को चिकना कर सकता है।
एंडोलिथ

यह पाठ में लाइनों के रोटेशन का पता लगाने के लिए अच्छी तरह से काम करता है, कम से कम: gist.github.com/endolith/334196bac1cac45a4893
endolith

16

मैंने अलग-अलग पैमानों पर व्युत्पन्न सुविधाओं (2 के क्रम तक) का उपयोग करते हुए पिक्सल पर एक विभेदक क्लासिफायरियर का प्रशिक्षण दिया।

मेरे लेबल:

लेबलिंग

प्रशिक्षण छवि पर भविष्यवाणी:

यहां छवि विवरण दर्ज करें

अन्य दो छवियों पर भविष्यवाणी:

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

मुझे लगता है कि यह आशाजनक लग रहा है और अधिक प्रशिक्षण डेटा और शायद होशियार सुविधाओं को दिया जा सकने योग्य परिणाम दे सकता है। दूसरी ओर इन परिणामों को प्राप्त करने में मुझे केवल कुछ ही मिनट लगे। आप ओपन सोर्स सॉफ्टवेयर ilastik का उपयोग करके परिणामों को स्वयं पुन: उत्पन्न कर सकते हैं । [अस्वीकरण: मैं मुख्य डेवलपर्स में से एक हूं।]


2

(क्षमा करें, यह पोस्ट भयानक प्रदर्शनों के साथ नहीं आती है।)

यदि आप सूचना के साथ काम करना चाहते हैं तो TeX में पहले से ही (अक्षर और स्थिति) हैं, आप मैन्युअल रूप से अक्षरों और अक्षर जोड़े को एक दिशा या किसी अन्य में "झुका हुआ" के रूप में वर्गीकृत कर सकते हैं। उदाहरण के लिए, "w" में SW और SE कोने की ढलान है, "al" कॉम्बो में एक NW कोने की ढलान है, "k" में एक NE कोने की ढलान है। (विराम चिह्न न भूलें - एक उद्धरण जिसके बाद एक अक्षर होता है जो ग्लिफ़ बॉक्स के निचले आधे हिस्से को भरता है, एक अच्छा ढलान स्थापित करता है; क्यू द्वारा पीछा किया गया उद्धरण विशेष रूप से मजबूत है।)

फिर, एक स्थान के विपरीत किनारों पर संबंधित ढलानों की घटनाओं की तलाश करें - एक एनडब्ल्यू-से-एसई नदी के लिए एक स्व-से-एनई नदी या "के टी" के लिए "डब्ल्यू अल"। जब आप एक लाइन पर एक पाते हैं, तो देखें कि क्या एक समान होता है, उचित रूप से बाएं या दाएं, ऊपर या नीचे की लाइनों पर; जब आप इनमें से एक रन पाते हैं, तो शायद एक नदी है।

इसके अलावा, जाहिर है, बस खड़ी ऊर्ध्वाधर नदियों के लिए लगभग खड़ी खड़ी रिक्त स्थान की तलाश करें।

ढलान की "ताकत" को मापकर आप थोड़ा और अधिक परिष्कृत हो सकते हैं: ढलान के कारण अग्रिम बॉक्स का कितना हिस्सा "खाली" है और इस तरह नदी की चौड़ाई में योगदान कर रहा है। "डब्ल्यू" काफी छोटा है, क्योंकि इसमें नदी को योगदान देने के लिए इसके अग्रिम बॉक्स का केवल एक छोटा सा कोना है, लेकिन "वी" बहुत मजबूत है। "बी" "के" की तुलना में थोड़ा मजबूत है; जेंटलर वक्र एक अधिक नेत्रहीन-निरंतर नदी का किनारा देता है, जिससे यह मजबूत और नेत्रहीन व्यापक हो जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.