Plaka Golf: Tanıma


20

Ayrıca bakınız: Ayrıştırma

Giriş

Hız kameralarını programlayan bir hükümet programlama ekibi üzerinde çalışıyorsunuz. Ancak, hız hesaplayıcısını programlayan insan grubu çok fazla yer kapladı, bu yüzden plaka tanıma yazılımını mümkün olduğunca küçük hale getirmelisiniz.

Meydan okuma

Bir plaka görüntüsü verildiğinde, metni plaka üzerinde döndürün.

Sayı plakaları

Programınızın tanıması gereken tüm karakterler aşağıdadır:

ABCDEFG

H1JKLMN0

PQRSTUVW

XYZ01234

56789

Not

İngiliz sayı plakalarında, I (i) ve 1 (bir) karakterleri aynı ve O (o) ve 0 (sıfır) karakterleri aynıdır. Bu nedenle, her zaman karakterlerin sayılar olduğunu varsayalım. Yani aşağıdaki plaka 10'dur (bir sıfır):

Örnekler

C0D3 GLF

B3T4 DCY

M1NUS 15

YET1CGN

Diğer kurallar

İnternet erişimi ve OCR kitaplıklarına ve işlevlerine izin verilmez.

Numara plakaları her zaman yukarıda gösterilenlerle aynı görünecektir. Tüm sayı plakaları kabaca aynı boyutta olacaktır (kırpma yönteminden dolayı bazı yanlışlıklar olacaktır).

Herhangi bir sayı plakasının kayıpsız PNG sürümlerine ihtiyacınız varsa, bunları size sağlayacağım.

puanlama

Bayt cinsinden en kısa program kazanır.

Tüm plakalar bu sitedeki arama çubuğunun ekran görüntüleri


8
Hız tuzağından geçmemi hatırlat. (Numara
Neil

3
Evet, bu sorunun başlığı oldukça yanlış. "OCR İngiliz plakasına" ne dersiniz ?
Lynn

3
@Neil İngiltere plakamın hem O hem de 0 değeri var ve aynı görünüyorlar. Hangisinin doğru yorum olduğunu belirlemek için elbette kurallar vardır, ancak bu başka bir zorluk olacaktır.
Level River St

2
Karakterlerin sabit bir genişlik olmaması çok kötü. Bu çok kısa kod olasılıkları sağlayabilir.
GuitarPicker

1
@YetiCGN İsteğin benim emrimdir;)
Beta

Yanıtlar:


11

C, 409 bayt (ve herkes kadar şaşırdım)

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

Girdi olarak alır: görüntünün genişliği ( w) ve yüksekliği ( h), ardından bir dizi chars (d ) . Diğer tüm fonksiyon parametreleri kılık değiştirmiş değişken bildirimlerdir. Yeşil kanal dışındaki her şeyi yok sayar ve ilk geçiş olarak 32 eşik değerini uygular.

Çoğunlukla @ DavidC'nin yöntemiyle aynıdır, ancak bu, her örnek kutusunun en az% 35'inin doldurulduğunu kontrol eder. Umarım bu, değişiklikleri ölçeklendirmeyi daha sağlam hale getirir, ancak kim bilir.

En iyi güvenilirlik için hangi yeniden örnekleme boyutunun ve kapsama yüzdesinin kullanılacağını bulmak için bir kaba kuvvet yöntemi kullandım (yani, bir karakterin birden fazla yorumu olan en az sayıda örneği). % 35 kapsama alanına sahip 4x5 ızgarasının en iyisi olduğu ortaya çıktı. Daha sonra karakter verilerini kısa bir dizeye paketlemek için en iyi bit düzenlemesini ve modulo değerini hesaplamak için ikinci bir kaba kuvvet yöntemi kullandım - sol üstteki düşük bit, x sonra y'de artarak son değer% 101 döndü en iyisi, bu arama tablosunu vererek:

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

7'nin çıkarılması, ilk harflerin çıkarılabileceği ve son 2'nin fazladan bir iş yapmadan çıkarılabileceği anlamına gelir. Bu kaldırma, bazı geçersiz girişlerin geçersiz bir bellek okumasına neden olabileceği anlamına gelir, bu nedenle belirli görüntülerde segfault olabilir.

Kullanımı:

Görüntüleri içine almak için libpng kullanarak bir paket yazdım. Ayrıca, dosya adına rağmen, söz konusu görüntülerin aslında jpegs (!) Olduğu ortaya çıkıyor, bu yüzden bunları önce png olarak manuel olarak dışa aktarmanız gerekecek.

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

Yıkmak

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

C ile Python ve Mathemetica'yı yenmek için +1 . Oooollllld okulu, yo.
Robert Fraser

C ile
KAZANMA

12

Mathematica 1170 1270 10961059505285755755 525498 bayt

