2013-05-04 108 views
5

我正在開發Android應用程序使用的Tesseract OCR掃描從圖像的文本,
聽說在其上進行OCR前二值化圖像將提供更好的結果,
所以我開始尋找代碼做的操作,二值化圖像中的Android

我發現很少,但其實際上在Java和需要awt圖書館...所以他們不能在android上工作。
所以你能幫我找到一個。
謝謝

+0

Firas habibi會有這樣的幫助嗎? http://imageshack.us/photo/my-images/7/binarize.png/ – 2013-05-13 15:03:28

+0

是的,其實我的很簡單,它的一個文字只有圖像導致我的項目是OCR文字 – 2013-05-13 19:15:59

+0

和代碼habibi :-) – 2013-05-13 19:19:07

回答

4

一個簡單的解決

在下文中,我簡單改變基於正常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> 
+0

我會嘗試它,再來,thaannnnnnnnxxxxx HABIB ALBY – 2013-05-14 14:03:54

+0

謝謝你完美的作品。 – 2013-05-30 12:36:46

+0

嗨,我也找到了解決辦法。我怎樣才能將圖像實現到你的代碼?我嘗試創建一個新項目並粘貼代碼,但應用程序不會在設備上啓動時運行它。或者你可以看看我的問題:http://stackoverflow.com/questions/35568362/binarize-image-before-ocr-scan? – 2016-02-23 05:23:03

6

我必須做一個類似的任務作爲一個項目的一部分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); 

希望這對你有所幫助。

+0

didn' t和我一起工作 – 2013-05-07 13:31:47

+0

問題是什麼?也許我可以幫你修復它。 – Diego 2013-05-07 15:35:44

+0

也許我沒有這樣做,但我應該使用上面給出的兩個代碼嗎?只有其中一個代碼 – 2013-05-07 15:38:22

2

您可以看看條碼掃描器在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

+0

好,你會告訴我如何在我的代碼中實現這個? – 2013-05-07 12:50:28

+0

使用這些類,就像你看到它們在Android應用中使用的那樣,來二值化。我建議你重用這個核心庫中的代碼,並且你有完整的源代碼,包括使用它的源代碼。 – 2013-05-07 13:13:16

+0

我認爲它在'DecodeHandler.java'類中,但是我不能讓代碼去做,代碼太複雜了! – 2013-05-07 14:46:08

2

不會是很難的端口這從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; 

    } 

} 
+0

我試過但不能幫你嗎? – 2013-05-13 19:18:01

2

我有涉及顏色的類似項目,但在另一個平臺上。

雖然它們可能是其他更好的算法,但我使用函數(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,以使較暗的像素變白。

0

您可以使用卡塔拉諾框架,這很簡單,有超過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(); 
1

簡單幹淨,第一 第一轉換圖像灰度(如果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);