我正在開發Android應用程序使用的Tesseract OCR掃描從圖像的文本,
聽說在其上進行OCR前二值化圖像將提供更好的結果,
所以我開始尋找代碼做的操作,二值化圖像中的Android
我發現很少,但其實際上在Java和需要awt圖書館...所以他們不能在android上工作。
所以你能幫我找到一個。
謝謝
我正在開發Android應用程序使用的Tesseract OCR掃描從圖像的文本,
聽說在其上進行OCR前二值化圖像將提供更好的結果,
所以我開始尋找代碼做的操作,二值化圖像中的Android
我發現很少,但其實際上在Java和需要awt圖書館...所以他們不能在android上工作。
所以你能幫我找到一個。
謝謝
一個簡單的解決
在下文中,我簡單改變基於正常3-維空間距離式圖像中的每個像素。我決定一個像素應該是黑色還是白色,取決於它與每種顏色的距離。例如,(1,2,3)比(255,055,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 *
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
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" />
</RelativeLayout>
我會嘗試它,再來,thaannnnnnnnxxxxx HABIB ALBY – 2013-05-14 14:03:54
謝謝你完美的作品。 – 2013-05-30 12:36:46
嗨,我也找到了解決辦法。我怎樣才能將圖像實現到你的代碼?我嘗試創建一個新項目並粘貼代碼,但應用程序不會在設備上啓動時運行它。或者你可以看看我的問題:http://stackoverflow.com/questions/35568362/binarize-image-before-ocr-scan? – 2016-02-23 05:23:03
我必須做一個類似的任務作爲一個項目的一部分asignment。我在工作區中找到這段代碼,我覺得這是你所需要的:
Bitmap img = BitmapFactory.decodeResource(this.getResources(), drawable.testimage);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
float a = 77f;
float b = 151f;
float c = 28f;
float t = 120 * -256f;
cm.set(new float[] { a, b, c, 0, t, a, b, c, 0, t, a, b, c, 0, t, 0, 0, 0, 1, 0 });
paint.setColorFilter(new ColorMatrixColorFilter(cm));
canvas.drawBitmap(img, 0, 0, paint);
在這裏,我用嘉洛斯生成從顏色一個黑白圖像。此外,我發現這段代碼,我用於將彩色圖像轉換爲灰度圖像:
Bitmap result = Bitmap.createBitmap(destWidth, destHeight,Bitmap.Config.RGB_565);
RectF destRect = new RectF(0, 0, destWidth, destHeight);
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0);
ColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
paint.setColorFilter(filter);
canvas.drawBitmap(bitmap, sourceRect, destRect, paint);
希望這對你有所幫助。
didn' t和我一起工作 – 2013-05-07 13:31:47
問題是什麼?也許我可以幫你修復它。 – Diego 2013-05-07 15:35:44
也許我沒有這樣做,但我應該使用上面給出的兩個代碼嗎?只有其中一個代碼 – 2013-05-07 15:38:22
您可以看看條碼掃描器在Android上使用的簡單方法,將圖像轉換爲亮度,然後轉換爲黑白。它可能適用於OCR。
https://code.google.com/p/zxing/source/browse/trunk/core/src/com/google/zxing/common/HybridBinarizer.java https://code.google.com/p/zxing/source/browse/trunk/core/src/com/google/zxing/PlanarYUVLuminanceSource.java
好,你會告訴我如何在我的代碼中實現這個? – 2013-05-07 12:50:28
使用這些類,就像你看到它們在Android應用中使用的那樣,來二值化。我建議你重用這個核心庫中的代碼,並且你有完整的源代碼,包括使用它的源代碼。 – 2013-05-07 13:13:16
我認爲它在'DecodeHandler.java'類中,但是我不能讓代碼去做,代碼太複雜了! – 2013-05-07 14:46:08
不會是很難的端口這從Java到Android:
/**
* Image binarization - Otsu algorithm
*
* Author: Bostjan Cigan (http://zerocool.is-a-geek.net)
*
*/
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class OtsuBinarize {
private static BufferedImage original, grayscale, binarized;
public static void main(String[] args) throws IOException {
File original_f = new File(args[0]+".jpg");
String output_f = args[0]+"_bin";
original = ImageIO.read(original_f);
grayscale = toGray(original);
binarized = binarize(grayscale);
writeImage(output_f);
}
private static void writeImage(String output) throws IOException {
File file = new File(output+".jpg");
ImageIO.write(binarized, "jpg", file);
}
// Return histogram of grayscale image
public static int[] imageHistogram(BufferedImage input) {
int[] histogram = new int[256];
for(int i=0; i<histogram.length; i++) histogram[i] = 0;
for(int i=0; i<input.getWidth(); i++) {
for(int j=0; j<input.getHeight(); j++) {
int red = new Color(input.getRGB (i, j)).getRed();
histogram[red]++;
}
}
return histogram;
}
// The luminance method
private static BufferedImage toGray(BufferedImage original) {
int alpha, red, green, blue;
int newPixel;
BufferedImage lum = new BufferedImage(original.getWidth(), original.getHeight(), original.getType());
for(int i=0; i<original.getWidth(); i++) {
for(int j=0; j<original.getHeight(); j++) {
// Get pixels by R, G, B
alpha = new Color(original.getRGB(i, j)).getAlpha();
red = new Color(original.getRGB(i, j)).getRed();
green = new Color(original.getRGB(i, j)).getGreen();
blue = new Color(original.getRGB(i, j)).getBlue();
red = (int) (0.21 * red + 0.71 * green + 0.07 * blue);
// Return back to original format
newPixel = colorToRGB(alpha, red, red, red);
// Write pixels into image
lum.setRGB(i, j, newPixel);
}
}
return lum;
}
// Get binary treshold using Otsu's method
private static int otsuTreshold(BufferedImage original) {
int[] histogram = imageHistogram(original);
int total = original.getHeight() * original.getWidth();
float sum = 0;
for(int i=0; i<256; i++) sum += i * histogram[i];
float sumB = 0;
int wB = 0;
int wF = 0;
float varMax = 0;
int threshold = 0;
for(int i=0 ; i<256 ; i++) {
wB += histogram[i];
if(wB == 0) continue;
wF = total - wB;
if(wF == 0) break;
sumB += (float) (i * histogram[i]);
float mB = sumB/wB;
float mF = (sum - sumB)/wF;
float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);
if(varBetween > varMax) {
varMax = varBetween;
threshold = i;
}
}
return threshold;
}
private static BufferedImage binarize(BufferedImage original) {
int red;
int newPixel;
int threshold = otsuTreshold(original);
BufferedImage binarized = new BufferedImage(original.getWidth(), original.getHeight(), original.getType());
for(int i=0; i<original.getWidth(); i++) {
for(int j=0; j<original.getHeight(); j++) {
// Get pixels
red = new Color(original.getRGB(i, j)).getRed();
int alpha = new Color(original.getRGB(i, j)).getAlpha();
if(red > threshold) {
newPixel = 255;
}
else {
newPixel = 0;
}
newPixel = colorToRGB(alpha, newPixel, newPixel, newPixel);
binarized.setRGB(i, j, newPixel);
}
}
return binarized;
}
// Convert R, G, B, Alpha to standard 8 bit
private static int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red; newPixel = newPixel << 8;
newPixel += green; newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
}
我試過但不能幫你嗎? – 2013-05-13 19:18:01
我有涉及顏色的類似項目,但在另一個平臺上。
雖然它們可能是其他更好的算法,但我使用函數(GetColorDistance)通過勾股定理計算了兩個顏色之間的距離,在3D RGB空間中。 GetNewColor計算一種顏色是接近白色還是黑色,然後相應地返回黑色或白色。最後,GetBitmapBinary函數處理位圖上的像素並將它們轉換成黑色&白色。
private Bitmap GetBinaryBitmap(Bitmap bitmap_src)
{
Bitmap bitmap_new=bitmap_src.copy(bitmap_src.getConfig(), true);
for(int x=0; x<bitmap_new.getWidth(); x++)
{
for(int y=0; y<bitmap_new.getHeight(); y++)
{
int color=bitmap_new.getPixel(x, y);
color=GetNewColor(color);
bitmap_new.setPixel(x, y, color);
}
}
return bitmap_new;
}
private double GetColorDistance(int c1, int c2)
{
int db=Color.blue(c1)-Color.blue(c2);
int dg=Color.green(c1)-Color.green(c2);
int dr=Color.red(c1)-Color.red(c2);
double d=Math.sqrt( Math.pow(db, 2) + Math.pow(dg, 2) +Math.pow(dr, 2) );
return d;
}
private int GetNewColor(int c)
{
double dwhite=GetColorDistance(c,Color.WHITE);
double dblack=GetColorDistance(c,Color.BLACK);
if(dwhite<=dblack)
{
return Color.WHITE;
}
else
{
return Color.BLACK;
}
}
您可以修改GetNewColor函數以在不同光密度下獲得更好的結果。例如,在黑暗的環境中,可以將dblack乘以1.5,以使較暗的像素變白。
您可以使用卡塔拉諾框架,這很簡單,有超過60個濾波器
http://code.google.com/p/catalano-framework/
FastBitmap fb = new FastBitmap(bitmap);
Grayscale g = new Grayscale(fb);
g.applyInPlace(fb);
Threshold t = new Threshold(100);
t.applyInPlace(fb);
bitmap = fb.toBitmap();
簡單幹淨,第一 第一轉換圖像灰度(如果u不要你會得到一個輸入圖像錯誤) 轉換後使用自適應閾值方法來完成任務 代碼:
Mat tmp = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1);
// Convert
Utils.bitmapToMat(bitmap, tmp);
Mat gray = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC1);
// Conver the color
Imgproc.cvtColor(tmp, gray, Imgproc.COLOR_RGB2GRAY);
// Convert back to bitmap
Mat destination = new Mat(gray.rows(),gray.cols(),gray.type());
Imgproc.adaptiveThreshold(gray, destination, 255,
Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 15, 4);
Utils.matToBitmap(destination, bitmap);
imv_binary.setImageBitmap(bitmap);
Firas habibi會有這樣的幫助嗎? http://imageshack.us/photo/my-images/7/binarize.png/ – 2013-05-13 15:03:28
是的,其實我的很簡單,它的一個文字只有圖像導致我的項目是OCR文字 – 2013-05-13 19:15:59
和代碼habibi :-) – 2013-05-13 19:19:07