在Android中对图像进行二值化
我正在开发一个使用tesseract OCR扫描图像中文本的android应用,
听说在对其执行OCR之前对图像进行二值化处理会产生更好的结果,
所以我开始寻找可以执行此操作的代码,
我发现很少,但实际上是在Java中,并且需要awt库…因此它们在android上不起作用。
所以你能帮我找到一个吗?
谢谢
回答:
在下文中,我仅根据正常的3维空间距离公式更改图像中的每个像素。我根据像素与每种颜色的距离来决定像素应为黑色还是白色。例如,(1,2,3)比(255,255,255)更接近(0,0,0),因此将其确定为黑色。我敢肯定还有更多聪明的算法。这只是一个简单的
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;i<binarizedImage.getWidth();i++) {
for(int c=0;c<binarizedImage.getHeight();c++) {
int pixel = binarizedImage.getPixel(i, c);
if(shouldBeBlack(pixel))
binarizedImage.setPixel(i, c, Color.BLACK);
else
binarizedImage.setPixel(i, c, Color.WHITE);
}
}
ImageView iv = (ImageView) findViewById(R.id.imageView1);
ImageView ivb = (ImageView) findViewById(R.id.ImageView01);
//show the original image
iv.setImageBitmap(BitmapFactory.decodeResource(this.getResources(), drawable.ic_launcher));
//show the binarized image
ivb.setImageBitmap(binarizedImage);
}
/**
* @param pixel the pixel that we need to decide on
* @return boolean indicating whether this pixel should be black
*/
private static boolean shouldBeBlack(int pixel) {
int alpha = Color.alpha(pixel);
int redValue = Color.red(pixel);
int blueValue = Color.blue(pixel);
int greenValue = Color.green(pixel);
if(alpha == 0x00) //if this pixel is transparent let me use TRASNPARENT_IS_BLACK
return TRASNPARENT_IS_BLACK;
// distance from the white extreme
double distanceFromWhite = Math.sqrt(Math.pow(0xff - redValue, 2) + Math.pow(0xff - blueValue, 2) + Math.pow(0xff - greenValue, 2));
// distance from the black extreme //this should not be computed and might be as well a function of distanceFromWhite and the whole distance
double distanceFromBlack = Math.sqrt(Math.pow(0x00 - redValue, 2) + Math.pow(0x00 - blueValue, 2) + Math.pow(0x00 - greenValue, 2));
// distance between the extremes //this is a constant that should not be computed :p
double distance = distanceFromBlack + distanceFromWhite;
// distance between the extremes
return ((distanceFromWhite/distance)>SPACE_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 *
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView2"
android:layout_centerHorizontal="true"
android:text="Original Image" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/TextView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/imageView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="28dp"
android:text="YES/NO Image" />
<ImageView
android:id="@+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/TextView02"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_launcher" />
以上是 在Android中对图像进行二值化 的全部内容, 来源链接: utcz.com/qa/419315.html