【问题标题】:Binarize Image in AndroidAndroid中的二值化图像
【发布时间】:2013-05-04 14:41:30
【问题描述】:

我正在开发使用 tesseract OCR 从图像中扫描文本的 android 应用程序,
我听说在对图像执行 OCR 之前对图像进行二值化会得到更好的结果,
所以我开始寻找执行操作的代码,

我发现很少,但它实际上在 java 中并且需要 awt 库......所以它们不能在 android 上工作。
那你能帮我找一个吗。
谢谢你

【问题讨论】:

标签: java android image image-processing


【解决方案1】:

作为分配项目的一部分,我必须执行类似的任务。我在我的工作区找到了这段代码,我想这就是你需要的:

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);

在这里,我使用 ColorMatrix 从彩色图像生成黑白图像。我还发现了这段用于将彩色图像转换为灰度图像的代码:

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); 

希望对您有所帮助。

【讨论】:

  • 出了什么问题?也许我可以帮你解决它。
  • 也许我没有做对,但我应该把你上面给出的两个代码一起使用还是只使用其中一个
  • 只有其中一个,第一个将图像 img 转换为黑白,请注意第一行假设您的资源中有图像 testimage。您需要替换第一行以加载图像。第二段代码将图像转换为灰度。同样,您需要加载自己的图像并从中获取宽度和高度(destWidth 和 destHeight)。有什么需要请告诉我。
  • @Diego 嗨,同样我也在尝试在 ocr 处理之前对图像进行二值化,我可以知道在哪里可以粘贴此代码吗?我尝试将其放入我的代码中,但它无法解析符号“画布”。我正在运行 Android Studio 1.5.1
【解决方案2】:

一个简单的解决方案

在下文中,我将根据正常的 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*

<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>

【讨论】:

  • 我会再试一次,thaannnnnnnnnxxxxx HABIB ALBY
  • 嗨,我也在寻找解决方案。如何将图像实施到您的代码中?我尝试创建一个新项目并粘贴您的代码,但是当我运行它时应用程序没有在设备上启动。或者你能看看我的问题:stackoverflow.com/questions/35568362/… 吗?
【解决方案3】:

您可以查看条码扫描仪在 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

【讨论】:

  • 使用这些类进行二值化,就像您在 Android 应用中看到它们一样。我建议你重用这个核心库中的代码,并且你有完整的源代码,包括使用它的源代码。
  • 我认为它在DecodeHandler.java 类中,但我无法获取代码,代码太复杂了!!
  • 您不需要使用其他代码。 PlanarYUVLuminanceSource 将图像数据读入适当的形式,然后HybridBinarzier 将其二值化。你从中得到一个图像,你可以用抽象的形式做你喜欢的事情。真的只有这些类。
【解决方案4】:

我有一个类似的涉及颜色的项目,虽然是在另一个平台上。

虽然它们可能是其他更好的算法,但我使用了一个函数 (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,以便在黑暗环境中较暗的像素变为白色。

【讨论】:

    【解决方案5】:

    将它从 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;
    
        }
    
    }
    

    【讨论】:

      【解决方案6】:

      你可以使用 Catalano 框架,它很简单,有 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();
      

      【讨论】:

        【解决方案7】:

        简单干净,第一 首先将图像转换为灰度(如果你不这样做,你会得到一个输入图像错误) 转换后使用自适应阈值方法完成任务 代码:

         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);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-13
          • 2018-08-18
          • 1970-01-01
          • 1970-01-01
          • 2013-05-10
          • 1970-01-01
          相关资源
          最近更新 更多