画像から2014年の数字を生成する


11

では2014年の挑戦、マイケル・スターンは、解析するためにOCRを使用することを提案している番号2014の画像私は別の方向にこの挑戦を取るしたいと思います2014年に。選択した言語/標準ライブラリの組み込みOCRを使用して、ASCII文字列「2014」に解析される最小のイメージ(バイト単位)を設計します。

Sternの元の画像は7357バイトですが、少し手間をかけると980バイトに可逆圧縮できます。白黒バージョン(181バイト)も同じコードで機能することは間違いありません。

ルール:各回答では、画像、バイト単位のサイズ、および画像の処理に必要なコードを提供する必要があります。明らかな理由により、カスタムOCRは許可されません...!妥当な言語と画像形式が許可されます。

編集:コメントに応じて、既存のライブラリ、またはOCRが利用できない言語のhttp://www.free-ocr.com/を含むようにこれを拡大します。


9
OCRが組み込まれている言語または標準ライブラリの数は?または、ここで「標準ライブラリ」とは「この課題のために特別に作成されていないライブラリ」を意味しますか?
ピーターテイラー14年

3
Mathematica以外の開発プラットフォームにはOCRが組み込まれていますか?
マイケル・スターン14年

標準化して、「use free-ocr.com」または他の簡単にアクセスできるocrなどを言ってください。
ジャスティン14年

回答:


10

シェル(ImageMagick、Tesseract)、18バイト

file=golf_2014
echo -n UDQKMTMgNQruqCqo6riKiO6I | base64 -d > $file.pbm
convert -border 2x2 -bordercolor white -resize 300% -sharpen 0 -monochrome $file.pbm $file.png
tesseract $file.png $file digits
cat $file.txt
rm $file.pbm $file.png $file.txt

イメージは18バイトで、次のように再現できます。

echo -n UDQKMTMgNQruqCqo6riKiO6I | base64 -d > 2014.pbm

このように見えます(これはPNGコピーであり、オリジナルではありません):

2014

ImageMagickで処理すると、次のようになります。

2014大

ImageMagickバージョン6.6.9-7、Tesseractバージョン3.02を使用。PBMイメージはGimpで作成され、16進エディターで編集されました。


このバージョンにはが必要jp2aです。

file=golf_2014
echo -n UDQKMTMgNQruqCqo6riKiO6I | base64 -d > $file.pbm
convert -border 2x2 -bordercolor white -resize 300% -sharpen 0 -monochrome $file.pbm $file.png
tesseract $file.png $file digits
cat $file.txt
convert -background black -fill white -border 2x2 -bordercolor black -pointsize 100 label:$(cat $file.txt) $file.jpg
jp2a --chars=" $(cat $file.txt) " $file.jpg
rm $file.pbm $file.png $file.txt $file.jpg

次のようなものを出力します。

    2014444444102         01144444102              214441                 214441     
   1             1      24           1            04    4                0     4     
  1    410201     0    0    410004    1       2014      4              21      4     
 24   42     0    4    4    0     1    0    24          4             04       4     
  22222      1    1   0    42     0    4    2   4100    4            1   41    4     
            1    42   0    4      2     2   2412   0    4          24   420    4     
          04    42    0    1      2     2          0    4         0   40  0    4     
       204    42      0    1      2     2          0    4       24   42   0    4     
     21     12        0    4      0    42          0    4      2     411114     1112 
    04   412          24    0     1    0           0    4      0                   0 
  24     1111111110    1    42  21    4            0    4      200011111001    40002 
  4               4     04    44     42            0    4                 0    4     
 0                4      214       10              0    4                 0    4     
  22222222222222222         222222                  22222                  22222     

とても印象的です。ヘッダーに3バイト、画像のサイズに5バイト、ビットマップに10バイト。形式はここに記述されています:netpbm.sourceforge.net/doc/pbm.html-
チャールズ

5

Java + Tesseract、53バイト

Mathematicaを持っていないので、ルールを少し曲げて、Tesseractを使用してOCRを実行することにしました。「2014」をさまざまなフォント、サイズ、スタイルを使用して画像にレンダリングし、「2014」として認識される最小の画像を見つけるプログラムを作成しました。結果は利用可能なフォントに依存します。

これが私のコンピューターでの勝者です-53バイト、「URW Gothic L」フォントを使用: 2014

