Nummernschild Golf: Anerkennung

20

Siehe auch: Parsen

Einführung

Sie arbeiten in einem staatlichen Programmierteam, das die Radarkameras programmiert hat. Die Gruppe der Personen, die den Geschwindigkeitsrechner programmiert haben, hat jedoch zu viel Platz in Anspruch genommen, sodass Sie die Kennzeichenerkennungssoftware so klein wie möglich halten müssen.

Herausforderung

Geben Sie den Text auf dem Nummernschild zurück, wenn Sie ein Bild von einem Nummernschild erhalten haben.

Kennzeichen

Das Folgende sind alle Zeichen, die Ihr Programm erkennen muss:

ABCDEFG

H1JKLMN0

PQRSTUVW

XYZ01234

56789

Hinweis

Auf britischen Nummernschildern sind die Zeichen für I (i) und 1 (eins) gleich und die Zeichen für O (o) und 0 (null) gleich. Nehmen Sie aus diesem Grund immer an, dass Zeichen die Zahlen sind. Dh das folgende Nummernschild ist 10 (eine Null):

Beispiele

C0D3 GLF

B3T4 DCY

M1NUS 15

YET1CGN

Andere Regeln

Internetzugang und OCR-Bibliotheken und -Funktionen sind nicht zulässig.

Die Nummernschilder sehen immer identisch mit den oben gezeigten aus. Alle Nummernschilder haben ungefähr die gleiche Größe (aufgrund der Beschneidungsmethode kann es zu Ungenauigkeiten kommen).

Wenn Sie verlustfreie PNG-Versionen eines Nummernschilds benötigen, werde ich Ihnen diese zur Verfügung stellen.

Wertung

Das kürzeste Programm in Bytes gewinnt.

Alle Nummernschilder sind Screenshots der Suchleiste auf dieser Site

Beta-Zerfall
quelle
8
Erinnere mich daran, durch deine Geschwindigkeitsfalle zu fahren. (Mein Nummernschild enthält einen Buchstaben O.)
Neil
3
Ja, der Titel dieser Frage ist ziemlich ungenau. Wie wäre es mit "OCR ein britisches Nummernschild" ?
Lynn
3
@Neil Mein UK-Nummernschild hat sowohl ein O als auch eine 0 und sie sehen identisch aus. Es gibt natürlich Regeln, um festzustellen, welche die richtige Interpretation ist, aber das wäre eine ganz andere Herausforderung.
Level River St
2
Es ist schade, dass die Zeichen keine feste Breite haben. Das könnte zu sehr kurzen Code-Möglichkeiten führen.
GuitarPicker
1
@ YetiCGN Ihr Wunsch ist mein Befehl;)
Beta Decay

Antworten:

11

C, 409 Bytes (und ich bin genauso überrascht wie jeder andere)

f(w,h,d,X,T,B,x,y,b,v,u,t,a)char*d;{for(x=X=0;++x<w;){for(y=b=h;y--;a=0)d[(y*w+x)*3+1]&224||(b=0,X||(X=x,T=B=y),T=y<T?y:T,B=y>B?y:B);if(X*b){for(B+=1-T,X=x-X,v=5;v--;)for(u=4;u--;a|=(b>X/4*(B/5)*.35)<<19-u*5-v)for(b=0,t=X/4;t--;)for(y=B/5;y--;)b+=!(d[((v*B/5+y+T)*w+x-X+u*X/4+t)*3+1]&224);X=!putchar("g------a----mj---et-u--6----7--8s4-c-x--q--d9xy5-0v--n-2-hw-k-----3---bf-----t-r---pzn-1---l"[a%101-7]);}}}

Nimmt als Eingabe: die Breite ( w) und Höhe ( h) des Bildes, gefolgt von den gepackten RGB-Daten als Array von chars ( d). Alle anderen Funktionsparameter sind getarnte Variablendeklarationen. Ignoriert alles außer dem grünen Kanal und wendet als ersten Durchgang einen Schwellenwert von 32 an.

Meistens die gleiche Methode wie bei @ DavidC, mit der Ausnahme, dass überprüft wird, ob mindestens 35% der einzelnen Probenfelder gefüllt sind. Hoffentlich ist es dadurch robuster, Änderungen zu skalieren, aber wer weiß.

Ich habe eine Brute-Force-Methode verwendet, um herauszufinden, welche Resampling-Größe und welcher Coverage-Prozentsatz für die beste Zuverlässigkeit zu verwenden sind (dh die wenigsten Fälle eines Zeichens mit mehreren Interpretationen). Es stellte sich heraus, dass ein 4x5-Raster mit 35% Deckung am besten war. Ich habe dann eine zweite Brute-Force-Methode verwendet, um die beste Bitanordnung und den besten Modulowert zu berechnen, um die Zeichendaten in eine kurze Zeichenfolge zu packen - das untere Bit oben links, das in x und y zunimmt, wobei der Endwert% 101 gedreht ist am besten mit dieser Nachschlagetabelle:

-------g------a----mj---et-u--6----7--8s4-c-x--q--d9xy5-0v--n-2-hw-k-----3---bf-----t-r---pzn-1---l--

