Android: Adaptive Thresholding
Asked Answered
G

2

6

I'm trying to implement adaptive thresholding algorithm by Derek Bradley using Android. But it is returning black pixels all the time. Here is my code snippet. Please suggest me about what should I do. Thanks in advance.

public static Bitmap GrayscaleToBin(Bitmap bm2)
{

    Bitmap bm;
    bm=bm2.copy(Config.ARGB_8888, true);
    final   int width = bm.getWidth();
    final  int height = bm.getHeight();
    int[]  pixels;
    pixels = new int[width*height];
    bm.getPixels(pixels,0,width,0,0,width,height);     
    //Bradley AdaptiveThrsholdging       
    int []intImg= new int[width*height];
    int sum=0;
    for(int i=0;i<width;++i){
        sum=0;
        for(int j=0;j<height;++j)
        {
            sum=sum+pixels[i+j*width];
            if(i==0){intImg[i+j*width]=sum;}
            else
            {
                intImg[i+j*width]= intImg[i-1+j*width]+sum;
            }
        }
    }
    int x1,x2,y1,y2=0,count=0;
    int s=width >> 3;   
    int t=15;
    for(int i=0;i<width;++i)
    {
        for(int j=0;j<height;++j)
        {
            x1=i-s/2;
            x2=i+s/2;
            y1=j-s/2;
            y2=j+s/2;
            if (x1 <0) x1 = 0;  
            if (x2>= width) x2 = width-1;  
            if (y1 <0) y1 = 0;  
            if (y2>= height) y2 = height-1;  
            count = (x2-x1) * (y2-y1);  
            sum = intImg [y2 * width + x2] -  
            intImg [y1 * width + x2] -  
            intImg [y2 * width + x1] +  
            intImg [y1 * width + x1]; 
            if((pixels[i+j*width]*count)<=(sum*(100-t)/100))
            {
                pixels[i+j*width]=0;
            }
            else
            {
                pixels[i+j*width]=255; 
            }
        }
    }
    /*---------------------------------------------------------------------------*/
    bm.setPixels(pixels,0,width,0,0,width,height);
    // Log.d("cdsfss","afterloop");
    return bm;
}
Galengalena answered 7/2, 2013 at 18:42 Comment(2)
That paper deals with binarization, so my first issue with your code is the function's name "RGBtoGrayScale". That immediately raises another issue, the paper doesn't care about RGB images but your code doesn't seem to make sure the input is a grayscale one. Lastly, you are using a formula for finding the s x s average that is different from that on the paper (or any text that deals with integral images for the matter). Have you checked these issues ?Eboni
sorry, Function name was not written properly. I've changed it. My input bitmap image is grayscale one and is obtained after grayscale from RGB conversion using R = G = B = (int)(0.299 * R + 0.587 * G + 0.114 * B); Again it is not working with s=width/8;Galengalena
G
10

After a Long struggle I have solved the issue with the following code.

public static Bitmap GrayscaleToBin(Bitmap bm2)
 {
 Bitmap bm;
 bm=bm2.copy(Config.RGB_565, true);
 final   int width = bm.getWidth();
 final  int height = bm.getHeight();

 int pixel1,pixel2,pixel3,pixel4,A,R;
 int[]  pixels;
 pixels = new int[width*height];
 bm.getPixels(pixels,0,width,0,0,width,height);
 int size=width*height;
      int s=width/8;
      int s2=s>>1;
      double t=0.15;
      double it=1.0-t;
      int []integral= new int[size];
      int []threshold=new int[size];
      int i,j,diff,x1,y1,x2,y2,ind1,ind2,ind3;
      int sum=0;
      int ind=0;
      while(ind<size)
      {
       sum+=pixels[ind] & 0xFF;
       integral[ind]=sum;
       ind+=width;
      }
   x1=0;
   for(i=1;i<width;++i)       
   {
       sum=0;
       ind=i;
       ind3=ind-s2;
       if(i>s)
       {
           x1=i-s;
       }
       diff=i-x1;
       for(j=0;j<height;++j)
       {
           sum+=pixels[ind] & 0xFF;
           integral[ind]=integral[(int)(ind-1)]+sum;
           ind+=width;
           if(i<s2)continue;
           if(j<s2)continue;
           y1=(j<s ? 0 : j-s);
           ind1=y1*width;
           ind2=j*width;

        if (((pixels[ind3]&0xFF)*(diff * (j - y1))) < ((integral[(int)(ind2 + i)] - integral[(int)(ind1 + i)] - integral[(int)(ind2 + x1)] + integral[(int)(ind1 + x1)])*it)) {
            threshold[ind3] = 0x00;
        } else {
            threshold[ind3] = 0xFFFFFF;
        }
        ind3 += width;
    }
}

y1 = 0;
for( j = 0; j < height; ++j )
{
    i = 0;
    y2 =height- 1;
    if( j <height- s2 ) 
    {
        i = width - s2;
        y2 = j + s2;
    }

    ind = j * width + i;
    if( j > s2 ) y1 = j - s2;
    ind1 = y1 * width;
    ind2 = y2 * width;
    diff = y2 - y1;
    for( ; i < width; ++i, ++ind )
    {

        x1 = ( i < s2 ? 0 : i - s2);
        x2 = i + s2;

        // check the border
        if (x2 >= width) x2 = width - 1;

        if (((pixels[ind]&0xFF)*((x2 - x1) * diff)) < ((integral[(int)(ind2 + x2)] - integral[(int)(ind1 + x2)] - integral[(int)(ind2 + x1)] + integral[(int)(ind1 + x1)])*it)) {
            threshold[ind] = 0x00;
        } else {
            threshold[ind] = 0xFFFFFF;
        }
    }
}
   /*-------------------------------
    * --------------------------------------------*/
   bm.setPixels(threshold,0,width,0,0,width,height);

   return bm;
}
Galengalena answered 8/2, 2013 at 9:57 Comment(2)
So what turned out to be wrong? I have almost identical code to what was posted in the question, and getting similar output (completely black or white), but this code is unreadable to me, so I don't know what is different now.Birthwort
The difference is that, the first example uses ARGB_8888 and this one RGB_565Saleme
P
4

You can use Catalano Framework. There's an example using Bradley for Android in samples folder.

FastBitmap fb = new FastBitmap(bitmap);

fb.toGrayscale();

BradleyLocalThreshold bradley = new BradleyLocalThreshold();
bradley.applyInPlace(fb);

bitmap = fb.toBitmap();
Polytypic answered 23/9, 2013 at 2:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.