我有一些想法,分享......我想我会沿着这些路线进行:
第1步 - 阈值,以黑色和白色
我想我会用的OpenCV的Otsu分割为这个。
第2步 - 查找垂直的黑线
我将平均像素图像的每一行,并找到一个最低的平均水平,这应该是垂直线向上中间。下面输出代码:
Centreline at column: 1635
步骤3 - 分割图像中的两个并修剪多余的空白空间
步骤4 - 箱式滤波器
我将箱式滤波器一个55x45的盒子与每个段落开头的缩进相匹配,然后是阈值,所以所有的段落开始都用黑色标出框。
我非常新的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);
}
以防万一你需要一只手来建立这个代码 - 因为它似乎不平凡的编译和反对任何联系起来 - 我做了我CMakeLists.txt
文件中像这样并将其存储在同一d作为源文件的irectory。然后,我创建了一个名为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})
@Miki * *不是** ImageMagick ;-) –
哇,谢谢! :)我仍然在研究OpenCV的基础知识,但这似乎是要走的路,并且将尽快进行测试。我也想到矩形的左上角作为坐标。我想最后一部分应该是找到一种方法将它们修剪成实际的矩形,并用它们来设置分割线。 – MrVocabulary
你在Visual Studio/C++中做了这个吗? – MrVocabulary