Das Subtrahieren von 7 bedeutet, dass die Initialen entfernt werden können, und die letzten 2 können ohne zusätzliche Arbeit entfernt werden. Dieses Entfernen bedeutet, dass bestimmte ungültige Eingaben zu einem ungültigen Speicherlesevorgang führen können, sodass bei bestimmten Bildern ein Fehler auftreten kann.

Verwendung:

Um die Bilder hinein zu bekommen, habe ich einen Wrapper mit libpng geschrieben. Es stellt sich auch heraus, dass die Bilder in der Frage trotz des Dateinamens eigentlich JPEGs (!) Sind, sodass Sie sie zuerst manuell als PNGs exportieren müssen.

#include <png.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char *const *argv) {
    if(argc < 2) {
        fprintf(stderr, "Usage: %s <file.png>\n", argv[0]);
        return 1;
    }

    const char *file = argv[1];

    FILE *const fp = fopen(file, "rb");
    if(fp == NULL) {
        fprintf(stderr, "Failed to open %s for reading\n", file);
        return 1;
    }

    png_structp png_ptr = png_create_read_struct(
        PNG_LIBPNG_VER_STRING, NULL, NULL, NULL
    );

    if(!png_ptr) {
        fclose(fp);
        fprintf(stderr, "Failed to initialise LibPNG (A)\n");
        return 1;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);

    if(!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        fclose(fp);
        fprintf(stderr, "Failed to initialise LibPNG (B)\n");
        return 1;
    }

    if(setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        fclose(fp);
        fprintf(stderr, "Error while reading PNG\n");
        return 1;
    }

    png_init_io(png_ptr, fp);
    png_set_sig_bytes(png_ptr, 0);

    png_read_png(
        png_ptr, info_ptr,
        PNG_TRANSFORM_STRIP_16 |
        PNG_TRANSFORM_GRAY_TO_RGB |
        PNG_TRANSFORM_STRIP_ALPHA,
        NULL
    );
    const png_bytep *const rows = png_get_rows(png_ptr, info_ptr);
    const int w = png_get_image_width(png_ptr, info_ptr);
    const int h = png_get_image_height(png_ptr, info_ptr);
    unsigned char *const data = malloc(w*h*3 * sizeof(unsigned char));
    for(int y = 0; y < h; ++ y) {
        for(int x = 0; x < w; ++ x) {
            memcpy(&data[y*w*3], rows[y], w * 3 * sizeof(unsigned char));
        }
    }
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    fclose(fp);

    f(w, h, (char*) data);

    free(data);

    return 0;
}

Nervenzusammenbruch

f(                          // Function
    w,h,d,                  // Parameters: width, height, RGB data
    X,T,B,x,y,b,v,u,t,a     // Variables
)char*d;{                   // K&R syntax to save lots of type decls
  for(x=X=0;++x<w;){        // Loop through each column of the image:
    for(y=b=h;y--;a=0)      //  Loop through pixels in column:
      d[(y*w+x)*3+1]&224||( //   If green < 32: (char could be signed or unsigned)
        b=0,                //    This is not a blank line
        X||(X=x,T=B=y),     //    Start a new character if not already in one
        T=y<T?y:T,          //    Record top of character
        B=y>B?y:B           //    Record bottom of character
      );
    if(X*b){                //  If we just found the end of a character:
      // Check cell grid & record bits into "a"
      for(B+=1-T,X=x-X,v=5;v--;)
        for(u=4;u--;a|=(b>X/4*(B/5)*.35)<<19-u*5-v)
          // Calculate coverage of current cell
          for(b=0,t=X/4;t--;)
            for(y=B/5;y--;)
              b+=!(d[((v*B/5+y+T)*w+x-X+u*X/4+t)*3+1]&224);

      // Look up meaning of "a" in table & print, reset X to 0
      X=!putchar(
        "g------a----mj---et-u--6----7--8s4-c-x--q--d9x"
        "y5-0v--n-2-hw-k-----3---bf-----t-r---pzn-1---l"
        [a%101-7]
      );
    }
  }
}
Dave
quelle
+1 für mit freaking Python und Mathemetica schlagen C . Oooollllld Schule, yo.
Robert Fraser
+1 für das GEWINNEN mit C, wie, hätte nie gedacht, dass das passieren könnte, nicht
wahr
12

Mathematica 1170 1270 1096 1059 650 528 570 551 525 498 Bytes

Die neueste Version spart 27 Byte, da die Platte vor dem Parsen nicht "zugeschnitten" werden muss. Die vorletzte Version sparte 26 Bytes, indem nur 10 der ursprünglich 24 Abtastpunkte verwendet wurden.