En son sürüm, plaka ayrıştırılmadan önce "kırpılması" gerek kalmadan 27 bayt kaydeder. Sondan bir önceki sürüm, orijinal 24 örnek noktasının yalnızca 10'unu kullanarak 26 bayt kaydetti.

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

LegionMammal978'in baz 10 numaralarının uzun listesini tek bir baz 36 numarası olarak paketleme fikri ile kaydedilen 122 bayt. Nihai koddan 20 bayt daha ayırdı.

528'den 570 bayta atlamak, iade edilen harflerin sırasının, plaka üzerindeki harflerin sırasına karşılık gelmesini sağlamak için ek koddan kaynaklandı. Her harf için centroid, x boyunca harflerin göreli konumlarını gösteren x-koordinatını içerir.


Açık Kod

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

genel bakış

Temel fikir, giriş görüntüsünden sistematik bir piksel örneklemesinin iyi niyetli görüntülerde aynı konumdaki piksellerle eşleşip eşleşmediğini kontrol etmektir. Kodun çoğu, her karakter için bit imzalarından oluşur,

Diyagram, "J", "P", "Q" ve "R" harflerinden örneklenen pikselleri gösterir.

jpqr

Piksel değerleri matrisler olarak temsil edilebilir. Koyu, koyu renk 1siyah hücrelere karşılık gelir. 0Beyaz hücrelere bireyin karşılık gelmektedir.

jjjj

Bunlar JPQ R için şifre çözme değiştirme kurallarıdı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"

"0" kuralının neden olduğunu anlamak mümkün olmalıdır:

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

ve böylece "Q" harfinden ayırt edilebilir.


Aşağıda son versiyonda kullanılan 10 nokta gösterilmektedir. Bu noktalar tüm karakterleri tanımlamak için yeterlidir.

indirimli


Fonksiyonlar ne yapar

plateCrop[img]çerçeveyi ve sol kenarı plakadan kaldırır, arka planı beyaz yapar. Görüntü işlevlerini, 100 ile 120 piksel yüksekliğinde olası harfleri seçerek bu işlevi son sürümden kaldırabildim.

platecrop


isolateLetters[img] kırpılan görüntüden tek tek harfleri kaldırır.

Kırpılan görüntünün, çıktının plateCropnereye girdi olarak gösterildiğini göstererek nasıl çalıştığını gösterebiliriz isolateLetters. Çıktı tek tek karakterlerin listesidir .

harfler


Coordinatespiksel rengini kontrol etmek için 24 eşit dağıtılmış konumdur. Koordinatlar ilk şekildedakilere karşılık gelir.

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 pikselleri ikiliye dönüştürür.

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

codesher karakterin imzasıdır. Ondalık değerler, siyah (0) ve Beyaz (1) hücreler için ikili kodun kısaltmalarıdır. Golflü versiyonda, taban 36 kullanılır.

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

(* decryptRulesimzaları ilgili karakterleriyle değiştirmek içindir *)

decryptRules=Rule@@@codes;

f bir plaka görüntüsünü alıp bir harf döndüren işlevdir.

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

tabaklar

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

Her karakter için 24 bitin tümünü (beyaz veya siyah) temsil eden tek bir ondalık sayı kullanılarak kod kısaltılır. Örneğin, mektup "J" Aşağıdaki yedek kuralını kullanır: 1118623 -> "J".

1118623 karşılık gelir

IntegerDigits[1118623 , 2, 24]

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

olarak yeniden paketlenebilir

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

ki bu sadece yukarıda gördüğümüz "J" matrisidir.

%//MatrixForm

matris

Bir başka tasarruf da harfleri "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"listelemek yerine alfabeyi temsil etmektir .

Son olarak, uzun versiyondaki tüm fonksiyonlar, ayrı olarak tanımlanmak yerine hfonksiyona entegre edildi f.


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 SE berbat gibi görünüyor; değiştirmeyi deneyin {1118623, 2518818, ..., 16645599}ile bu .
LegionMammal978

@ LegionMammal978, öneriniz kodun 100 bayttan fazla kısalmasına neden oldu. Şimdi Mathematica'nın üsleri nasıl ele aldığını daha iyi anlıyorum.
DavidC

