文档图像SauvolA二值化算法C++实现

这个二值化算法主要针对文档图像,原理较复杂,感兴趣的同学可以自己搜一下论文看看。下面先给出代码

void SauvolA(vector &FilesVec,vector &outputImg,string root)
{
    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(j) + wxh;
        float *map_m_data = map_m.ptr(j) + wxh;
        float *map_s_data = map_s.ptr(j) + wxh;
        // 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(j);
                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(u);
                        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(u);
                        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(j) + x_lastth;
        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(u) + x_lastth;
                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(u) + x_lastth;
                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(y);
        float *th_surf_data = thsurf.ptr(y);
        unsigned char *output_data = output.ptr(y);
        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(j - wyh);
        double *sum_top_right = sum_top_left + winx;
        double *sum_bottom_left = im_sum.ptr(j - wyh + winy);
        double *sum_bottom_right = sum_bottom_left + winx;
        // for sum_sq array iterator pointer
        double *sum_eq_top_left = im_sum_sq.ptr(j - wyh);
        double *sum_eq_top_right = sum_eq_top_left + winx;
        double *sum_eq_bottom_left = im_sum_sq.ptr(j - wyh + winy);
        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(j) + x_firstth;
        float *map_s_data = map_s.ptr(j) + x_firstth;
        *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;
}

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部