2017-02-11 15 views
2

Я провел некоторое исследование по этому вопросу, но я думаю, что мой вопрос существенно отличается от того, что было задано раньше.Простые способы обнаружения и обрезки блоков (абзацев) текста из образа?

Моя дипломная работа посвящена распознаванию старого словаря и преобразованию результата в XML-подобную базу данных автоматически. Эта часть я выяснил. Тем не менее, я хотел бы обогатить конечный результат, показывая фрагмент сканирования, используемый для каждой записи/заголовка. Поскольку словарь составляет почти 9000 страниц, делать это вручную не может быть и речи.

Это как случайная страница выглядит: http://i.imgur.com/X2mPZr0.png

Поскольку каждая запись всегда соответствует одному пункту, я хотел бы найти способ, чтобы разделить каждое изображение на прямоугольники с текстом (не требует OCR) в виде отдельных файлов, как это (без рисования прямоугольников): http://i.imgur.com/CWtQD6Q.png

Хорошо, что сканирование, которое у меня есть, идентично по форме и размеру и аналогично с точки зрения выравнивания полей/текста. У каждого абзаца всегда есть идентификация.

Плохо то, что я в основном лингвист и не много программиста. Большая часть моего опыта связана с Ruby, XML и CSS. И что некоторые абзацы являются только однострочными.

Я знаю некоторых способов сделать с подобной вещи:

, но они требуют значительного времени для мне узнать (особенно, что у меня есть 0 знаний в Pytho n), и я не знаю, разрешают ли они не только обнаружение текста, но и определение абзаца.

Любые ввод/предложение по этому вопросу были бы весьма полезными, особенно новичкам.

ответ

2

У меня есть несколько идей, чтобы поделиться ... Я думаю, что я бы идти по этим линиям:

Шаг 1 - Порог в черно-белый

Я думаю, что я хотел бы использовать Оцу пороговую OpenCV для это.

Шаг 2 - Найти вертикальная черная линия

Я бы усреднить пикселей в каждом столбце изображения и найти один с самым низким средним и что должно быть вертикальная линия до середины.Код ниже выходов:

Centreline at column: 1635 

Шаг 3 - Разделить изображение на две части и обрезать избыток белого пространства

enter image description hereenter image description here

Шаг 4 - Вставка фильтра

Я бы боксировать фильтр с полем 55x45, который соответствует отступу в начале каждого абзаца, тогда порог, поэтому все начальные абзацы отмечены черным коробки.

enter image description here

Я довольно новыми для OpenCV, но закодированы вышеуказанные идеи следующим образом: - Я уверен, что много из него можно было бы сделать более надежными и более эффективными, так относиться к ней как концептуальное ;-)

#include <iostream> 
#include <opencv2/opencv.hpp> 

using namespace cv; 
using namespace std; 

int 
main(int argc,char*argv[]) 
{ 
    // Load image 
    Mat orig=imread("page.png",IMREAD_COLOR); 

    vector<int> PNGwriteOptions; 
    PNGwriteOptions.push_back(CV_IMWRITE_PNG_COMPRESSION); 
    PNGwriteOptions.push_back(9); 

    // Get greyscale and Otsu-thresholded version 
    Mat bw,grey; 
    cvtColor(orig,grey,CV_RGB2GRAY); 
    threshold(grey,bw,0,255,CV_THRESH_BINARY|CV_THRESH_OTSU); 

    // Find vertical centreline by looking for lowest column average - i.e. darkest vertical bar 
    Mat colsums; 
    reduce(bw,colsums,0,CV_REDUCE_AVG); 
    double min,max; 
    Point min_loc, max_loc; 
    minMaxLoc(colsums,&min,&max,&min_loc,&max_loc); 
    cout << "Centreline at column: " << min_loc.x << endl; 

    namedWindow("test",CV_WINDOW_AUTOSIZE); 

    // Split image into left and right 
    Rect leftROI(0,0,min_loc.x,bw.rows); 
    Mat leftbw=bw(leftROI); 
    Rect rightROI(min_loc.x+8,0,bw.cols-min_loc.x-8,bw.rows); 
    Mat rightbw=bw(rightROI); 
    imshow("test",leftbw); 
    waitKey(0); 
    imshow("test",rightbw); 
    waitKey(0); 

    // Trim surrounding whitespace off 
    Mat Points; 
    Mat inverted = cv::Scalar::all(255) - leftbw; 
    findNonZero(inverted,Points); 
    Rect bRect=boundingRect(Points); 
    Mat lefttrimmed=leftbw(bRect); 

    inverted = cv::Scalar::all(255) - rightbw; 
    findNonZero(inverted,Points); 
    bRect=boundingRect(Points); 
    Mat righttrimmed=rightbw(bRect); 

    imwrite("lefttrimmed.png",lefttrimmed,PNGwriteOptions); 
    imwrite("righttrimmed.png",righttrimmed,PNGwriteOptions); 

    // Box filter with 55x45 rectangle to match size of paragraph indent on left 
    Mat lBoxFilt,rBoxFilt; 
    boxFilter(lefttrimmed,lBoxFilt,-1,Size(55,45)); 
    normalize(lBoxFilt,lBoxFilt,0,255,NORM_MINMAX,CV_8UC1); 
    threshold(lBoxFilt,lBoxFilt,254,255,THRESH_BINARY_INV); 
    imwrite("leftBoxed.png",lBoxFilt,PNGwriteOptions); 

} 

enter image description here

Только в случае, если вам нужна рука, чтобы построить этот код - как это кажется нетривиальным компилировать и компоновать ничего против него - я сделал свой CMakeLists.txt файл, как это и хранить его в том же г как исходный файл. Затем я создаю подкаталог build, чтобы сделать «вне источника» сборки в и процесс сборки:

cd build 
cmake .. 
make -j 8 
./demo 

CMakeLists.txt

cmake_minimum_required(VERSION 2.8) 
project(demo) 
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 
find_package(OpenCV) 
add_executable(demo main.cpp) 
target_link_libraries(demo ${OpenCV_LIBS}) 
+0

@Miki * * Не ** ImageMagick ;-) –

+0

Ничего себе, спасибо! :) Я все еще разрабатываю основы OpenCV, но, похоже, это способ пойти и будет проверять его как можно скорее. Я также подумал о верхнем левом углу прямоугольников в качестве координат. Думаю, последняя часть должна найти способ обрезать их в фактические прямоугольники и использовать их для создания линий разделения. – MrVocabulary

+0

Вы сделали это в Visual Studio/C++? – MrVocabulary