Pull to refresh

Распознавание коридоров в тексте

Reading time2 min
Views27K
Коридор (river) — совпадение пробелов по вертикали или наклонной линии в трёх и более смежных строках, один из дефектов вёрстки. Дефект устраняется довольно легко, но сложность заключается в его автоматическом обнаружении.

Коридор появляется не только из-за специфичного расположения пробелов, но из-за формы глифов. Например, в двух текстах пробелы расположены в одинаковых местах. В первом хорошо заметны два коридора, а во втором дефекта нет.

               

Логично применить здесь метод с переводом текста в растровую картинку и обработкой изображения.

При обсуждении задачи на StackExchange было предложено два простых и эффективных решения. Возможно, кому-то они тоже окажутся полезными.

1. Открываем изображение с чёрно-белой маской nPix-by-1, где nPix примерно соответствует межстрочному интервалу, то есть количеству пикселов между строками.

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



2. Обрабатываем изображение маской 1-by-mPix, где mPix — минимальная ширина коридора. Так мы избавляемся от слишком тонких линий.

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



3. Избавляемся от горизонтальных «коридоров», которые могут быть вызваны или отступом первой строки, или интервалом между абзацами. Также убираем «озёра» большого размера, просто наложив маску чуть больше, чем nPix-by-nPix. На этом шаге мы избавляемся также от слишком маленьких «речушек», которые имеют размер меньше, чем (nPix+2)*(mPix+2)*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);



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;



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


Tags:
Hubs:
Total votes 83: ↑75 and ↓8+67
Comments48

Articles