z=Partition;h@i_:=i~PixelValue~#/.{_,_,_,z_}:>⌈z⌉&/@z[{45,99,27,81,63,81,9,63,45,63,9,45,45,45,63,45,45,27,45,9},2];f@p_:=h/@SortBy[Select[p~ColorReplace~Yellow~ComponentMeasurements~{"Image","Centroid"},100<Last@ImageDimensions@#[[2,1]]<120&],#[[2,2,1]]&][[All,2,1]]/.Thread[IntegerDigits[#,2,10]&/@(z[IntegerDigits[Subscript["ekqeuiv5pa5rsebjlic4i5886qsmvy34z5vu4e7nlg9qqe3g0p8hcioom6qrrkzv4k7c9fdc3shsm1cij7jrluo", "36"]],4]/.{a__Integer}:> FromDigits[{a}])-> Characters@"BD54TARP89Q0723Z6EFGCSWMNVYXHUJKL1"]

Durch die Idee von LegionMammal978, die lange Liste der Basis-10-Zahlen als einzelne Basis-36-Zahl zu packen, wurden 122 Byte gespeichert. Er hat weitere 20 Bytes vom endgültigen Code entfernt.

Der Sprung von 528 auf 570 Byte war auf zusätzlichen Code zurückzuführen, um sicherzustellen, dass die Reihenfolge der zurückgegebenen Buchstaben der Reihenfolge der Buchstaben auf dem Nummernschild entsprach. Der Schwerpunkt für jeden Buchstaben enthält die x-Koordinate, die die relativen Positionen der Buchstaben entlang x angibt.


Ungolfed Code

