이미지에서 숫자 2014를 생성하십시오


11

에서 2014 도전 , 마이클 스턴은 구문 분석 OCR 사용하여 제안 숫자 2014 이미지내가 다른 방향으로이 문제를 가지고 싶습니다 2014을. 선택한 언어 / 표준 라이브러리의 내장 OCR을 사용하여 ASCII 문자열 "2014"로 구문 분석되는 가장 작은 이미지 (바이트)를 디자인하십시오.

Stern의 원본 이미지는 7357 바이트이지만 약간의 노력으로 980 바이트로 손실없이 압축 할 수 있습니다. 의심 할 여지없이 흑백 버전 (181 바이트)은 동일한 코드에서 잘 작동합니다.

규칙 : 각 답변은 이미지, 크기 (바이트) 및 이미지를 처리하는 데 필요한 코드를 제공해야합니다. 명백한 이유로 맞춤형 OCR이 허용되지 않습니다 ...! 합리적인 언어 및 이미지 형식이 허용됩니다.

편집 : 의견에 따라 기존 라이브러리를 포함하도록 확장하거나 OCR을 사용할 수없는 언어의 경우 http://www.free-ocr.com/ 을 확장 합니다.


9
내장 OCR에는 몇 개의 언어 또는 표준 라이브러리가 있습니까? 아니면 "표준 라이브러리"를 "이 도전을 위해 특별히 제작되지 않은 라이브러리"를 의미합니까?
피터 테일러

3
Mathematica 이외의 개발 플랫폼에 OCR이 내장되어 있습니까?
Michael Stern

" free-ocr.com 사용 "또는 쉽게 액세스 할 수있는 다른 ocr 과 같은 것을 표준화해야합니다 .
Justin

답변:


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
Charles

5

자바 + Tesseract, 53 바이트

Mathematica가 없기 때문에 규칙을 약간 구부리고 Tesseract 를 사용 하여 OCR을 수행 하기로 결정했습니다 . 다양한 글꼴, 크기 및 스타일을 사용하여 "2014"를 이미지로 렌더링하고 "2014"로 인식되는 가장 작은 이미지를 찾는 프로그램을 작성했습니다. 사용 가능한 글꼴에 따라 결과가 달라집니다.

내 컴퓨터에서 "URW Gothic L"글꼴을 사용하는 53 바이트의 승자가 있습니다. 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);
                    }
                }
            }
        }
    }
}

이 항목과 유사한 항목을 허용하도록 규칙을 변경했습니다. 인상적인 파일 크기.
Charles

1

매스 매 티카 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에서이기는 방법은 아마도 아래와 같이 ImageResize [] 함수를 사용하는 것입니다.

먼저, "2014"라는 텍스트를 만들어 David Carraher의 솔루션과의 비교를 위해 GIF 파일로 저장했습니다. 텍스트는 다음과 같습니다 2014 년. 이것은 어떤 식 으로든 최적화되지 않습니다. 작은 글꼴 크기의 제네바 일뿐입니다. 다른 글꼴과 더 작은 크기가 가능할 수 있습니다. Straight 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

이미지를 흰색 테두리에서 잘라내어 숫자 사이의 간격을 더 작고 짧게 만들거나 다시 그려서 더 작게 만들 수 있습니다.
Swish

@swish 실제로 흰색 테두리를 자르면 78 바이트가됩니다.
Michael Stern
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.