Menghasilkan angka 2014 dari suatu gambar


11

Dalam tantangan 2014 , Michael Stern menyarankan menggunakan OCR untuk menguraikan gambar angka 2014hingga 2014. Saya ingin mengambil tantangan ini ke arah yang berbeda. Dengan menggunakan OCR bawaan dari perpustakaan bahasa / standar pilihan Anda, rancang gambar terkecil (dalam byte) yang diuraikan ke dalam string ASCII "2014".

Gambar asli Stern adalah 7357 byte, tetapi dengan sedikit usaha itu dapat dikompresi hingga 980 byte. Tidak diragukan lagi versi hitam-putih (181 byte) juga berfungsi dengan kode yang sama.

Aturan: Setiap jawaban harus memberikan gambar, ukurannya dalam byte, dan kode yang diperlukan untuk memprosesnya. Tidak diizinkan OCR khusus, untuk alasan yang jelas ...! Semua bahasa dan format gambar yang masuk akal diizinkan.

Sunting: Sebagai tanggapan terhadap komentar, saya akan memperluas ini untuk menyertakan pustaka yang sudah ada sebelumnya, atau bahkan http://www.free-ocr.com/ untuk bahasa-bahasa di mana OCR tidak tersedia.


9
Berapa banyak bahasa atau perpustakaan standar yang memiliki OCR bawaan? Atau apakah Anda bermaksud "perpustakaan standar" di sini berarti "perpustakaan apa pun yang belum dibuat khusus untuk tantangan ini"?
Peter Taylor

3
Apakah ada platform pengembangan selain Mathematica yang memiliki OCR?
Michael Stern

Anda harus membuat standar, mengatakan sesuatu seperti "gunakan free-ocr.com " atau ocr lain yang mudah diakses.
Justin

Jawaban:


10

Shell (ImageMagick, Tesseract), 18 byte

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

Gambar adalah 18 byte dan dapat direproduksi seperti ini:

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

Sepertinya ini (ini adalah salinan PNG, bukan yang asli):

2014

Setelah diproses dengan ImageMagick, tampilannya seperti ini:

2014 besar

Menggunakan ImageMagick versi 6.6.9-7, Tesseract versi 3.02. Gambar PBM dibuat di Gimp dan diedit dengan hex editor.


Versi ini membutuhkan 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

Ini menghasilkan sesuatu seperti ini:

    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     

Sangat, sangat mengesankan. 3 byte untuk header, 5 byte untuk dimensi gambar, 10 byte untuk bitmap. Formatnya dijelaskan di sini: netpbm.sourceforge.net/doc/pbm.html
Charles

5

Java + Tesseract, 53 byte

Karena saya tidak memiliki Mathematica, saya memutuskan untuk sedikit membengkokkan aturan dan menggunakan Tesseract untuk melakukan OCR. Saya menulis sebuah program yang menerjemahkan "2014" menjadi sebuah gambar, menggunakan berbagai font, ukuran, dan gaya, dan menemukan gambar terkecil yang diakui sebagai "2014". Hasil tergantung pada font yang tersedia.

Inilah pemenangnya di komputer saya - 53 byte, menggunakan font "URW Gothic L": 2014

Kode:

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

Saya mengubah aturan untuk mengizinkan entri ini dan yang sejenis. Ukuran file yang mengesankan.
Charles

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

Kasus terbaik saya sejauh ini:

f[24, "PBM"]

efisiensi


1

Mathematica, 78 byte

Trik untuk memenangkan ini di Mathematica mungkin akan menggunakan fungsi ImageResize [] seperti di bawah ini.

Pertama, saya membuat teks "2014" dan menyimpannya ke file GIF, untuk perbandingan yang adil dengan solusi David Carraher. Teksnya seperti 2014. Ini tidak dioptimalkan dengan cara apa pun; hanya Jenewa dalam ukuran font kecil; font lain dan ukuran yang lebih kecil dimungkinkan. Straight TextRecognize [] akan gagal, tetapi TextRecognize [ImageResize []]] tidak memiliki masalah

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

hasil

Meributkan dengan jenis huruf, ukuran font, tingkat penskalaan, dll., Mungkin akan menghasilkan file yang lebih kecil yang berfungsi.


Ukuran file sangat mengesankan.
DavidC

Anda dapat memotong gambar dari batas putih untuk membuatnya lebih kecil dan mempersingkat jarak antar digit, mungkin menggambar ulang agar lebih kompak.
desir

@ Berharap memang, memotong perbatasan putih membawanya ke 78 bye.
Michael Stern
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.