I am developing android app that uses tesseract OCR to scan a text from image,
I heard that binarizing image before performing OCR on it will give better result,
So
A Simple Solution
In the following, I simply alter each pixel in an image based on the normal 3-dimension-space distance formula. I decide whether a pixel should be black or white based on how far it is from each of these colors. For example, (1,2,3) is closer to (0,0,0) than it is to (255,255,255) and therefore it is decided to be black. I'm sure there are more clever algorithms out there. This is just a simple one
MainActivity.java
package com.example.binarizeimage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;
import com.example.binarizeimage.R.drawable;
/**
* @author Sherif elKhatib - shush
*
*/
public class MainActivity extends Activity {
/**
* Boolean that tells me how to treat a transparent pixel (Should it be black?)
*/
private static final boolean TRASNPARENT_IS_BLACK = false;
/**
* This is a point that will break the space into Black or white
* In real words, if the distance between WHITE and BLACK is D;
* then we should be this percent far from WHITE to be in the black region.
* Example: If this value is 0.5, the space is equally split.
*/
private static final double SPACE_BREAKING_POINT = 13.0/30.0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//this is the original image
Bitmap theOriginalImage = BitmapFactory.decodeResource(this.getResources(), drawable.ic_launcher);
//this is the image that is binarized
Bitmap binarizedImage = convertToMutable(theOriginalImage);
// I will look at each pixel and use the function shouldBeBlack to decide
// whether to make it black or otherwise white
for(int i=0;iSPACE_BREAKING_POINT);
}
/**
* @author Derzu
*
* @see http://stackoverflow.com/a/9194259/833622
*
* Converts a immutable bitmap to a mutable bitmap. This operation doesn't allocates
* more memory that there is already allocated.
*
* @param imgIn - Source image. It will be released, and should not be used more
* @return a copy of imgIn, but muttable.
*/
public static Bitmap convertToMutable(Bitmap imgIn) {
try {
//this is the file going to use temporally to save the bytes.
// This file will not be a image, it will store the raw image data.
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "temp.tmp");
//Open an RandomAccessFile
//Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
//into AndroidManifest.xml file
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
// get the width and height of the source bitmap.
int width = imgIn.getWidth();
int height = imgIn.getHeight();
Config type = imgIn.getConfig();
//Copy the byte to the file
//Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888;
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes()*height);
imgIn.copyPixelsToBuffer(map);
//recycle the source bitmap, this will be no longer used.
imgIn.recycle();
System.gc();// try to force the bytes from the imgIn to be released
//Create a new bitmap to load the bitmap again. Probably the memory will be available.
imgIn = Bitmap.createBitmap(width, height, type);
map.position(0);
//load it back from temporary
imgIn.copyPixelsFromBuffer(map);
//close the temporary file and channel , then delete that also
channel.close();
randomAccessFile.close();
// delete the temp file
file.delete();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return imgIn;
}
}
*activity_main.xml*