Numero di targa da golf: riconoscimento


20

Vedi anche: Analisi

introduzione

Stai lavorando a un team di programmazione governativo, che ha programmato gli autovelox. Tuttavia, il gruppo di persone che ha programmato il calcolatore di velocità ha occupato troppo spazio, quindi è necessario rendere il software di riconoscimento della targa il più piccolo possibile.

Sfida

Data l'immagine di una targa, restituisce il testo sulla targa.

Numeri di targa

Di seguito sono riportati tutti i caratteri che il tuo programma deve riconoscere:

ABCDEFG

H1JKLMN0

PQRSTUVW

XYZ01234

56789

Nota

Sulle targhe britanniche, i caratteri per I (i) e 1 (uno) sono gli stessi e i caratteri per O (o) e 0 (zero) sono gli stessi. Per questo motivo, supponi sempre che i caratteri siano i numeri. Vale a dire la seguente targa è 10 (uno zero):

Esempi

C0D3 GLF

B3T4 DCY

M1NUS 15

YET1CGN

Altre regole

Le librerie e le funzioni di accesso a Internet e OCR non sono consentite.

Le targhe appariranno sempre identiche a quelle mostrate sopra. Tutte le targhe avranno all'incirca le stesse dimensioni (ci saranno alcune imprecisioni dovute al metodo di ritaglio).

Se hai bisogno di versioni PNG senza perdita di targhe, te le fornirò.

punteggio

Vince il programma più breve in byte.

Tutte le targhe sono schermate della barra di ricerca in questo sito


8
Ricordami di guidare attraverso la tua trappola della velocità. (La mia targa contiene una lettera O.)
Neil,

3
Sì, il titolo di questa domanda è piuttosto impreciso. Che ne dici di "OCR una targa britannica" ?
Lynn,

3
@Neil La mia targa del Regno Unito ha sia una O che una 0 e sembrano identiche. Esistono ovviamente delle regole per determinare quale sia l'interpretazione corretta, ma sarebbe un'altra sfida.
Level River St

2
Peccato che i personaggi non abbiano una larghezza fissa. Ciò potrebbe comportare alcune possibilità di codici molto brevi.
GuitarPicker,

1
@YetiCGN Il tuo desiderio è il mio comando;)
Decadimento beta

Risposte:


11

C, 409 byte (e sono sorpreso come chiunque)

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

Accetta come input: la larghezza ( w) e l'altezza ( h) dell'immagine, seguite dai dati RGB compressi come una matrice di chars ( d). Tutti gli altri parametri di funzione sono dichiarazioni variabili mascherate. Ignora tutto tranne il canale verde e applica una soglia di 32 come passaggio iniziale.

Principalmente uguale al metodo di @ DavidC, tranne per il fatto che almeno il 35% di ogni casella campione è riempito. Speriamo che ciò renda più robusto scalare i cambiamenti, ma chi lo sa.

Ho usato un metodo a forza bruta per scoprire quale percentuale di ricampionamento e percentuale di copertura usare per la migliore affidabilità (ovvero il minor numero di casi di un personaggio con interpretazioni multiple). Si è scoperto che una griglia 4x5 con una copertura del 35% era la migliore. Ho quindi usato un secondo metodo di forza bruta per calcolare la migliore disposizione dei bit e il valore del modulo per impacchettare i dati dei caratteri in una stringa breve: il bit basso in alto a sinistra, aumentando in x poi y, con il valore finale% 101 attivato meglio, dando questa tabella di ricerca:

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

Sottraendo 7 significa che le iniziali possono essere rimosse e le ultime 2 possono essere rimosse senza ulteriore lavoro. Questa rimozione significa che alcuni input non validi potrebbero causare una lettura della memoria non valida, quindi potrebbe essere segfault su immagini particolari.

Uso:

Per ottenere le immagini, ho scritto un wrapper usando libpng. Inoltre, nonostante il nome del file, le immagini nella domanda sono in realtà jpeg (!), Quindi dovrai prima esportarle manualmente come png.

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

Abbattersi

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

+1 per battere Python e Mathemetica con impazzendo C . Oooollllld school, yo.
Robert Fraser,

+1 per VINCERE con C, tipo, non
avrei

12

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

L'ultima versione consente di risparmiare 27 byte non richiedendo che la "piastra" venga tagliata prima di essere analizzata. La penultima versione ha salvato 26 byte utilizzando solo 10 dei 24 punti campione originali.

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

