Mathematica 1170 1270 1096 1059 650 528 570 551 525 498 bajtów
Najnowsza wersja pozwala zaoszczędzić 27 bajtów, ponieważ nie wymaga „przycinania” tablicy przed parsowaniem. Przedostatnia wersja zaoszczędziła 26 bajtów, wykorzystując tylko 10 oryginalnych 24 punktów próbnych.
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 bajty zaoszczędzone dzięki pomysłowi LegionMammal978 spakowania długiej listy liczb podstawowych 10 jako pojedynczej liczby podstawowej 36. Oddzielił kolejne 20 bajtów od końcowego kodu.
Skok z 528 do 570 bajtów wynikał z dodatkowego kodu, aby upewnić się, że kolejność zwracanych liter odpowiada kolejności liter na tablicy rejestracyjnej. Środek ciężkości każdej litery zawiera współrzędną x, która ujawnia względne położenie liter wzdłuż x.
Kod niepoznany
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
Przegląd
Podstawową ideą jest sprawdzenie, czy systematyczne próbkowanie pikseli z obrazu wejściowego jest zgodne z pikselami z tego samego miejsca na obrazach bonafide. Znaczna część kodu składa się z sygnatur bitowych dla każdego znaku,
Schemat pokazuje piksele próbkowane z liter „J”, „P”, „Q” i „R”.
Wartości pikseli mogą być reprezentowane jako macierze. Ciemne, pogrubione 1
odpowiadają czarnym komórkom. Te 0
odpowiadają białym komórkom.
Są to zasady zastępowania odszyfrowywania 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”
Powinno być możliwe zrozumienie, dlaczego reguła dla „0” to:
{15, 9, 9, 9, 9, 15} -> „0”
i dlatego można je odróżnić od litery „Q”.
Poniżej przedstawiono 10 punktów wykorzystanych w ostatecznej wersji. Punkty te są wystarczające do zidentyfikowania wszystkich znaków.
Jakie funkcje pełnią
plateCrop[img]
usuwa ramkę i lewą krawędź z płyty, sprawia, że tło jest białe. Udało mi się wyeliminować tę funkcję z ostatecznej wersji, wybierając komponenty obrazu, możliwe litery o wysokości od 100 do 120 pikseli.
isolateLetters[img]
usuwa pojedyncze litery z przyciętego obrazu.
Możemy pokazać, jak to działa, pokazując, gdzie przycięty obraz, wyjście z plateCrop
idzie jako dane wejściowe isolateLetters
. Dane wyjściowe to lista pojedynczych znaków.
Coordinates
to 24 równomiernie rozmieszczone pozycje do sprawdzania koloru pikseli. Współrzędne odpowiadają tym na pierwszym rysunku.
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
konwertuje piksele na binarne.
h[img_] :=ArrayReshape[PixelValue[img, #] /. {_, _, _, z_} :> ⌈z⌉ & /@ coordinates, {6, 4}];
codes
są sygnaturą każdego znaku. Wartości dziesiętne są skrótami kodu binarnego dla czarnych (0) i białych (1) komórek. W wersji golfowej stosowana jest podstawa 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"}};
(* decryptRules
służą do zastępowania podpisów ich odpowiednimi postaciami *)
decryptRules=Rule@@@codes;
f
to funkcja, która pobiera obraz tablicy rejestracyjnej i zwraca literę.
f[plate_]:=FromDigits[#,2]&/@#&/@h/@isolate[plateCrop@plate]/.decryptRules;
{„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”}
Grał w golfa
Kod jest skracany za pomocą pojedynczej liczby dziesiętnej reprezentującej wszystkie 24 bity (biały lub czarny) dla każdego znaku. Na przykład litera „J” stosuje następującą regułę zastępczy: 1118623 -> "J"
.
1118623 odpowiada
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}
który można ponownie zapakować jako
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}}
który jest po prostu matrycą „J”, którą widzieliśmy powyżej.
%//MatrixForm
Kolejne oszczędności wynikają z reprezentowania alfabetu "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
zamiast listy liter.
Na koniec wszystkie funkcje z długiej wersji, oprócz h
, zostały zintegrowane z funkcją, f
a nie zdefiniowane osobno.
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"]