텍스트에서 "강"감지


175

TeX 스택 교환 에서이 질문의 단락에서 "강"을 감지하는 방법에 대해 논의했습니다 .

이러한 맥락에서, 강은 텍스트에서 단어 간 공간의 우연한 정렬로 인해 발생하는 공백 밴드입니다. 이것은 독자에게 혼란을 줄 수 있기 때문에 나쁜 강은 타이포그래피의 열악한 증상으로 간주됩니다. 강이있는 텍스트의 예는 대각선으로 흐르는 두 개의 강이있는 것입니다.

여기에 이미지 설명을 입력하십시오

이러한 하천을 자동으로 감지하여 피할 수 있도록 (텍스트를 수동으로 편집하여) 관심이 있습니다. Raphink는 TeX 레벨에서 약간의 진전을 이루고 있지만 (글리프 위치와 경계 상자 만 알고 있음) 강을 감지하는 가장 좋은 방법은 이미지 처리를 사용하는 것입니다 (글리프 모양이 매우 중요하고 TeX에서는 사용할 수 없기 때문에) . 위 이미지에서 강을 추출하는 다양한 방법을 시도했지만 소량의 타원체 블러 링을 적용하는 간단한 아이디어로는 충분하지 않은 것 같습니다. 나는 또한 라돈을 시도거친 변환 기반 필터링이지만 그중에서도 아무 것도 얻지 못했습니다. 강은 인간의 눈 / 망막 / 뇌의 특징 감지 회로에 매우 잘 보입니다. 어떤 아이디어?

구체적으로, 위 이미지에서 2 개의 강을 감지하지만 다른 오 탐지가 너무 많지 않은 작업을 찾고 있습니다.

편집 : endolith는 TeX에서 글리프 위치, 간격 등에 액세스 할 수 있고 이미지를 처리하는 알고리즘을 사용하는 것이 실제 텍스트를 검사하는 알고리즘을 사용하는 것이 훨씬 빠르고 안정적이라는 점을 고려하여 이미지 처리 기반 접근 방식을 추구하는 이유를 물었습니다. 일을 다른 방법을 수행하기위한 내 이유는 것입니다 모양글리프 중 하나는 강이 얼마나 눈에 띄는가에 영향을 줄 수 있으며 텍스트 수준에서이 모양 (글꼴, 합자 등에 따라)을 고려하는 것은 매우 어렵습니다. 글리프의 모양이 어떻게 중요한지에 대한 예를 들어, 다음 두 가지 예를 고려하십시오. 그들 사이의 차이점은 텍스트 기반 분석이 고려할 수 있도록 몇 개의 글리프를 거의 같은 너비의 다른 글리프로 대체 한 것입니다. 그것들은 똑같이 좋거나 나쁘다. 그러나 첫 번째 예의 강은 두 번째 예보다 훨씬 나쁩니다.

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오


5
+1이 질문이 마음에 듭니다. 내 첫 번째 생각은 Hough Transform 이지만 사전 처리가 필요할 것입니다. 아마도 팽창 필터 일 것 입니다.
datageist

실제로 라돈 변환이 작동하지 않는다는 것에 놀랐습니다. 어떻게 했어?
endolith

@endolith : 정교한 것은 없습니다. 나는 ImageLines[]전처리 과정을 거치지 않고 Mathematica에서 사용 했습니다. 이것이 기술적으로 라돈 변환 대신 허프를 사용하는 것 같습니다. 적절한 전처리 (datageist의 제안 된 확장 필터를 시도하지 않았 음) 및 / 또는 매개 변수 설정 이이 작업을 수행 할 수 있는지 놀라지 않을 것입니다.
Lev Bishop

강에 대한 Google 이미지 검색에도 "감기"강이 표시됩니다. 그것들을 찾고 싶습니까? cdn.ilovetypography.com/img/text-river1.gif
endolith

