My self implemented otsu returns a good quality of binarize image but if the image has "more black" pixels it returns a full black image and if the image has "more white" pixels it returns a full white image.
Im using drawable and if I use camera it returns the output with the same idea (full black or full white). How can I correctly binarize the image even if the image has more black or more white?
(the image that returns with full black or full white can be binarize by sauvola as I try to compare and check the output. I didn't put the sauvola output to avoid long post but I can post it if needed.)
Here are some of the output on Otsu:
Bad Output:
(the image below is from camera capture)
Otsu Binarization Code
Bitmap BWimg = Bitmap.createBitmap(gImg.getWidth(), gImg.getHeight(), gImg.getConfig());
int width = gImg.getWidth();
int height = gImg.getHeight();
int A, R, G, B, colorPixel;
// histo-thresh
double Wcv = 0;
int[] Bx = new int[256];
int[] By = new int[256];
int[] Fx = new int[256];
int[] Fy = new int[256];
double Bw = 0, Bm = 0, Bv = 0, Bp = 0;
double Fw = 0, Fm = 0, Fv = 0, Fp = 0;
int c = 0, ImgPix = 0;
// pixel check for histogram
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
colorPixel = gImg.getPixel(x, y);
A = Color.alpha(colorPixel);
R = Color.red(colorPixel);
G = Color.green(colorPixel);
B = Color.blue(colorPixel);
int gray = (int) (0.2989 * R + 0.5870 * G + 0.1140 * B);
if (gray > 128) { // white - foreground
Fx[gray] = gray;
Fy[gray] = Fy[gray] + 1;
Fw = Fw + 1;
Fp = Fp + 1;
}
else { // black - background
Bx[gray] = gray;
By[gray] = By[gray] + 1;
Bw = Bw + 1;
Bp = Bp + 1;
}
ImgPix = ImgPix + 1;
}
}
//BG hist
Bw = Bw / ImgPix; //BG weight
int i;
for (i = 0; i < Bx.length; i++) { //BG mean
Bm = Bm + (Bx[i] * By[i]);
Bm = Bm / Bp;
}
for (i = 0; i < Bx.length; i++) { //BG variance
Bv = Bv + (Math.pow((Bx[i] - Bm), 2) * By[i]); // (Bx[i]-Bm) * (Bx[i]-Bm)
}
Bv = Bv / Bp;
//FG hist
Fw = Fw / ImgPix; //BG weight
for (i = 0; i < Bx.length; i++) { //BG mean
Fm = Fm + (Fx[i] * Fy[i]);
}
Fm = Fm / Fp;
for (i = 0; i < Bx.length; i++) { //BG variance
Fv = Fv + (Math.pow((Fx[i] - Fm), 2) * Fy[i]); // (Fx[i]-Fm) * (Fx[i]-Fm)
}
Fv = Fv / Fp;
// within class variance
Wcv = (Bw * Bv) + (Fw * Fv);
//int gray2 = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
colorPixel = gImg.getPixel(x, y);
A = Color.alpha(colorPixel);
R = Color.red(colorPixel);
G = Color.green(colorPixel);
B = Color.blue(colorPixel);
//int gray2 = (int) ((0.2989 * R) + (0.5870 * G) + (0.1140 * B));
int gray2 = (R + G + B);
if (gray2 > Wcv) {
gray2 = 255;
}
else {
gray2 = 0;
}
BWimg.setPixel(x, y, Color.argb(A, gray2, gray2, gray2));
}
}
return BWimg;
I got my answer last tuesday and forgot to post it. And I got it running.
@Morrison Chang thanks for the little push and clarifications about my codes
Bitmap BWimg = Bitmap.createBitmap(gImg.getWidth(), gImg.getHeight(), gImg.getConfig());
int width = gImg.getWidth();
int height = gImg.getHeight();
int A, R, G, B, colorPixel;
double Wcv = 0, th = 0;
int[] tPXL = new int[256];
int[][] pxl = new int[width][height];
double Bw, Bm, Bv, Fw, Fm, Fv;
int np, ImgPix = 0, fth = 0;
// pixel check for histogram //
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
colorPixel = gImg.getPixel(x, y);
A = Color.alpha(colorPixel);
R = Color.red(colorPixel);
G = Color.green(colorPixel);
B = Color.blue(colorPixel);
int gray = (int) ( (0.2126 * R) + (0.7152 * G) + (0.0722 * B) ); // (int) ( (0.299 * R) + (0.587 * G) + (0.114 * B) );
pxl[x][y] = gray;
tPXL[gray] = tPXL[gray] + 1;
ImgPix = ImgPix + 1;
}
}
// ----- histo-variance ----- //
for (int t = 0; t < 256; t++){
Bw = 0; Bm = 0; Bv = 0;
Fw = 0; Fm = 0; Fv = 0;
np = 0;
if (t == 0){ // all white/foreground as t0 ----- //
Fw = 1;
for (int d = 0; d < 256; d++) { //mean
Fm = Fm + (d * tPXL[d]);
}
Fm = Fm / ImgPix;
for (int e = 0; e < 256; e++) { //variance
Fv = Fv + (Math.pow((e - Fm), 2) * tPXL[e]);
}
Fv = Fv / ImgPix;
}
else { // main thresholding
for (int d = 0; d < (t-1); d++){ // BG weight & mean + BG pixel
Bw = Bw + tPXL[d];
Bm = Bm + (d * tPXL[d]);
np = np + tPXL[d];
}
Bw = Bw / ImgPix;
Bm = Bm / np;
for (int e = 0; e < (t-1); e++) { //BG variance
Bv = Bv + (Math.pow((e - Bm), 2) * tPXL[e]);
}
Bv = Bv / np;
for (int j = t; j < 256; j++) { // FG weight & mean + BG pixel
Fw = Fw + tPXL[j];
Fm = Fm + (j * tPXL[j]);
np = ImgPix - np;
}
Fw = Fw / ImgPix;
Fm = Fm / np;
for (int k = t; k < 256; k++) { //FG variance
Fv = Fv + (Math.pow((k - Fm), 2) * tPXL[k]);
}
Fv = Fv / np;
}
// within class variance
Wcv = (Bw * Bv) + (Fw * Fv);
if (t == 0){
th = Wcv;
}
else if (Wcv < th){
th = Wcv;
fth = t;
}
}
// set binarize pixel
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int fnpx = pxl[x][y];
colorPixel = gImg.getPixel(x, y);
A = Color.alpha(colorPixel);
if (fnpx > fth) { //R > fth
fnpx = 255;
BWimg.setPixel(x, y, Color.argb(A, fnpx, fnpx, fnpx));
}
else {
fnpx = 0;
BWimg.setPixel(x, y, Color.argb(A, fnpx, fnpx, fnpx));
}
}
}
return BWimg;