tesseract OCRを使用して画像からテキストをスキャンするAndroidアプリを開発しています.OCRを
実行する前に画像を2値化するとより良い結果が得られると聞いた
ので、操作を行うコードを探し始めました.
いくつか見つかりましたが、実際にはJavaであり、awtライブラリが必要です...したがって、Androidでは動作しません。
それで、私がそれを見つけるのを手伝ってくれませんか。
ありがとうございました
tesseract OCRを使用して画像からテキストをスキャンするAndroidアプリを開発しています.OCRを
実行する前に画像を2値化するとより良い結果が得られると聞いた
ので、操作を行うコードを探し始めました.
いくつか見つかりましたが、実際にはJavaであり、awtライブラリが必要です...したがって、Androidでは動作しません。
それで、私がそれを見つけるのを手伝ってくれませんか。
ありがとうございました
Barcode Scanner が 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
別のプラットフォームではありますが、色を含む同様のプロジェクトがありました。
他のより優れたアルゴリズムかもしれませんが、関数 (GetColorDistance) を使用して、ピタゴラスの定理を使用して、3D RGB 空間で 2 つの色の間の距離を計算しました。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 を掛けると、暗い環境では暗いピクセルが白くなります。
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();
シンプルなクリーンで、最初に画像をグレースケールに変換します (入力画像エラーが発生しない場合)。変換後、適応しきい値法を使用してタスク コードを完成させます。
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);
これを 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;
}
}