@endolith 필자는 궁극적으로 공간의 특정 구성을 산만하게 만드는 인간 시각 시스템의 처리를 복제하고 싶다고 생각합니다. 이것은 구불 구불 한 강에서도 발생할 수 있기 때문에 직선 강이 일반적으로 더 문제가되는 것처럼 보이지만 그 강을 잡고 싶습니다. 텍스트를 읽을 때 강이 얼마나 잘 보이는지에 따라 강의 "나쁜 점"을 정량화하는 방법이 더 좋습니다. 그러나 그것은 매우 주관적이고 정량화하기가 어렵습니다. 우선, 너무 많은 거짓 긍정없이 실제로 모든 나쁜 강을 잡는 것은 할 것입니다.
Lev Bishop

답변:


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) 1xmPix 마스크로 이미지를 열어 강이 되기에는 너무 좁은 것을 제거하십시오.

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

여기에 이미지 설명을 입력하십시오

(3) 단락 사이의 공간 또는 들여 쓰기로 인한 수평 "강과 호수"를 제거하십시오. 이를 위해 모든 행을 제거하고 이전에 찾은 강에 영향을 미치지 않는 nPix-by-1 마스크로 엽니 다.

호수를 제거하기 위해 nPix-n-nPix보다 약간 큰 오프닝 마스크를 사용할 수 있습니다.

이 단계에서, 우리는 실제 강이 되기에는 너무 작은 모든 것, 즉 (nPix + 2) * (mPix + 2) * 4 (~ 3 줄을 줄 것입니다)보다 적은 면적을 커버하는 모든 것을 버릴 수 있습니다. +2는 모든 객체의 높이가 최소 nPix이고 너비가 mPix라는 것을 알고 있기 때문에 그보다 조금 더 가고 싶습니다.

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

여기에 이미지 설명을 입력하십시오

(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 배로 꺼져 있지만)

이제 연결된 각 구성 요소의 픽셀 수와 픽셀 값의 평균을 계산하여 평균 너비를 계산하여 강의 대략적인 길이를 얻을 수 있습니다.


다음은 "강이없는"두 번째 이미지에 적용되는 것과 정확히 동일한 분석입니다.

여기에 이미지 설명을 입력하십시오


감사. Matlab이 있으므로 다른 텍스트 에서이 기능을 사용하여 얼마나 강력한 지 확인할 것입니다.
Lev Bishop

어떻게 든 그것을 Lua로 포팅 할 수 없다면 TeX에 다시 통합하는 것은 또 다른 문제 일 수 있습니다.
ℝaphink

@ LevBishop : 나는이 문제를 조금 더 잘 이해한다고 생각합니다. 새로운 솔루션은 상당히 강력해야합니다.
Jonas

@levBishop : 하나 더 업데이트.
Jonas

1
@LevBishop : 방금 두 번째 이미지를 보았습니다. 형태학 기반 분석이 그 일을한다는 것이 밝혀졌습니다.
Jonas

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

여기에 이미지 설명을 입력하십시오

Mr. Wizard의 답변 답변 편집

수평선을 제거하려면 다음과 같이하십시오 (아마도 누군가가 간단하게 만들 수 있음).

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

여기에 이미지 설명을 입력하십시오


1
모든 수평선을 제거하지 않겠습니까? (+1)
Mr.Wizard의

@씨. 모든 선이 감지되고 있음을 보여주기 위해 ...
Dr. belisarius

1
그것은 문제의 일부가 아닙니다.
Mr.Wizard

@씨. 요청에 따라 편집
belisarius 박사