122 byte salvati attraverso l'idea di LegionMammal978 di impacchettare la lunga lista di numeri di base 10 come un singolo numero di base 36. Ha eliminato altri 20 byte dal codice finale.

Il salto da 528 a 570 byte era dovuto a un codice aggiuntivo per garantire che l'ordine delle lettere restituite corrispondesse all'ordine delle lettere sulla targa. Il centroide per ogni lettera contiene la coordinata x, che rivela le posizioni relative delle lettere lungo x.


Codice Ungolfed

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

Panoramica

L'idea di base è verificare se un campionamento sistematico di pixel dall'immagine di input corrisponde a pixel dalla stessa posizione sulle immagini in buona fede. Gran parte del codice è costituito dalle firme dei bit per ciascun carattere,

Il diagramma mostra i pixel campionati dalle lettere "J", "P", "Q" e "R".

jpqr

I valori dei pixel possono essere rappresentati come matrici. Gli oscuri, in grassetto 1corrispondono ai globuli neri. La 0's corrispondono alle cellule bianche.

jjjj

Queste sono le regole di sostituzione della decodifica per 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"

Dovrebbe essere possibile capire perché la regola per "0" è:

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

e quindi distinguibile dalla lettera "Q".


Quanto segue mostra i 10 punti utilizzati nella versione finale. Questi punti sono sufficienti per identificare tutti i personaggi.

ridotto


Cosa fanno le funzioni

plateCrop[img]rimuove la cornice e il bordo sinistro dal piatto, rende lo sfondo bianco. Sono stato in grado di eliminare questa funzione dalla versione finale selezionando i componenti dell'immagine, possibili lettere alte tra 100 e 120 pixel.

platecrop


isolateLetters[img] rimuove le singole lettere dall'immagine ritagliata.

Siamo in grado di visualizzare come funziona mostrando dove l'immagine ritagliata, l'output da plateCropva come input per isolateLetters. L'output è un elenco di singoli caratteri.

lettere


Coordinatessono 24 posizioni distribuite uniformemente per controllare il colore dei pixel. Le coordinate corrispondono a quelle nella prima figura.

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 converte i pixel in binari.

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

codessono la firma per ogni personaggio. I valori decimali sono abbreviazioni del codice binario per le celle nere (0) e bianche (1). Nella versione da golf, viene utilizzata la base 36.

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

(* decryptRulesservono per sostituire le firme con i rispettivi caratteri *)

decryptRules=Rule@@@codes;

f è la funzione che acquisisce l'immagine di una targa e restituisce una lettera.

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

piatti

{"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"}


golfed

Il codice viene abbreviato utilizzando un singolo numero decimale per rappresentare tutti i 24 bit (bianco o nero) per ciascun carattere. Per esempio, la lettera "J" utilizza la seguente regola di sostituzione: 1118623 -> "J".

1118623 corrisponde a

IntegerDigits[1118623 , 2, 24]

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

che può essere riconfezionato come

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

che è semplicemente la matrice per "J" che abbiamo visto sopra.

%//MatrixForm

matrice

Un altro risparmio deriva dal rappresentare l'alfabeto "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"piuttosto che come un elenco di lettere.

Infine, tutte le funzioni della versione lunga, tranne h, sono state integrate nella funzione fanziché definite separatamente.


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 Sembra che SE abbia fatto un casino; prova a sostituirlo {1118623, 2518818, ..., 16645599}con questo .
LegionMammal978,

@ LegionMammal978, il tuo suggerimento ha portato ad un accorciamento del codice di oltre 100 byte. Ora capisco meglio come Mathematica gestisce le basi.
DavidC