@DavidC Ayrıca, bazı boşluklar golf kodunuza gizlenmiş gibi görünüyor ve ben onsuz 571 bayt sayıyorum. Ayrıca, bazı işlevler infix formuna dönüştürülebilir. x[[All,2,1]]ile değiştirilebilir x[[;;,2,1]]. Flatten[x,1]eşittir Join@@xve Flatten[#,1]&/@xeşittir Join@@@x. Yapılabilecek birkaç küçük optimizasyon daha var. Bu golflerden sonra 551 baytlık kod.
LegionMammal978

Güzel ipuçları ve dikkatli okuma. Teşekkürler.
DavidC

Örnekleme noktalarının sayısını hareket ettirerek en aza indirmeye çalıştınız mı?
Sparr

4

C #, 1040 1027 bayt

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

Temelde her karakterin kimliğini belirlemek için sarı / siyahı kontrol etmek için bazı referans noktaları buldum.


Sağlanan görüntülerde herhangi bir fazlalık olmadığından ve karakterlerin örneğin 10 piksel kaydırıldığı plakaları tanıyacağından emin misiniz?
YetiCGN

@YetiCGN, boyut aynı olduğu ve aynı dikey konumda olduğu sürece onu tanımalıdır. Verilen tüm örneklerle denedim ve işe yarıyor; lütfen bilmediğiniz bir yer bulursanız bana bildirin
Nick Mertin

Visual Studio'yu sadece bunun için yüklemek istemiyorum, ancak boyutu biraz daha küçük olan i.imgur.com/i8jkCJu.png'yi deneyebilirsiniz . Tüm gönderimlerin söz konusu web sitesinden resimler olacağını varsaymanın güvenli olduğunu düşünüyorum. Başlangıçta benim yorumum daha çok "gerçek bir plaka taramasıysa?" / "bir başkası plaka yapmak için tüm karakterleri dikey olarak 10 piksel kaydırdıysa?"
YetiCGN

@YetiCGN derlemek için VisualStudio gerekmez, sadececsc.exe main.cs /r:System.Drawing.dll
VisualMelon

2

PHP - 1741 1674 1143 bayt

İlk olarak, ilk birkaç örnekten karakterlerin profillerini öğrenerek kuruldu, daha sonra her karakteri altı sayıya özetledi. Altı tane seçtim çünkü başlangıçta beş tane vardı ve istediğim kadar iyi çalışmadı, ama altı daha iyi çalışıyor gibi görünüyor. Optimizasyonun çoğu, bu profillerin daha küçük ve daha küçük bayt sayılarına sıkıştırılmasını içerir.

Birinci ve ikinci profil *lhdfdnve |nnmmkkaslında altta "GB" olan mavi damla *ve |görmezden geldiğimiz sağ sınır . Onları dahil etmek daha güvenlidir, böylece damla ve sağ sınırın eşleşecek bir şeyleri vardır.

Görüntü biçimini, en boy oranının çok fazla değişmemesi, açık renkte koyu renk ve hatta biraz gürültü ve gölgeleme olması koşuluyla makul herhangi bir ölçeklendirme yapmalıdır!

En azından üstte ve altta, bu profilin bir parçası olan sınıra ihtiyacı var.

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

Farklı kaydet ocr.php, ardından komut satırından çalıştırın:

$ 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

İlgilenenler için, işte öğrenme kodu. Farklı kaydet learn.phpve komut satırından çalıştır, argüman yok.

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

?>

Çıktıdaki boşlukları dahil etmelisiniz
Beta Çürümesi

3
Bu, aşağıdaki programınızın tanıması gereken karakterlerin tümü , sadece AH, JN, PZ ve 0-9 karakterleri altında belirtilen özelliklerde değildir . Boşluklardan bahsedilmiyor.

Oh, tamam, seninki o zaman iyi
Beta Çürüğü

"Birinci ve ikinci profil [...] aslında altta" GB "olan mavi damla ve görmezden geldiğimiz sağ kenarlık." O zaman neden kodu koydunuz, özellikle de boş bir dizeye sahip dizi anahtarının üzerine yazıldıysa? Artı: Kod golf için kısa açık sözdizimi kullanılmasına izin verilir! :-)
YetiCGN

@YetiCGN - eğer değilse, kod onları başka bir şeyle eşleştirmeye çalışır! Kodun hala çalıştığı için şanslı olduklarının farkında değildim. Ücret Değişikliği. Değişikliklerimden bazılarını cevabınıza uyarlayabilirsiniz.

0

PHP, 971670 bayt

Üzerine ağır çizer Yimin Rong 'ın cevabı ciddiye özellikle dizi indeksleri aşağı golfed ve gzip sıkıştırma ile bir Phar içine konabilir.

Phar'ı indirin

Bu benim 1557 1535 bayt, sadece "o" dosya adı altında kaydedilmiş benim gelişmiş temel versiyonu :

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

İyileştirmeler:

1. aşama

  • Sayısal dizi dizinleri kaldırıldı ve diziyi yeniden sıraladı, dize dizinleri örtülü sabitler olarak

2. aşama

  • Değiştirilen intvalile ~~(tasarruf 8 bayt, iki görünüm)
  • for-loop başlatma gereksiz yerlerde kaldırıldı
  • file_get_contents($u)ile değiştirildi join('',file($u))(5 bayt kaydeder)
  • ve birkaç tane daha

Ne yazık ki, tüm ikinci aşama iyileştirmeleri sadece 1 bayt daha az gzip edilmiş koda dönüşür. :-D

Ve bu kod Phar'ı oluşturmak için kullanıldı:

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

Test php ocr.phar http://i.imgur.com/i8jkCJu.pngörneği görüntüleri ile veya başka herhangi biriyle test edin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.