4
@belisarius Hough 변환에 사용 된 좌표계는 8.0.0 이후에 Radon 변환 중 하나와 일치하도록 변경되었습니다. 이로 인해 ImageLine의 동작이 변경되었습니다. 전반적으로 이것은 개선이지만이 경우 이전 동작을 선호합니다. 피크 검출을 실험하지 않으려면 입력 이미지의 종횡비를 1에 가깝게 변경하고 8.0.0 :과 유사한 결과를 얻을 수 있습니다 lines = ImageLines[ImageResize[#, {300, 300}], .6, "Segmented" -> True] & /@ i1;. 이 문제에 대해 형태 학적 접근 방식이 더 강력 해 보입니다.
Matthias Odisio

29

흠 ... 라돈 변환 은 추출하기 쉽지 않다고 생각 합니다. (라돈 변환은 기본적으로 이미지를 통해 보면서 이미지를 회전시킵니다. CAT 스캔의 기본 원리입니다.) 이미지 변환은 "강"이 밝은 피크를 형성하는이 사이 노 그램을 생성합니다.

여기에 이미지 설명을 입력하십시오

70도 회전하는 것은 가로 축을 따라 슬라이스 의이 플롯의 왼쪽에있는 피크로 매우 명확하게 볼 수 있습니다.

여기에 이미지 설명을 입력하십시오

특히 텍스트가 Gaussian이 먼저 흐리게 표시된 경우 :

여기에 이미지 설명을 입력하십시오

그러나 나머지 노이즈에서 이러한 피크를 안정적으로 추출하는 방법을 잘 모르겠습니다. 사이 노 그램의 밝은 상단과 하단은 텍스트의 가로줄 사이의 "강"을 나타내며, 신경 쓰지 않아도됩니다. 더 많은 수직선을 강조하고 수평선을 최소화하는 가중치 기능 대 각도 일 수 있습니까?

이 이미지에서 간단한 코사인 가중치 기능이 잘 작동합니다.

여기에 이미지 설명을 입력하십시오

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'

비대칭 가우스로 먼저 흐릿하게하려면 어떻게해야합니까? 즉, 수평 방향으로 좁고 수직 방향으로 넓습니다.
Jonas

@Jonas : 아마 도움이 될 것입니다. 주된 문제는 배경이 회전에 따라 크게 변할 때 배경에서 피크를 자동으로 선택하는 것입니다. 비대칭 블러는 가로줄을 줄마다 다듬을 수 있습니다.
endolith

이 텍스트에서, 적어도 라인의 회전을 검출 잘 작동 gist.github.com/endolith/334196bac1cac45a4893
endolith을

16

다른 스케일에서 미분 기능 (최대 2 차)을 사용하여 픽셀에서 차별적 분류기를 훈련했습니다.

내 라벨 :

라벨링

훈련 이미지에 대한 예측 :

여기에 이미지 설명을 입력하십시오

다른 두 이미지에 대한 예측 :

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

나는 이것이 유망한 것으로 보이며 더 많은 훈련 데이터와 더 똑똑한 기능으로 인해 유용한 결과를 얻을 수 있다고 생각합니다. 반면에이 결과를 얻는 데 몇 분 밖에 걸리지 않았습니다. 오픈 소스 소프트웨어 ilastik 을 사용하여 결과를 직접 재현 할 수 있습니다 . [면책 조항 : 저는 주요 개발자 중 한 명입니다.]


2

(죄송합니다.이 게시물에는 멋진 데모가 제공되지 않습니다.)

TeX에 이미 가지고있는 정보 (문자 및 위치)로 작업하려면 문자와 문자 쌍을 한 방향 또는 다른 방향으로 "경사"로 수동으로 분류 할 수 있습니다. 예를 들어 "w"에는 SW 및 SE 코너 기울기가 있고 "al"콤보에는 NW 코너 기울기가 있으며 "k"에는 NE 코너 기울기가 있습니다. 문장 부호를 잊지 마십시오-문자 상자의 아래쪽 절반을 채우는 문자 다음에 인용 부호가 있으면 좋은 경사가됩니다. 따라서 인용 부호가 특히 강합니다.

그런 다음 공간의 반대편에 해당 경사가 나타나는지 확인하십시오 (SW-to-NE 강의 경우 "w al"또는 NW-SE-SE 강의 경우 "k T"). 한 줄에서 하나를 찾으면 위 / 아래 줄에서 비슷한 것이 발생하는지, 왼쪽이나 오른쪽으로 적절히 이동했는지 확인하십시오. 당신이 이것의 실행을 발견하면 아마 강이있을 수 있습니다.

또한 평범한 수직 강을 위해 거의 수직으로 쌓인 공간을 찾으십시오.

경사면의 "강도"를 측정하여 조금 더 정교해질 수 있습니다. 경사면으로 인해 고급 상자의 "빈"정도가 강 너비에 기여합니다. "w"는 강에 기여할 수있는 전진 상자의 작은 모서리 만 가지고 있기 때문에 상당히 작지만 "V"는 매우 강합니다. "b"는 "k"보다 약간 강하다. 부드러운 곡선은 시각적으로 연속적인 강 가장자리를 제공하여 강하고 시각적으로 넓어집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.