@DavidC Inoltre, sembra che alcuni spazi bianchi siano penetrati nel tuo codice golf e io conto 571 byte senza di esso. Inoltre, alcune funzioni possono essere convertite in forma infissa. x[[All,2,1]]può essere sostituito con x[[;;,2,1]]. Flatten[x,1]è equivalente a Join@@xed Flatten[#,1]&/@xè equivalente a Join@@@x. Ci sono alcune altre ottimizzazioni minori che possono essere fatte. Il codice a 551 byte dopo questi campi da golf.
LegionMammal978,

Consigli utili e lettura attenta. Grazie.
DavidC

Hai tentato di ridurre al minimo il numero di punti di campionamento spostandoli?
Sparr,

4

C #, 1040 1027 byte

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

Fondamentalmente ho trovato alcuni punti di riferimento specifici per controllare il giallo / nero per determinare l'identità di ciascun personaggio.


Sei sicuro che non ci sia un eccesso delle immagini fornite e che riconoscerà le targhe in cui i caratteri sono spostati, ad esempio, di 10 pixel?
YetiCGN,

@YetiCGN dovrebbe riconoscerlo fintanto che la dimensione è la stessa e sono nella stessa posizione verticale. Ho provato con tutti gli esempi forniti e funziona; per favore fatemi sapere se ne trovate uno dove non lo è
Nick Mertin,

Non voglio installare Visual Studio solo per questo, ma puoi provare i.imgur.com/i8jkCJu.png che è un po 'più piccolo. Penso che sia sicuro presumere che tutti gli invii saranno immagini da quel particolare sito web. Inizialmente il mio commento è stato più sulla falsariga di "e se fosse una vera scansione di lastre?" / "cosa succede se qualcun altro sposta tutti i caratteri verticalmente di 10 pixel per creare un piatto?"
YetiCGN,

@YetiCGN non dovresti avere bisogno di compilare VisualStudio, solocsc.exe main.cs /r:System.Drawing.dll
VisualMelon

2

PHP - 1741 1674 1143 byte

È stato inizialmente impostato imparando i profili dei personaggi dai primi esempi, che hanno quindi riassunto ogni personaggio in sei numeri. Ne ho scelti sei perché originariamente ne avevo cinque e non funzionava come avrei voluto, ma sei sembra funzionare molto meglio. Gran parte dell'ottimizzazione comporta la compressione di questi profili in conteggi di byte sempre più piccoli.

Il primo e il secondo profilo *lhdfdne |nnmmkksono in realtà il blob blu con "GB" in basso *, e il bordo destro |, che stiamo ignorando. È più sicuro includerli in modo che il blob e il bordo destro abbiano qualcosa a cui corrispondere.

Dovrebbe gestire qualsiasi formato di immagine, qualsiasi ridimensionamento ragionevole a condizione che le proporzioni non cambino troppo, nessun colore scuro su chiaro e persino un po 'di rumore e ombreggiatura!

Ha bisogno del bordo, almeno nella parte superiore e inferiore, che fa parte del profilo.

<?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,'|*');}

Salva come ocr.php, quindi esegui dalla riga di comando:

$ 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

Per coloro che sono interessati, ecco il codice di apprendimento. Salva come learn.phped esegui dalla riga di comando, senza argomenti.

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

?>

Dovresti includere gli spazi nell'output
Beta Decay

3
Questo non è nelle specifiche sotto I seguenti sono tutti i caratteri che il tuo programma deve riconoscere , solo i caratteri AH, JN, PZ e 0-9. Nessuna menzione di spazi.

Oh, va bene, il tuo va bene allora
Decadimento Beta

"Il primo e il secondo profilo [...] sono in realtà il BLOB BLU con" GB "in basso e il bordo destro, che stiamo ignorando." Quindi perché li hai inclusi nel codice, specialmente se la chiave di matrice con una stringa vuota viene sovrascritta? Inoltre: è consentito utilizzare una sintassi aperta breve per il golf del codice! :-)
YetiCGN

@YetiCGN - se non lo sono, il codice tenterà di abbinarli a qualcos'altro! Non mi rendevo conto che fossero stati sovrascritti, fortunatamente il codice funzionava ancora. Revisione. Potresti essere in grado di adattare alcune delle mie modifiche alla tua risposta.

0

PHP, 971 970 byte

Disegna pesantemente su Yimin Rong 's risposta , che può essere seriamente giocato a golf a lungo, specialmente gli indici degli array, e messo in un Phar con compressione gzip.

Scarica il phar

Questa è la mia versione base migliorata a 1557 1535 byte, salvata semplicemente con il nome file "o":

<?$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;}

miglioramenti:

1a tappa

  • Gli indici di array numerici hanno rimosso e riordinato l'array, gli indici di stringa come costanti implicite

2a tappa

  • Sostituito intvalcon ~~(salva 8 byte, due occorrenze)
  • inizializzazione for-loop rimossa se non necessaria
  • file_get_contents($u)sostituito con join('',file($u))(salva 5 byte)
  • e pochi altri

Sfortunatamente, tutti i miglioramenti del secondo stadio si traducono solo in 1 byte di codice gzip in meno. :-D

E questo codice è stato usato per creare il Phar:

<?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();');

Prova con php ocr.phar http://i.imgur.com/i8jkCJu.pngo qualsiasi altra immagine del test case.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.