Ask Your Question
4

Sauvola Thresholding for Android

asked 2013-10-24 07:59:12 -0600

Kroan gravatar image

updated 2020-11-30 03:27:25 -0600

Hi everyone,

ist there a way to use Sauvola Thresholding for a pre grayscaled Bitmap in Android with the help of the OpenCV Android SDK? I mean does a class or method or anythin exist that helps me doing that?

And is so, where can I find an example code?

Thank you in advance.

Best regards.

Kroan

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
6

answered 2013-10-24 13:41:22 -0600

updated 2014-03-08 05:27:47 -0600

You can use this class for sauvola thresholding.

thresholder.h

#ifndef _THRESHOLDER
#define _THRESHOLDER
#include <cv.h>

using namespace cv;

enum class BhThresholdMethod{OTSU,NIBLACK,SAUVOLA,WOLFJOLION};


class BhThresholder
{
public :
    void doThreshold(InputArray src ,OutputArray dst,const BhThresholdMethod &method);
private:
};

#endif //_THRESHOLDER

thresholder.cpp

#include "stdafx.h"

#define uget(x,y)    at<unsigned char>(y,x)
#define uset(x,y,v)  at<unsigned char>(y,x)=v;
#define fget(x,y)    at<float>(y,x)
#define fset(x,y,v)  at<float>(y,x)=v;

// *************************************************************
// glide a window across the image and
// create two maps: mean and standard deviation.
// *************************************************************
//#define BINARIZEWOLF_VERSION  "2.3 (February 26th, 2013)"


double calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int win_x, int win_y) {

    double m,s,max_s, sum, sum_sq, foo;
    int wxh = win_x / 2;
    int wyh = win_y / 2;
    int x_firstth = wxh;
    int y_lastth = im.rows-wyh-1;
    int y_firstth= wyh;
    double winarea = win_x*win_y;

    max_s = 0;
    for (int j = y_firstth ; j<=y_lastth; j++) 
    {
        // Calculate the initial window at the beginning of the line
        sum = sum_sq = 0;
        for (int wy=0 ; wy<win_y; wy++)
            for (int wx=0 ; wx<win_x; wx++) {
                foo = im.uget(wx,j-wyh+wy);
                sum    += foo;
                sum_sq += foo*foo;
            }
        m  = sum / winarea;
        s  = sqrt ((sum_sq - (sum*sum)/winarea)/winarea);
        if (s > max_s)
            max_s = s;
        map_m.fset(x_firstth, j, m);
        map_s.fset(x_firstth, j, s);

        // Shift the window, add and remove new/old values to the histogram
        for (int i=1 ; i <= im.cols  -win_x; i++) {

            // Remove the left old column and add the right new column
            for (int wy=0; wy<win_y; ++wy) {
                foo = im.uget(i-1,j-wyh+wy);
                sum    -= foo;
                sum_sq -= foo*foo;
                foo = im.uget(i+win_x-1,j-wyh+wy);
                sum    += foo;
                sum_sq += foo*foo;
            }
            m  = sum / winarea;
            s  = sqrt ((sum_sq - (sum*sum)/winarea)/winarea);
            if (s > max_s)
                max_s = s;
            map_m.fset(i+wxh, j, m);
            map_s.fset(i+wxh, j, s);
        }
    }

    return max_s;
}




void NiblackSauvolaWolfJolion (InputArray _src, OutputArray _dst,const BhThresholdMethod &version,int winx, int winy, double k, double dR) {

    Mat src = _src.getMat();
    Mat dst = _dst.getMat();
    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 = src.cols-wxh-1;
    int y_lastth = src.rows-wyh-1;
    int y_firstth= wyh;
    int mx, my;

    // Create local statistics and store them in a double matrices
    Mat map_m = Mat::zeros (src.size(), CV_32FC1);
    Mat map_s = Mat::zeros (src.size(), CV_32FC1);
    max_s = calcLocalStats (src, map_m, map_s, winx, winy);

    minMaxLoc(src, &min_I, &max_I);

    Mat thsurf (src.size(), CV_32FC1);

    // Create the threshold surface, including border processing
    // ----------------------------------------------------

    for (int j = y_firstth ; j<=y_lastth; j++) {

        // NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW:
        for (int i=0 ; i <= src.cols-winx; i++) {

            m  = map_m.fget(i+wxh, j);
            s  = map_s.fget(i+wxh, j);

            // Calculate the threshold
            switch (version) {

            case BhThresholdMethod::NIBLACK:
                    th = m + k*s;
                    break;

            case BhThresholdMethod::SAUVOLA:
                    th = m * (1 + k*(s/dR-1));
                    break;

            case BhThresholdMethod::WOLFJOLION:
                    th = m + k * (s/max_s-1) * (m-min_I);
                    break;

                default:
                    cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n";
                    exit (1);
            }

            thsurf.fset(i ...
(more)
edit flag offensive delete link more

Comments

I don't understand. How can I use cpp inside my android Application with the help of opencv Android SDK?

Thank you for your answer.

Best regards

Kroan gravatar imageKroan ( 2013-10-25 01:48:35 -0600 )edit
4

@Mostafa Sataki cool answer! @Kroan There is no implementation of this threshold in OpenCV, so you can use this code in your android app through jni. Look at "Face detection sample" (http://opencv.org/platforms/android/opencv4android-samples.html). It shows an example of wrapping a C++ class to the Java.

Daniil Osokin gravatar imageDaniil Osokin ( 2013-10-25 03:02:06 -0600 )edit

Okay thank you both, so do I understand taht right? This code is no part of the OpenCV library? It's selfwritten by Mostafa Sataki? And if I want to use it inside my Android app I have to copy this files to my project, init OpenCV, call System.loadLibrary() and than I can use it? What do I have to write inside loadLibrary("") function? In the example they write "detection_based_tracker" but I don't think that's what I have to do^^

THX

Kroan gravatar imageKroan ( 2013-10-25 04:51:12 -0600 )edit

when I build it I got the error message like "type.h: No such file or directory". How can i solve this kind of problem?

sofit gravatar imagesofit ( 2014-03-07 10:25:12 -0600 )edit

@sofit It's extra.remove it.

Mostafa Sataki gravatar imageMostafa Sataki ( 2014-03-08 05:29:14 -0600 )edit

shame, i can upvote only once ;)

berak gravatar imageberak ( 2014-03-08 07:06:15 -0600 )edit

Awesome answer !

VishalNair gravatar imageVishalNair ( 2017-03-27 11:33:00 -0600 )edit

I'm sorry but to say that there seems to be lots of bugs here: the variable "mx", "my" are not used, and why to use the header "stdafx.h" ? In the function "doThreshold", the method NIBLACK was not included in, and so on. Besides, there was a similar method here

thinder gravatar imagethinder ( 2017-07-27 22:46:53 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2013-10-24 07:59:12 -0600

Seen: 6,633 times

Last updated: Mar 08 '14