Mathematica 1170 1270 1096 1059 650 528 570 551 525 498 байт
Последняя версия экономит 27 байт, не требуя «обрезки» пластины перед ее анализом. Предпоследняя версия сэкономила 26 байт, используя только 10 из 24 исходных точек выборки.
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 байта были сохранены благодаря идее LegionMammal978, заключающейся в упаковке длинного списка из 10 основных чисел в одно целое число из 36 базовых чисел. Он срезал еще 20 байтов с окончательного кода.
Скачок с 528 до 570 байт был вызван дополнительным кодом для обеспечения того, чтобы порядок возвращаемых букв соответствовал порядку букв на номерном знаке. Центроид для каждой буквы содержит X-координату, которая показывает относительное положение букв вдоль X.
Код без правил
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
обзор
Основная идея состоит в том, чтобы проверить, соответствует ли систематическая выборка пикселей из входного изображения пикселям из того же места на достоверных изображениях. Большая часть кода состоит из битовых подписей для каждого символа,
На диаграмме показаны пиксели, которые взяты из букв «J», «P», «Q» и «R».
Значения пикселей могут быть представлены в виде матриц. Темные, жирные 1
соответствуют черным клеткам. Это 0
соответствует белым клеткам.
Это правила замены расшифровки для 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»
Должно быть возможно понять, почему правило для «0» таково:
{15, 9, 9, 9, 9, 15} -> "0"
и, следовательно, отличается от буквы «Q».
Ниже показаны 10 баллов, использованных в финальной версии. Этих точек достаточно для идентификации всех персонажей.
Что делают функции
plateCrop[img]
удаляет рамку и левый край с пластины, делает фон белым. Мне удалось исключить эту функцию из окончательной версии, выбрав компоненты изображения, возможные буквы размером от 100 до 120 пикселей.
isolateLetters[img]
удаляет отдельные буквы из обрезанного изображения.
Мы можем показать, как это работает, показывая, куда обрезанное изображение выводится в plateCrop
качестве входных данных isolateLetters
. Вывод представляет собой список отдельных символов.
Coordinates
24 равномерно распределенных положения для проверки цвета пикселя. Координаты соответствуют указанным на первом рисунке.
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
преобразует пиксели в двоичный файл
h[img_] :=ArrayReshape[PixelValue[img, #] /. {_, _, _, z_} :> ⌈z⌉ & /@ coordinates, {6, 4}];
codes
являются подписью для каждого символа. Десятичные значения - это сокращения двоичного кода для черных (0) и белых (1) ячеек. В версии для гольфа используется основание 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
предназначены для замены подписи соответствующим символом *)
decryptRules=Rule@@@codes;
f
это функция, которая берет изображение номерного знака и возвращает письмо.
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"}
Golfed
Код сокращается за счет использования одного десятичного числа для представления всех 24 битов (белого или черного) для каждого символа. Например, буква «J» использует следующие правила замены: 1118623 -> "J"
.
1118623 соответствует
IntegerDigits[1118623 , 2, 24]
{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1}
который можно упаковать как
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}}
это просто матрица для «J», которую мы видели выше.
%//MatrixForm
Другая экономия "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"
заключается в представлении алфавита, а не в виде списка букв.
Наконец, все функции из длинной версии, кроме h
, были интегрированы в функцию, 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"]