コード:

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Ocr {
    public static boolean blankLine(final BufferedImage img, final int x1, final int y1, final int x2, final int y2) {
        final int d = x2 - x1 + y2 - y1 + 1;
        final int dx = (x2 - x1 + 1) / d;
        final int dy = (y2 - y1 + 1) / d;
        for (int i = 0, x = x1, y = y1; i < d; ++i, x += dx, y += dy) {
            if (img.getRGB(x, y) != -1) {
                return false;
            }
        }
        return true;
    }

    public static BufferedImage trim(final BufferedImage img) {
        int x1 = 0;
        int y1 = 0;
        int x2 = img.getWidth() - 1;
        int y2 = img.getHeight() - 1;
        while (x1 < x2 && blankLine(img, x1, y1, x1, y2)) x1++;
        while (x1 < x2 && blankLine(img, x2, y1, x2, y2)) x2--;
        while (y1 < y2 && blankLine(img, x1, y1, x2, y1)) y1++;
        while (y1 < y2 && blankLine(img, x1, y2, x2, y2)) y2--;
        return img.getSubimage(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
    }

    public static int render(final Font font, final int w, final String name) throws IOException {
        BufferedImage img = new BufferedImage(w, w, BufferedImage.TYPE_BYTE_BINARY);
        Graphics2D g = img.createGraphics();
        float size = font.getSize2D();
        Font f = font;
        while (true) {
            final FontMetrics fm = g.getFontMetrics(f);
            if (fm.stringWidth("2014") <= w) {
                break;
            }
            size -= 0.5f;
            f = f.deriveFont(size);
        }
        g = img.createGraphics();
        g.setFont(f);
        g.fillRect(0, 0, w, w);
        g.setColor(Color.BLACK);
        g.drawString("2014", 0, w - 1);
        g.dispose();
        img = trim(img);
        final File file = new File(name);
        ImageIO.write(img, "gif", file);
        return (int) file.length();
    }

    public static boolean ocr() throws Exception {
        Runtime.getRuntime().exec("/usr/bin/tesseract 2014.gif out -psm 8").waitFor();
        String t = "";
        final BufferedReader br = new BufferedReader(new FileReader("out.txt"));
        while (true) {
            final String s = br.readLine();
            if (s == null) break;
            t += s;
        }
        br.close();
        return t.trim().equals("2014");
    }

    public static void main(final String... args) throws Exception {
        int min = 10000;
        for (String s : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()) {
            for (int t = 0; t < 4; ++t) {
                final Font font = new Font(s, t, 50);
                for (int w = 10; w < 25; ++w) {
                    final int size = render(font, w, "2014.gif");
                    if (size < min && ocr()) {
                        render(font, w, "2014win.gif");
                        min = size;
                        System.out.println(s + ", " + size);
                    }
                }
            }
        }
    }
}

これと同様のエントリを許可するようにルールを変更しました。印象的なファイルサイズ。
チャールズ14年

1

Mathematica 753 100

f[n_,format_]:=
Module[{filename},
Print["raster: ",n," by ", n];
filename="2014At"<>ToString[n]<>"."<>format;
Print["filename:  ",filename];
Print["format: ",format];
Print["raster image: ",rasterImg=Rasterize[Style[2014,"OCR A Std"],
RasterSize->n,ImageSize->1n,ImageResolution->6n]];
Export[filename,rasterImg];
Print["Actual imported image: ",img=Switch[format,"PDF"|"HDF",Import[filename][[1]],
_,Import[filename]]];
Print["Identified text: ",TextRecognize[ImageResize[img,Scaled[3]]]];
Print["filesize (bytes): ",FileByteCount[filename]]]

これまでの私の最高のケース:

f[24, "PBM"]

効率


1

Mathematica、78バイト

Mathematicaでこれを獲得する秘trickは、おそらく以下のようにImageResize []関数を使用することです。

最初に、テキスト「2014」を作成してGIFファイルに保存し、David Carraherのソリューションと公正に比較しました。テキストは次のようになり2014ます。これは決して最適化されていません。小さなフォントサイズのジュネーブです。他のフォントや小さなサイズも可能です。ストレートTextRecognize []は失敗しますが、TextRecognize [ImageResize []]]は問題ありません

filename = "~/Desktop/2014.gif";
Print["Actual imported image: ", img = Import[filename]]
Print["Identified text: ", 
 TextRecognize[ImageResize[img, Scaled[2]]]]
Print["filesize (bytes): ", FileByteCount[filename]]

結果

書体、フォントサイズ、スケーリングの程度などに悩まされると、おそらくさらに小さなファイルが機能します。


非常に印象的なファイルサイズ。
DavidC 14年

画像を白い枠から切り取って、数字間のスペースを小さくして短くすることができます。再描画して、よりコンパクトにすることもできます。
スウィッシュ

@swish実際、白い境界線をトリミングすると、78バイトになります。
マイケル・スターン14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.