coordinates=Flatten[Table[{x,y},{y,99,0,-18},{x,9,72,18}],1];
h[img_] :=ArrayReshape[PixelValue[img, #] /. {_, _, _, z_} :>  ⌈z⌉  & /@ coordinates, {6, 4}];
plateCrop[img_]:=ColorReplace[ImageTrim[img,{{100,53},{830,160}}],Yellow];
codes={{{15,13,15,13,13,15},"B"},{{15,8,8,8,9,15},"C"},{{15,13,13,13,13,15},"D"},{{15,8,14,8,8,15},"E"},{{15,8,14,8,8,8},"F"},{{15,8,8,11,9,15},"G"},{{6,6,6,6,15,9},"A"},{{9,9,15,15,9,9},"H"},{{8,8,8,8,8,15},"L"},{{9,15,15,15,13,9},"M"},{{15,9,9,9,9,15},"0"},{{9,10,12,14,10,9},"K"},{{9,13,13,11,11,9},"N"},{{8,8,8,8,8,8},"1"},{{1,1,1,1,9,15},"J"},{{15,9,15,14,8,8},"P"},{{15,9,9,9,15,15},"Q"},{{15,9,15,14,10,11},"R"},{{15,8,12,3,1,15},"S"},{{9,15,6,6,6,6},"V"},{{15,6,6,6,6,6},"T"},{{9,15,15,15,15,15},"W"},{{9,9,9,9,9,15},"U"},{{9,14,6,6,14,9},"X"},{{9,14,6,6,6,6},"Y"},{{15,3,2,4,12,15},"Z"},{{15,9,9,9,9,15},"0"},{{8,8,8,8,8,8},"1"},{{15,1,3,6,12,15},"2"},{{15,1,3,1,9,15},"3"},{{2,6,6,15,2,2},"4"},{{7,12,14,1,1,15},"5"},{{15,8,14,9,9,15},"6"},{{15,1,2,2,6,4},"7"},{{15,9,15,9,9,15},"8"},{{15,9,15,1,9,15},"9"}};
decryptRules=Rule@@@codes;
isolateLetters[img_]:=SortBy[Select[ComponentMeasurements[plateCrop[img],{"Image","Centroid"}],ImageDimensions[#[[2,1]]][[2]]>100&],#[[2,2,1]]&][[All,2,1]]
f[plate_]:=FromDigits[#,2]&/@#&/@h/@isolateLetters[plate]/.decryptRules

Überblick

Die Grundidee besteht darin, zu prüfen, ob eine systematische Abtastung von Pixeln aus dem Eingabebild mit Pixeln aus derselben Position auf den Originalbildern übereinstimmt. Ein Großteil des Codes besteht aus den Bit-Signaturen für jedes Zeichen.

Das Diagramm zeigt die Pixel, die aus den Buchstaben "J", "P", "Q" und "R" abgetastet wurden.

jpqr

Die Pixelwerte können als Matrizen dargestellt werden. Die dunklen, fetten 1entsprechen schwarzen Zellen. Die 0entsprechen weißen Zellen.

jjjj

Dies sind die Regeln zum Ersetzen der Entschlüsselung für JPQ R.

{1, 1, 1, 1, 9, 15} -> "J",
{15, 9, 15, 14, 8, 8} -> "P",
{15, 9, 9, 9, 15, 15 } -> "Q",
{15, 9, 15, 14, 10, 11} -> "R"

Es sollte verständlich sein, warum die Regel für "0" lautet:

{15, 9, 9, 9, 9, 15} -> "0"

und somit vom Buchstaben "Q" unterscheidbar.


Das Folgende zeigt die 10 Punkte, die in der endgültigen Version verwendet wurden. Diese Punkte reichen aus, um alle Zeichen zu identifizieren.

reduziert


Was machen die Funktionen?

plateCrop[img]Entfernt den Rahmen und die linke Kante von der Platte, wird der Hintergrund weiß. Ich konnte diese Funktion aus der endgültigen Version entfernen, indem ich Bildkomponenten auswählte, mögliche Buchstaben, die zwischen 100 und 120 Pixel hoch waren.

Plattenkultur


isolateLetters[img] Entfernt die einzelnen Buchstaben aus dem zugeschnittenen Bild.

Wir können anzeigen, wie es funktioniert, indem wir zeigen, wo das zugeschnittene Bild, das von ausgegeben wird, plateCropals Eingabe für dient isolateLetters. Die Ausgabe ist eine Liste einzelner Zeichen.

Briefe


Coordinates24 gleichmäßig verteilte Positionen zur Überprüfung der Pixelfarbe. Die Koordinaten entsprechen denen in der ersten Abbildung.

coordinates=Flatten[Table[{x,y},{y,99,0,-18},{x,9,72,18}],1];

{{9, 99}, {27, 99}, {45, 99}, {63, 99}, {9, 81}, {27, 81}, {45, 81}, {63, 81}, { 9, 63}, {27, 63}, {45, 63}, {63, 63}, {9, 45}, {27, 45}, {45, 45}, {63, 45}, {9, 27}, {27, 27}, {45, 27}, {63, 27}, {9, 9}, {27, 9}, {45, 9}, {63, 9}}


h wandelt die Pixel in Binär um.

h[img_] :=ArrayReshape[PixelValue[img, #] /. {_, _, _, z_} :>  ⌈z⌉  & /@ coordinates, {6, 4}];

codessind die Signatur für jedes Zeichen. Die Dezimalwerte sind Abkürzungen des Binärcodes für schwarze (0) und weiße (1) Zellen. In der Golfversion wird die Basis 36 verwendet.

codes={{{15, 9, 9, 9, 9, 15}, "0"}, {{8, 8, 8, 8, 8, 8}, "1"}, {{15, 1, 3,6,12, 15}, "2"}, {{15, 1, 3, 1, 9, 15}, "3"}, {{2, 6, 6, 15, 2, 2}, "4"}, {{7, 12, 14, 1, 1, 15},"5"}, {{15, 8, 14, 9, 9, 15}, "6"}, {{15, 1, 2, 2, 6, 4},"7"}, {{15, 9, 15, 9, 9, 15}, "8"}, {{15, 9, 15, 1, 9, 15},"9"}, {{6, 6, 6, 6, 15, 9}, "A"}, {{15, 13, 15, 13, 13, 15}, "B"}, {{15, 8, 8, 8, 9, 15}, "C"}, {{15, 13, 13, 13, 13, 15}, "D"}, {{15, 8, 14, 8, 8, 15}, "E"}, {{15, 8, 14, 8, 8, 8},"F"}, {{15, 8, 8, 11, 9, 15}, "G"}, {{9, 9, 15, 15, 9, 9}, "H"}, {{1, 1, 1, 1, 9, 15}, "J"}, {{9, 10, 12, 14, 10, 9}, "K"}, {{8, 8, 8, 8, 8, 15}, "L"}, {{9, 15, 15, 15, 13, 9}, "M"}, {{9, 13, 13, 11, 11, 9}, "N"}, {{15, 9, 15, 14, 8, 8}, "P"}, {{15, 9, 9, 9, 15, 15}, "Q"}, {{15, 9, 15, 14, 10, 11}, "R"}, {{15, 8, 12, 3, 1, 15}, "S"}, {{15, 6, 6, 6, 6, 6}, "T"}, {{9, 9, 9, 9, 9, 15}, "U"}, {{9, 15, 6, 6, 6, 6}, "V"}, {{9, 15, 15, 15, 15, 15}, "W"}, {{9, 14, 6, 6, 14, 9}, "X"}, {{9, 14, 6, 6, 6, 6}, "Y"}, {{15, 3, 2, 4, 12, 15}, "Z"}};

(* decryptRulesdienen zum Ersetzen von Signaturen durch die entsprechenden Zeichen *)

decryptRules=Rule@@@codes;

f ist die Funktion, die ein Bild von einem Nummernschild erstellt und einen Buchstaben zurückgibt.

f[plate_]:=FromDigits[#,2]&/@#&/@h/@isolate[plateCrop@plate]/.decryptRules;

Platten

{"A", "B", "C", "D", "E", "F", "G"}
{"H", "1", "J", "K", "L", "M", "N", "0"}
{"P", "Q", "R", "S", "T", "U", "V", "W"}
{"X", "Y", "Z", "0", "1", "2", "3", "4"}
{"5", "6", "7", "8", "9"}


Golf gespielt

Der Code wird mit einer einzelnen Dezimalzahl gekürzt, um alle 24 Bits (weiß oder schwarz) für jedes Zeichen darzustellen. Zum Beispiel verwenden die Buchstaben „J“ die folgende Ersetzungsregel: 1118623 -> "J".

1118623 entspricht

IntegerDigits[1118623 , 2, 24]

{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1}

die kann als umgepackt werden

ArrayReshape[{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1}, {6, 4}]

{{0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}, {0, 0, 0, 1}, {1, 0, 0, 1} , {1, 1, 1, 1}}

Das ist einfach die Matrix für "J", die wir oben gesehen haben.

%//MatrixForm

Matrix

Eine weitere Einsparung ergibt sich aus der Darstellung des Alphabets "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"anstelle einer Buchstabenliste.

Schließlich wurden alle Funktionen aus der Langversion, mit Ausnahme hder Funktion, in die Funktion integriert fund nicht separat definiert.


h@i_:=ArrayReshape[i~PixelValue~#/.{_,_,_,z_}:>⌈z⌉&/@Join@@Table[{x,y},{y,99,0,-18},{x,9,72,18}],{6,4}];f@p_:=#~FromDigits~2&/@(Join@@@h/@SortBy[Select[p~ImageTrim~{{100,53},{830,160}}~ColorReplace~Yellow~ComponentMeasurements~{"Image","Centroid"},Last@ImageDimensions@#[[2,1]]>100&],#[[2,2,1]]&][[;;,2,1]])/.Thread[IntegerDigits[36^^1c01agxiuxom9ds3c3cskcp0esglxf68g235g1d27jethy2e1lbttwk1xj6yf590oin0ny1r45wc1i6yu68zxnm2jnb8vkkjc5yu06t05l0xnqhw9oi2lwvzd5f6lsvsb4izs1kse3xvx694zwxz007pnj8f6n,8^8]->Characters@"J4A51LUHKNYXVMW732ZTCGSFE60Q98PRDB"]
DavidC
quelle
@ DavidC Scheint, als hätte SE es vermasselt; versuchen Sie es {1118623, 2518818, ..., 16645599}mit diesem zu ersetzen .
LegionMammal978
@ LegionMammal978, Ihr Vorschlag führte zu einer Kürzung des Codes um über 100 Bytes. Ich verstehe jetzt besser, wie Mathematica mit Basen umgeht.
DavidC
@DavidC Es sieht auch so aus, als ob sich ein Whitespace in Ihren Code eingeschlichen hat, und ich zähle 571 Bytes ohne diesen Code. Darüber hinaus können einige Funktionen in Infix-Form konvertiert werden. x[[All,2,1]]kann durch ersetzt werden x[[;;,2,1]]. Flatten[x,1]ist gleichbedeutend mit Join@@xund Flatten[#,1]&/@xist gleichbedeutend mit Join@@@x. Es gibt noch ein paar kleinere Optimierungen, die durchgeführt werden können. Der 551-Byte-Code nach diesen Golfspielen.
LegionMammal978
Nette Tipps und sorgfältiges Lesen. Vielen Dank.
DavidC
Haben Sie versucht, die Anzahl der Abtastpunkte zu minimieren, indem Sie sie verschoben haben?
Sparr
4

C #, 1040 1027 Bytes

using System;using System.Drawing;class _{static Bitmap i;static bool b(int x,int y)=>i.GetPixel(x,y).GetBrightness()<.4;static char l(int x,int y){if(y<45)return b(x+5,145)?((b(x+30,100)||b(x+30,50))?(b(x+68,94)?(b(x+40,50)?'D':b(x+40,120)?(b(x+45,80)?'M':'N'):'H'):b(x,97)?(b(x+30,140)?'E':b(x+60,70)?(b(x+50,140)?'R':'P'):'F'):b(x+65,45)?(b(x+5,100)?'K':b(x+30,145)?'Z':'X'):'B'):b(x+30,140)?'L':'1'):b(x+30,55)?(b(x+60,70)?'7':'T'):b(x+2,100)?'U':b(x+30,70)?'W':b(x+15,100)?'V':'Y';if(y<70)return b(x+50,110)?(b(x+50,70)?(b(x+10,110)?(b(x+30,100)?(b(x+55,80)?'8':'6'):b(x+55,80)?'0':'G'):b(x+10,70)?(b(x+60,80)?'9':'S'):b(x+60,120)?'3':'2'):'G'):b(x+30,125)?'Q':'C';if(y>150)return'A';if(y>120)return'J';else return b(x+10,135)?'5':'4';}static void Main(string[]z){i=new Bitmap(Console.ReadLine());bool s=true;int w=int.MinValue;for(int x=100;x<800;++x){for(int y=40;y<160;++y)if(s){if(b(x,y)){if(w>50)Console.Write(' ');Console.Write(l(x,y));s=false;goto e;}}else if(b(x,y))goto e;if(!s){s=true;w=0;}else++w;e:continue;}}}

Ungolfed:

using System;
using System.Drawing;

class _
{
    static Bitmap bmp;
    static bool b(int x, int y) => bmp.GetPixel(x, y).GetBrightness() < .4;
    static char l(int x, int y)
    {
        if (y < 45)
            return b(x + 5, 145) ? ((b(x + 30, 100) || b(x + 30, 50)) ? (b(x + 68, 94) ? (b(x + 40, 50) ? 'D' : b(x + 40, 120) ? (b(x + 45, 80) ? 'M' : 'N') : 'H') : b(x, 97) ? (b(x + 30, 140) ? 'E' : b(x + 60, 70) ? (b(x + 50, 140) ? 'R' : 'P') : 'F') : b(x + 65, 45) ? (b(x + 5, 100) ? 'K' : b(x + 30, 145) ? 'Z' : 'X') : 'B') : b(x + 30, 140) ? 'L' : '1') : b(x + 30, 55) ? (b(x + 60, 70) ? '7' : 'T') : b(x + 2, 100) ? 'U' : b(x + 30, 70) ? 'W' : b(x + 15, 100) ? 'V' : 'Y';
        if (y < 70)
            return b(x + 50, 110) ? (b(x + 50, 70) ? (b(x + 10, 110) ? (b(x + 30, 100) ? (b(x + 55, 80) ? '8' : '6') : b(x + 55, 80) ? '0' : 'G') : b(x + 10, 70) ? (b(x + 60, 80) ? '9' : 'S') : b(x + 60, 120) ? '3' : '2') : 'G') : b(x + 30, 125) ? 'Q' : 'C';
        if (y > 150)
            return 'A';
        if (y > 120)
            return 'J';
        if (y > 95)
            return b(x + 10, 135) ? '5' : '4';
        return '-';
    }
    static void Main(string[] args)
    {
        bmp = new Bitmap(Console.ReadLine());
        bool state = true;
        int space = int.MinValue;
        for (int x = 100; x < 800; ++x)
        {
            for (int y = 40; y < 160; ++y)
                if (state)
                {
                    if (b(x, y))
                    {
                        if (space > 50)
                            Console.Write(' ');
                        Console.Write(l(x, y));
                        state = false;
                        goto bad;
                    }
                }
                else if (b(x, y))
                    goto bad;
            if (!state)
            {
                state = true;
                space = 0;
            }
            else
                ++space;
            bad:
            continue;
        }
    }
}

Grundsätzlich habe ich einige spezifische Bezugspunkte gefunden, um gelb / schwarz zu prüfen, um die Identität jedes Zeichens zu bestimmen.

Nick Mertin
quelle
Sind Sie sicher, dass die bereitgestellten Bilder keine Überanpassung aufweisen und dass Kennzeichen erkannt werden, bei denen die Zeichen z. B. um 10 Pixel verschoben sind?
YetiCGN
@YetiCGN sollte es erkennen, solange die Größe gleich ist und sie sich in der gleichen vertikalen Position befinden. Ich habe mit allen zur Verfügung gestellten Beispielen versucht, und es funktioniert; Bitte lassen Sie mich wissen, wenn Sie einen finden, bei dem dies nicht der Fall ist
Nick Mertin
Ich möchte Visual Studio nicht nur aus diesem Grund installieren, sondern Sie können i.imgur.com/i8jkCJu.png ausprobieren, das etwas kleiner ist. Ich denke, es ist sicher anzunehmen, dass alle Einsendungen Bilder von dieser bestimmten Website sein werden. Ursprünglich lautete mein Kommentar eher "Was ist, wenn es sich um einen echten Plattenscan handelt?" / "Was ist, wenn jemand anderes alle Zeichen vertikal um 10 Pixel verschoben hat, um eine Platte zu erstellen?"
YetiCGN
@YetiCGN Sie sollten nicht VisualStudio zum Kompilieren benötigen, nurcsc.exe main.cs /r:System.Drawing.dll
VisualMelon
2

PHP - 1741 1674 1143 Bytes

Es wurde zuerst eingerichtet, indem die Profile der Zeichen aus den ersten Beispielen gelernt wurden, die dann jedes Zeichen in sechs Zahlen zusammenfassten. Ich habe sechs gewählt, weil ich ursprünglich fünf hatte, und es hat nicht so gut funktioniert, wie ich es gerne hätte, aber sechs scheint viel besser zu funktionieren. Ein Großteil der Optimierung besteht darin, diese Profile in immer kleinere Bytezahlen zu zerlegen.

Das erste und das zweite Profil *lhdfdnund |nnmmkksind eigentlich die blaue Klecks mit „GB“ am unteren Rand *, und die rechte Grenze |, die wir ignorieren. Es ist sicherer, sie einzuschließen, damit der Blob und der rechte Rand etwas haben, mit dem sie verglichen werden können.

Sollte mit jedem Bildformat und jeder angemessenen Skalierung fertig werden, vorausgesetzt, das Seitenverhältnis ändert sich nicht zu stark, dunkle und helle Farben und sogar ein bisschen Rauschen und Schattierung!

Es braucht den Rand, zumindest oben und unten, der Teil des Profils ist.

<?php $X=[];foreach(str_split('*lhdfdn|nnmmkkA<njjk;BOnKB`^Chn::E7DHn?1X`EnkGGD4Fn_330!Gnj9G[IHnX!!XnJ%(##knKnX.EN6LnX!!!!Mn_<:bnNn^77_nPn^33@6QhfBDjnRn_8LaDSOlYYnUT$$nn$$Uh_##^nV9c][n;W_nWTlhXHnLTiCY4LhnM5ZJbnmaI0ng88lk1nnnnnn2C[__n`34B?Kna4+=Fnb"5NnUReX6gnKKaM7*4Xnb=8gkIIne9K`KKni',7)as$s){$t=[];foreach(str_split(substr($s,1))as$u)$t[]=ord($u)-11;$X[$s[0]]=$t;}echo m(r($argv[1]),$X)."\n";function r($u){$a=[];$i=imagecreatefromstring(file_get_contents($u));$w=imagesx($i);$h=imagesy($i);$s=[];for($x=0;$x<$w;$x++){$s[$x]=0;for($y=0;$y<$h;$y++){$p=imagecolorsforindex($i,imagecolorat($i,$x,$y));if(3*$p['red']+6*$p['green']+$p['blue']<1280)$s[$x]++;}}$j=0;$k=[];for($x=0;$x<$w;$x++){if($s[$x]>$h/10)for($o=0;$o<6;$o++)$k[]=$s[$x];elseif(count($k)){$a[]=$k;$j++;$k=[];}}$b=[];foreach($a as$v){$t=[];$u=array_chunk($v,intval(count($v)/6));foreach($u as$c)$t[]=array_sum($c)/count($c);$m=99/max($t);$e=[];foreach($t as$x)$e[]=intval($x*$m+0.5);$b[]=$e;}return$b;}function m($A,$X){$r='';foreach($A as$a){$s=INF;$c='';foreach($X as$k=>$x){$t=0;for($i=0;$i<6;$i++)$t+=pow($a[$i]-$x[$i],2);if($s>$t){$s=$t;$c=$k;}}$r.=$c;}return trim($r,'|*');}

Speichern unter ocr.phpund dann über die Befehlszeile ausführen:

$ php ocr.php http://i.imgur.com/UfI63md.png
ABCDEFG

$ php ocr.php http://i.imgur.com/oSAK7dy.png
H1JKLMN0

$ php ocr.php http://i.imgur.com/inuIHjm.png
PQRSTUVW

$ php ocr.php http://i.imgur.com/Th0QkhT.png
XYZ01234

$ php ocr.php http://i.imgur.com/igH3ZPQ.png
56789

$ php ocr.php http://i.imgur.com/YfVwebo.png
10

$ php ocr.php http://i.imgur.com/3ibQARb.png
C0D3GLF

$ php ocr.php http://i.imgur.com/c7XZqhL.png
B3T4DCY

$ php ocr.php http://i.imgur.com/ysBgXhn.png
M1NUS15

Für diejenigen, die interessiert sind, ist hier der Lerncode. Speichern Sie als learn.phpund führen Sie in der Befehlszeile keine Argumente aus.

<?php

define('BANDS', 6);

main();

function main()
{
    $glyphs = [];

    learn($glyphs, 'http://imgur.com/UfI63md.png', '*ABCDEFG|');
    learn($glyphs, 'http://imgur.com/oSAK7dy.png', '*H1JKLMN0|');
    learn($glyphs, 'http://imgur.com/inuIHjm.png', '*PQRSTUVW|');
    learn($glyphs, 'http://imgur.com/Th0QkhT.png', '*XYZ01234|');
    learn($glyphs, 'http://imgur.com/igH3ZPQ.png', '*56789|');

    $profiles = summarize($glyphs);

    foreach ($profiles as $glyph=>$profile)
    {
        print $glyph;
        foreach ($profile as $value)
            print chr($value + 11);
        print "\n";
    }
}

function learn(&$glyphs, $url, $answer)
{
    $image = imagecreatefromstring(file_get_contents($url));
    $width = imagesx($image);
    $height = imagesy($image);
    $counts = [];
    for ($x = 0; $x < $width; $x++)
    {
        $counts[$x] = 0;
        for ($y = 0; $y < $height; $y++)
        {
            $pixel = imagecolorsforindex($image, imagecolorat($image, $x, $y));
            if (3 * $pixel['red'] + 6 * $pixel['green'] + $pixel['blue'] < 1280)
                $counts[$x]++;
        }
    }

    $index = 0;
    $expanded = [];
    for ($x = 0; $x < $width; $x++)
    {
        if ($counts[$x] > $height / 10)
            for ($inner = 0; $inner < BANDS; $inner++)
                $expanded[] = $counts[$x];
        else if (count($expanded)) {
            $glyphs[$answer[$index]] = $expanded;
            $index++;
            $expanded = [];
        }
    }
}

function summarize($glyphs)
{
    $profiles = [];
    foreach ($glyphs as $glyph=>$expanded)
    {
        $averages = [];
        $bands = array_chunk($expanded, count($expanded) / BANDS);
        foreach ($bands as $band)
            $averages[] = array_sum($band) / count($band);
        $scaling = 99 / max($averages);
        $profile = [];
        foreach ($averages as $average)
            $profile[] = intval($average * $scaling + 0.5);
        $profiles[$glyph] = $profile;
    }
    return $profiles;
}

?>

quelle
Sie sollten die Leerzeichen in die Ausgabe einschließen
Beta Decay
3
Dies ist nicht in den Spezifikationen unter Folgendes sind alle Zeichen, die Ihr Programm erkennen muss , nur die Zeichen AH, JN, PZ und 0-9. Keine Erwähnung von Leerzeichen.
Oh, okay, dann geht es dir gut
Beta Decay
"Das erste und zweite Profil [...] sind eigentlich der blaue Fleck mit" GB "am unteren Rand und dem rechten Rand, den wir ignorieren." Warum haben Sie sie dann in den Code aufgenommen, insbesondere wenn der Array-Schlüssel mit einer leeren Zeichenfolge überschrieben wird? Plus: Es ist erlaubt, kurze offene Syntax für Code-Golf zu verwenden! :-)
YetiCGN
@YetiCGN - Wenn dies nicht der Fall ist, versucht der Code, sie mit etwas anderem abzugleichen! Ich wusste nicht, dass sie überschrieben wurden, zum Glück funktionierte der Code immer noch. Überarbeitung. Möglicherweise können Sie einige meiner Änderungen an Ihre Antwort anpassen.
0

PHP, 971 970 Bytes

Greift stark auf Yimin Rong ‚s Antwort , die ernsthaft golfed gelegt werden kann, vor allem den Array - Indizes, und in eine Phar mit gzip - Kompression.

Laden Sie den phar herunter

Dies ist meine verbesserte Basisversion mit 1557 bis 1535 Bytes, die einfach unter dem Dateinamen "o" gespeichert wurde:

<?$X=[[99,92,45,45,97,96],[99,99,99,99,99,99],[56,80,84,84,99,85],[41,55,52,64,99,86],[32,50,59,99,87,23],[67,99,74,71,90,77],[92,99,64,64,86,66],[31,41,77,99,87,50],[92,96,62,62,99,90],[64,85,64,64,99,94],''=>[99,99,98,98,96,96],A=>[49,99,95,95,96,48],B=>[68,99,64,55,85,83],C=>[93,99,47,47,58,44],D=>[61,99,52,38,77,85],E=>[99,96,60,60,57,41],F=>[99,84,40,40,37,22],G=>[99,95,46,60,80,62],H=>[99,77,22,22,77,99],1=>[99,99,99,99,99,99],J=>[26,29,24,24,96,99],K=>[99,77,35,58,67,43],L=>[99,77,22,22,22,22],M=>[99,84,49,47,87,99],N=>[99,83,44,44,84,99],P=>[99,83,40,40,53,43],Q=>[93,91,55,57,95,99],R=>[99,84,45,65,86,57],S=>[68,97,78,78,99,74],T=>[25,25,99,99,25,25],U=>[93,84,24,24,83,99],V=>[46,88,82,80,99,48],W=>[84,99,76,73,97,93],X=>[61,99,65,73,94,56],Y=>[41,65,93,99,66,42],Z=>[63,87,99,98,86,62]];echo m(r($argv[1]),$X);function r($u){$a=[];$i=imagecreatefromstring(join('',file($u)));$w=imagesx($i);$h=imagesy($i);$s=[];for(;$x<$w;$x++){$s[$x]=0;for($y=0;$y<$h;$y++){$p=imagecolorsforindex($i,imagecolorat($i,$x,$y));if(3*$p[red]+6*$p[green]+$p[blue]<1280)$s[$x]++;}}$j=0;$k=[];for(;$z<$w;$z++){if($s[$z]>$h/10)for($o=0;$o<6;$o++)$k[]=$s[$z];elseif(count($k)){$a[]=$k;$j++;$k=[];}}$b=[];foreach($a as$v){$t=[];$u=array_chunk($v,~~(count($v)/6));foreach($u as$c)$t[]=array_sum($c)/count($c);$m=99/max($t);$e=[];foreach($t as$x)$e[]=~~($x*$m+.5);$b[]=$e;}return$b;}function m($A,$X){$r='';foreach($A as$a){$s=INF;$c='';foreach($X as$k=>$x){$t=0;for($i=0;$i<6;)$t+=($a[$i]-$x[$i++])**2;if($s>$t){$s=$t;$c=$k;}}$r.=$c;}return$r;}

Verbesserungen:

1. Stufe

  • Numerische Array-Indizes haben das Array entfernt und neu angeordnet, String-Indizes als implizite Konstanten

2. Stufe

  • Ersetzt intvaldurch ~~(spart 8 Bytes, zwei Vorkommen)
  • Die for-Loop-Initialisierung wurde entfernt, wenn dies nicht erforderlich ist
  • file_get_contents($u)ersetzt durch join('',file($u))(spart 5 Bytes)
  • und ein paar andere

Leider werden alle Verbesserungen der zweiten Stufe nur in 1 Byte weniger gezippten Code übersetzt. :-D

Und dieser Code wurde verwendet, um den Phar zu erstellen:

<?php
$phar = new Phar('o.phar');
$phar->addFile('o');
$phar['o']->compress(Phar::GZ);
$phar->setStub('<?Phar::mapPhar(o.phar);include"phar://o.phar/o";__HALT_COMPILER();');

Testen Sie mit php ocr.phar http://i.imgur.com/i8jkCJu.pngoder einem anderen Testfallbild.

YetiCGN
quelle