文档图像SauvolA二值化算法C++实现
这个二值化算法主要针对文档图像,原理较复杂,感兴趣的同学可以自己搜一下论文看看。下面先给出代码
void SauvolA(vector
{
char version;
int c;
int winx = 0, winy = 0;
float optK = 0.5;
bool didSpecifyK = false;
string Saveroot;
// Determine the method
for (int i = 0;i < FilesVec.size();i++)
{
cout << "image name: " << FilesVec[i] << endl;
Mat input = imread(FilesVec[i], CV_LOAD_IMAGE_GRAYSCALE);
if ((input.rows <= 0) || (input.cols <= 0))
{
cout << "*** ERROR: Couldn't read input image " << FilesVec[i] << endl;
exit(1);
}
Saveroot.clear();
Saveroot = root;
Saveroot = root + (FilesVec[i].substr(FilesVec[i].find_last_of("\\") + 1));
winy = (int)(2.0 * input.rows - 1) / 3;
winx = (int)input.cols - 1 < winy ? input.cols - 1 : winy;
if (winx > 100)
winx = winy = 40;
Mat output(input.rows, input.cols, CV_8U);
NiblackSauvolaWolfJolion(input, output, winx, winy, optK, 128);
outputImg.push_back(output);
cerr << "Writing binarized image to file '" << Saveroot << "'.\n";
imwrite(Saveroot, output);
}
cout << "end" << endl;
}
void NiblackSauvolaWolfJolion(Mat im, Mat output, int winx, int winy, double k, double dR)//k=0.5,dR=128;
{
double m, s, max_s;
double th = 0;
double min_I, max_I;
int wxh = winx / 2;
int wyh = winy / 2;
int x_firstth = wxh;
int x_lastth = im.cols - wxh - 1;
int y_lastth = im.rows - wyh - 1;
int y_firstth = wyh;
// Create local statistics and store them in a double matrices
Mat map_m = Mat::zeros(im.rows, im.cols, CV_32F);
Mat map_s = Mat::zeros(im.rows, im.cols, CV_32F);
max_s = calcLocalStats(im, map_m, map_s, winx, winy);
minMaxLoc(im, &min_I, &max_I);
Mat thsurf(im.rows, im.cols, CV_32F);
// Create the threshold surface, including border processing
for (int j = y_firstth; j <= y_lastth; j++)
{
float *th_surf_data = thsurf.ptr
float *map_m_data = map_m.ptr
float *map_s_data = map_s.ptr
// NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW:
for (int i = 0; i <= im.cols - winx; i++)
{
m = *map_m_data++;
s = *map_s_data++;
// Calculate the threshold
th = m * (1 + k * (s / dR - 1));
*th_surf_data++ = th;
if (i == 0)
{
// LEFT BORDER
float *th_surf_ptr = thsurf.ptr
for (int i = 0; i <= x_firstth; ++i)
*th_surf_ptr++ = th;
// LEFT-UPPER CORNER
if (j == y_firstth)
{
for (int u = 0; u < y_firstth; ++u)
{
float *th_surf_ptr = thsurf.ptr
for (int i = 0; i <= x_firstth; ++i)
*th_surf_ptr++ = th;
}
}
// LEFT-LOWER CORNER
if (j == y_lastth)
{
for (int u = y_lastth + 1; u < im.rows; ++u)
{
float *th_surf_ptr = thsurf.ptr
for (int i = 0; i <= x_firstth; ++i)
*th_surf_ptr++ = th;
}
}
}
// UPPER BORDER
if (j == y_firstth)
{
for (int u = 0; u < y_firstth; ++u)
thsurf.fset(i + wxh, u, th);
}
// LOWER BORDER
if (j == y_lastth)
{
for (int u = y_lastth + 1; u < im.rows; ++u)
thsurf.fset(i + wxh, u, th);
}
}
// RIGHT BORDER
float *th_surf_ptr = thsurf.ptr
for (int i = x_lastth; i < im.cols; ++i)
*th_surf_ptr++ = th;
// RIGHT-UPPER CORNER
if (j == y_firstth)
{
for (int u = 0; u < y_firstth; ++u)
{
float *th_surf_ptr = thsurf.ptr
for (int i = x_lastth; i < im.cols; ++i)
*th_surf_ptr++ = th;
}
}
// RIGHT-LOWER CORNER
if (j == y_lastth)
{
for (int u = y_lastth + 1; u < im.rows; ++u)
{
float *th_surf_ptr = thsurf.ptr
for (int i = x_lastth; i < im.cols; ++i)
*th_surf_ptr++ = th;
}
}
}
for (int y = 0; y < im.rows; ++y)
{
unsigned char *im_data = im.ptr
float *th_surf_data = thsurf.ptr
unsigned char *output_data = output.ptr
for (int x = 0; x < im.cols; ++x)
{
*output_data = *im_data >= (*th_surf_data)*1.4 ? 255 : 0;
im_data++;
th_surf_data++;
output_data++;
}
}
}
double calcLocalStats(Mat &im, Mat &map_m, Mat &map_s, int winx, int winy)
{
Mat im_sum, im_sum_sq;
integral(im, im_sum, im_sum_sq, CV_64F);
double m, s, max_s, sum, sum_sq;
int wxh = winx / 2;
int wyh = winy / 2;
int x_firstth = wxh;
int y_firstth = wyh;
int y_lastth = im.rows - wyh - 1;
double winarea = winx * winy;
max_s = 0;
for (int j = y_firstth; j <= y_lastth; j++)
{
sum = sum_sq = 0;
// for sum array iterator pointer
double *sum_top_left = im_sum.ptr
double *sum_top_right = sum_top_left + winx;
double *sum_bottom_left = im_sum.ptr
double *sum_bottom_right = sum_bottom_left + winx;
// for sum_sq array iterator pointer
double *sum_eq_top_left = im_sum_sq.ptr
double *sum_eq_top_right = sum_eq_top_left + winx;
double *sum_eq_bottom_left = im_sum_sq.ptr
double *sum_eq_bottom_right = sum_eq_bottom_left + winx;
sum = (*sum_bottom_right + *sum_top_left) - (*sum_top_right + *sum_bottom_left);
sum_sq = (*sum_eq_bottom_right + *sum_eq_top_left) - (*sum_eq_top_right + *sum_eq_bottom_left);
m = sum / winarea;
s = sqrt((sum_sq - m * sum) / winarea);
if (s > max_s) max_s = s;
float *map_m_data = map_m.ptr
float *map_s_data = map_s.ptr
*map_m_data++ = m;
*map_s_data++ = s;
// Shift the window, add and remove new/old values to the histogram
for (int i = 1; i <= im.cols - winx; i++)
{
sum_top_left++, sum_top_right++, sum_bottom_left++, sum_bottom_right++;
sum_eq_top_left++, sum_eq_top_right++, sum_eq_bottom_left++, sum_eq_bottom_right++;
sum = (*sum_bottom_right + *sum_top_left) - (*sum_top_right + *sum_bottom_left);
sum_sq = (*sum_eq_bottom_right + *sum_eq_top_left) - (*sum_eq_top_right + *sum_eq_bottom_left);
m = sum / winarea;
s = sqrt((sum_sq - m * sum) / winarea);
if (s > max_s) max_s = s;
*map_m_data++ = m;
*map_s_data++ = s;
}
}
return max_s;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
