Ось ще альтернативне рішення вашої проблеми, моделюючи ваше питання як "проблему оптимізації шляху". Хоча це складніше, ніж просте рішення щодо бінаризації, а потім-кривих, воно є більш надійним на практиці.
З дуже високого рівня ми повинні розглядати це зображення як графік, де
кожен піксель зображення - це вузол на цьому графіку
кожен вузол з'єднаний з деякими іншими вузлами, відомими як сусіди, і це визначення з'єднання часто називають топологією цього графіка.
кожен вузол має вагу (функцію, вартість, енергію або все, що ви хочете назвати), що відображає ймовірність того, що цей вузол знаходиться в оптимальній центральній лінії, яку ми шукаємо.
Поки ми можемо моделювати цю ймовірність, тоді ваша проблема пошуку «центральних ліній меж» стає проблемою пошуку локальних оптимальних шляхів на графіку , які можна ефективно вирішити за допомогою динамічного програмування, наприклад, алгоритму Вітербі.
Ось деякі плюси використання цього підходу:
всі ваші результати будуть безперервними (на відміну від порогового методу, який може розбити одну центральну лінію на частини)
дуже багато свобод для побудови такого графіка, ви можете вибрати різні функції та топологію графа.
ваші результати оптимальні в сенсі оптимізації шляху
ваше рішення буде більш надійним щодо шуму, оскільки поки шум рівномірно розподілений між усіма пікселями, ці оптимальні шляхи залишаються стабільними.
Ось коротка демонстрація вищезазначеної ідеї. Оскільки я не використовую будь-яких попередніх знань для визначення можливих початкових і кінцевих вузлів, я просто декодую wrt кожен можливий стартовий вузол.
Для нечітких закінчень це викликано тим, що ми шукаємо оптимальні шляхи для всіх можливих кінцевих вузлів. Як результат, хоча для деяких вузлів, розташованих у темних областях, виділений шлях все одно є його локальним оптимальним.
Для нечіткого шляху ви можете або згладити його після того, як його знайдете, або використовувати деякі згладжені функції замість сирого інтенсивності.
Можна відновити часткові шляхи, змінивши початкові та кінцеві вузли.
Обрізати ці небажані локальні оптимальні шляхи буде непросто. Оскільки у нас є ймовірність усіх шляхів після декодування вітербі, і ви можете використовувати різні попередні знання (наприклад, ми бачимо, що це правда, що нам потрібен лише один оптимальний шлях для тих, хто ділиться тим самим джерелом.)
Для отримання більш детальної інформації ви можете звернутися до статті.
Wu, Y.; Zha, S.; Cao, H.; Liu, D., & Natarajan, P. (2014, February). A Markov Chain Line Segmentation Method for Text Recognition. In IS&T/SPIE 26th Annual Symposium on Electronic Imaging (DRR), pp. 90210C-90210C.
Ось короткий фрагмент пітонного коду, який використовується для створення вищевказаного графіка.
import cv2
import numpy as np
from matplotlib import pyplot
# define your image path
image_path = ;
# read in an image
img = cv2.imread( image_path, 0 );
rgb = cv2.imread( image_path, -1 );
# some feature to reflect how likely a node is in an optimal path
img = cv2.equalizeHist( img ); # equalization
img = img - img.mean(); # substract DC
img_pmax = img.max(); # get brightest intensity
img_nmin = img.min(); # get darkest intensity
# express our preknowledge
img[ img > 0 ] *= +1.0 / img_pmax;
img[ img = 1 :
prev_idx = vt_path[ -1 ].astype('int');
vt_path.append( path_buffer[ prev_idx, time ] );
time -= 1;
vt_path.reverse();
vt_path = np.asarray( vt_path ).T;
# plot found optimal paths for every 7 of them
pyplot.imshow( rgb, 'jet' ),
for row in range( 0, h, 7 ) :
pyplot.hold(True), pyplot.plot( vt_path[row,:], c=np.random.rand(3,1), lw = 2 );
pyplot.xlim( ( 0, w ) );
pyplot.ylim( ( h, 0 ) );