Number Number Golf: Công nhận


20

Xem thêm: Phân tích cú pháp

Giới thiệu

Bạn đang làm việc trong một nhóm lập trình của chính phủ, người đã lập trình máy ảnh tốc độ. Tuy nhiên, nhóm người đã lập trình máy tính tốc độ đã chiếm quá nhiều không gian, vì vậy bạn phải làm cho phần mềm nhận dạng biển số càng nhỏ càng tốt.

Thử thách

Cho một hình ảnh của một biển số, trả lại văn bản trên tấm.

Biển số

Sau đây là tất cả các ký tự mà chương trình của bạn phải nhận ra:

ABCDEFG

H1JKLMN0

PQRSTUVW

XYZ01234

56789

chú thích

Trên biển số Anh, các ký tự cho I (i) và 1 (một) giống nhau và các ký tự cho O (o) và 0 (không) giống nhau. Vì lý do đó, luôn luôn cho rằng các ký tự là số. Tức là biển số sau là 10 (một số không):

Ví dụ

C0D3 GLF

B3T4 DCY

M1NUS 15

YET1CGN

Các quy tắc khác

Truy cập Internet và các thư viện và chức năng OCR không được phép.

Các biển số sẽ luôn trông giống hệt với các biển số được hiển thị ở trên. Tất cả các biển số sẽ có kích thước gần như nhau (sẽ có một số điểm không chính xác do phương pháp cắt xén).

Nếu bạn yêu cầu phiên bản PNG không mất dữ liệu của bất kỳ biển số nào, tôi sẽ cung cấp chúng cho bạn.

Chấm điểm

Chương trình ngắn nhất tính bằng byte thắng.

Tất cả các biển số là ảnh chụp màn hình của thanh tìm kiếm tại trang web này


8
Nhắc tôi lái xe qua bẫy tốc độ của bạn. (Biển số của tôi có chữ O.)
Neil

3
Có, tiêu đề của câu hỏi này là không chính xác. Làm thế nào về "OCR một tấm giấy phép Anh" ?
Lynn

3
@Neil Biển số Anh của tôi có cả chữ O và số 0 và chúng trông giống hệt nhau. Tất nhiên có các quy tắc để xác định đó là cách giải thích chính xác, nhưng đó sẽ là một thách thức hoàn toàn khác.
Cấp sông St

2
Thật tệ khi các ký tự không có chiều rộng cố định. Điều đó có thể làm cho một số khả năng mã rất ngắn.
GuitarPicker

1
@YetiCGN Mong muốn của bạn là mệnh lệnh của tôi;)
Beta Decay

Câu trả lời:


11

C, 409 byte (và tôi cũng ngạc nhiên như bất kỳ ai)

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

Lấy làm đầu vào: chiều rộng ( w) và chiều cao ( h) của hình ảnh, theo sau là dữ liệu RGB được đóng gói dưới dạng một mảng chars ( d). Tất cả các tham số chức năng khác là khai báo biến trong ngụy trang. Bỏ qua tất cả mọi thứ trừ kênh màu xanh lá cây và áp dụng ngưỡng 32 là vượt qua ban đầu.

Chủ yếu giống như phương pháp của @ DavidC, ngoại trừ kiểm tra này rằng ít nhất 35% của mỗi hộp mẫu được điền. Hy vọng rằng điều đó làm cho nó mạnh mẽ hơn để thay đổi quy mô, nhưng ai biết được.

Tôi đã sử dụng một phương pháp brute-force để tìm ra kích thước lấy mẫu và tỷ lệ phần trăm phạm vi sử dụng để có độ tin cậy tốt nhất (nghĩa là ít trường hợp một nhân vật có nhiều cách hiểu). Hóa ra lưới 4x5 với độ bao phủ 35% là tốt nhất. Sau đó, tôi đã sử dụng phương pháp brute-force thứ hai để tính toán sắp xếp bit và giá trị modulo tốt nhất để đóng gói dữ liệu ký tự thành một chuỗi ngắn - bit thấp ở phía trên bên trái, tăng theo x rồi y, với giá trị cuối cùng% 101 tốt nhất, đưa ra bảng tra cứu này:

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

Trừ đi 7 có nghĩa là có thể loại bỏ các chữ cái đầu tiên và 2 cái cuối cùng có thể được loại bỏ mà không cần thêm bất kỳ công việc nào. Việc loại bỏ này có nghĩa là một số đầu vào không hợp lệ có thể gây ra đọc bộ nhớ không hợp lệ, do đó nó có thể tách biệt trên các hình ảnh cụ thể.

Sử dụng:

Để có được hình ảnh vào nó, tôi đã viết một trình bao bọc bằng libpng. Ngoài ra, hóa ra mặc dù có tên tệp, nhưng hình ảnh trong câu hỏi thực sự là jpeg (!), Vì vậy trước tiên bạn cần xuất chúng dưới dạng pngs.

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

Phá vỡ

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 để đánh bại Python và Mathemetica với C quái đản . Trường Oooollllld, yo.
Robert Fraser

+1 cho CHIẾN THẮNG với C, giống như, không bao giờ nghĩ điều đó có thể xảy ra, huh
HyperNeutrino

12

Toán học 1170 1270 1096 1059 650 528 570 551 525 498 byte

Phiên bản mới nhất tiết kiệm 27 byte bằng cách không yêu cầu tấm phải được "cắt" trước khi phân tích cú pháp. Phiên bản áp chót đã lưu 26 ​​byte bằng cách chỉ sử dụng 10 trong số 24 điểm mẫu ban đầu.

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 được lưu thông qua ý tưởng của LegionMammal978 về việc đóng gói danh sách dài gồm 10 số cơ bản dưới dạng một số, 36 số cơ bản. Anh ta giảm 20 byte cho mã cuối cùng.

Việc nhảy từ 528 đến 570 byte là do mã bổ sung để đảm bảo rằng thứ tự của các chữ cái được trả về tương ứng với thứ tự của các chữ cái trên biển số xe. Trọng tâm cho mỗi chữ cái chứa tọa độ x, cho thấy vị trí tương đối của các chữ cái dọc theo x.


Mã bị đánh cắp

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

Tổng quan

Ý tưởng cơ bản là kiểm tra xem một mẫu pixel có hệ thống từ hình ảnh đầu vào có khớp với pixel từ cùng một vị trí trên hình ảnh bonafide hay không. Phần lớn mã bao gồm các chữ ký bit cho mỗi ký tự,

Biểu đồ hiển thị các pixel được lấy mẫu từ các chữ cái "J", "P", "Q" và "R".

jpqr

Các giá trị pixel có thể được biểu diễn dưới dạng ma trận. Màu tối, đậm 1tương ứng với các ô màu đen. Các 0'tương ứng với các tế bào trắng.

jjjj

Đây là các quy tắc thay thế giải mã cho 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"

Có thể hiểu tại sao quy tắc cho "0" là:

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

và do đó phân biệt với chữ "Q".


Sau đây cho thấy 10 điểm được sử dụng trong phiên bản cuối cùng. Những điểm này là đủ để xác định tất cả các nhân vật.

giảm


Các chức năng làm gì

plateCrop[img]loại bỏ khung và cạnh trái từ tấm, làm cho nền trắng. Tôi đã có thể loại bỏ chức năng này khỏi phiên bản cuối cùng bằng cách chọn các thành phần hình ảnh, các chữ cái có thể cao từ 100 đến 120 pixel.

cao nguyên


isolateLetters[img] loại bỏ các chữ cái riêng lẻ từ hình ảnh cắt.

Chúng ta có thể hiển thị cách thức hoạt động của nó bằng cách hiển thị hình ảnh được cắt, đầu ra từ plateCropđâu đi làm đầu vào cho isolateLetters. Đầu ra là một danh sách các ký tự riêng lẻ.

bức thư


Coordinateslà 24 vị trí phân bố đồng đều để kiểm tra màu pixel. Các tọa độ tương ứng với những người trong hình đầu tiên.

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 chuyển đổi các pixel thành nhị phân.

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

codeslà chữ ký cho mỗi nhân vật. Các giá trị thập phân là chữ viết tắt của mã nhị phân cho các ô đen (0) và Trắng (1). Trong phiên bản golf, cơ sở 36 được sử dụng.

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

(* decryptRuleslà để thay thế chữ ký bằng ký tự tương ứng *)

decryptRules=Rule@@@codes;

f là chức năng lấy hình ảnh của biển số xe và trả về một chữ cái.

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

tấm

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


Chơi gôn

Mã được rút ngắn bằng cách sử dụng một số thập phân duy nhất để thể hiện tất cả 24 bit (trắng hoặc đen) cho mỗi ký tự. Ví dụ: chữ "J" sử dụng quy tắc thay thế sau : 1118623 -> "J".

1118623 tương ứng với

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}

có thể được đóng gói lại như

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

đó đơn giản là ma trận cho "J" mà chúng ta đã thấy ở trên.

%//MatrixForm

ma trận

Một khoản tiết kiệm khác đến từ việc đại diện cho bảng chữ cái "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ"chứ không phải là một danh sách các chữ cái.

Cuối cùng, tất cả các chức năng từ phiên bản dài, ngoại trừ h, được tích hợp vào chức năng fthay vì được xác định riêng biệt.


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 Có vẻ như SE đã làm hỏng nó; hãy thử thay thế {1118623, 2518818, ..., 16645599}bằng này .
LegionMammal978

@ LegionMammal978, đề xuất của bạn đã dẫn đến việc rút ngắn mã hơn 100 byte. Bây giờ tôi hiểu rõ hơn về cách Mathicala xử lý các căn cứ.
DavidC

@DavidC Ngoài ra, có vẻ như một số khoảng trắng lẻn vào mã golf của bạn và tôi đếm 571 byte mà không có nó. Ngoài ra, một số chức năng có thể được chuyển đổi thành dạng infix. x[[All,2,1]]có thể được thay thế bằng x[[;;,2,1]]. Flatten[x,1]tương đương với Join@@x, và Flatten[#,1]&/@xtương đương với Join@@@x. Có một vài tối ưu hóa nhỏ khác có thể được thực hiện. Mã 551 byte sau những golf này.
LegionMammal978

Mẹo hay và đọc cẩn thận. Cảm ơn.
DavidC

Bạn đã cố gắng giảm thiểu số lượng điểm lấy mẫu bằng cách di chuyển chúng xung quanh?
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;}}}

Ung dung:

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

Về cơ bản tôi tìm thấy một số điểm tham chiếu cụ thể để kiểm tra màu vàng / đen để xác định danh tính của từng nhân vật.


Bạn có chắc chắn không có hình ảnh quá phù hợp với hình ảnh được cung cấp và nó sẽ nhận ra biển số xe trong đó các ký tự được dịch chuyển 10 pixel?
YetiCGN

@YetiCGN cần nhận ra nó miễn là kích thước giống nhau và chúng ở cùng một vị trí thẳng đứng. Tôi đã thử với tất cả các ví dụ được cung cấp, và nó hoạt động; xin vui lòng cho tôi biết nếu bạn tìm thấy một nơi mà nó không
Nick Mertin

Tôi không muốn cài đặt Visual Studio chỉ cho việc này, nhưng bạn có thể thử i.imgur.com/i8jkCJu.png có kích thước nhỏ hơn một chút. Tôi nghĩ thật an toàn khi cho rằng tất cả các bài nộp sẽ là hình ảnh từ trang web cụ thể đó. Ban đầu bình luận của tôi có nhiều dòng chữ "nếu đó là một bản quét thực sự thì sao?" / "điều gì xảy ra nếu ai đó thay đổi tất cả các ký tự theo chiều dọc 10 pixel để tạo thành một tấm?"
YetiCGN

@YetiCGN bạn không cần phải biên dịch VisualStudio, chỉ cầncsc.exe main.cs /r:System.Drawing.dll
VisualMelon

2

PHP - 1741 1674 1143 byte

Nó được thiết lập đầu tiên bằng cách tìm hiểu hồ sơ của các nhân vật từ một vài ví dụ đầu tiên, sau đó tóm tắt mỗi nhân vật thành sáu số. Tôi đã chọn sáu vì ban đầu tôi có năm, và nó không hoạt động tốt như tôi muốn, nhưng sáu dường như hoạt động tốt hơn nhiều. Phần lớn việc tối ưu hóa liên quan đến việc ép các cấu hình này thành số byte nhỏ hơn và nhỏ hơn.

Hồ sơ thứ nhất và thứ hai *lhdfdn|nnmmkkthực sự là các đốm màu xanh với "GB" ở dưới cùng *và đường viền bên phải |, mà chúng ta đang bỏ qua. Sẽ an toàn hơn nếu bao gồm chúng để blob và đường viền phải có thứ gì đó phù hợp.

Nên xử lý bất kỳ định dạng hình ảnh nào, bất kỳ tỷ lệ hợp lý nào được cung cấp tỷ lệ khung hình sẽ không thay đổi quá nhiều, bất kỳ màu tối nào trên màu sáng và thậm chí là một chút nhiễu và bóng!

Nó không cần đường viền, ít nhất là ở trên cùng và dưới cùng, đó là một phần của hồ sơ.

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

Lưu dưới dạng ocr.php, sau đó chạy từ dòng lệnh:

$ 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

Đối với những người quan tâm, đây là mã học tập. Lưu dưới dạng learn.phpvà chạy từ dòng lệnh, không có đối số.

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

?>

Bạn nên bao gồm các khoảng trắng trong đầu ra
Beta Decay

3
Điều đó không có trong thông số kỹ thuật dưới đây Dưới đây là tất cả các ký tự mà chương trình của bạn phải nhận ra , chỉ các ký tự AH, JN, PZ và 0-9. Không đề cập đến không gian.

Oh, được rồi, bạn là tốt rồi
Beta Decay

"Hồ sơ thứ nhất và thứ hai [...] thực sự là các đốm màu xanh với" GB "ở dưới cùng và đường viền bên phải, mà chúng tôi đang bỏ qua." Vậy thì tại sao bạn lại đưa chúng vào mã, đặc biệt nếu khóa mảng có chuỗi trống bị ghi đè? Thêm vào đó, nó được phép sử dụng cú pháp mở ngắn cho mã golf! :-)
YetiCGN

@YetiCGN - nếu họ không có thì mã sẽ cố khớp chúng với thứ khác! Tôi đã không nhận ra họ đã bị ghi đè, may mắn là mã vẫn hoạt động. Sửa đổi. Bạn có thể điều chỉnh một số thay đổi của tôi cho câu trả lời của bạn.

0

PHP, 971 970 byte

Dựa vào câu trả lời của Yimin Rong , có thể bị đánh golf nghiêm trọng, đặc biệt là các chỉ số mảng và đưa vào Phar với nén gzip.

Tải xuống phar

Đây là phiên bản cơ sở cải tiến của tôi ở mức 1557 1535 byte, được lưu đơn giản dưới tên tệp "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;}

Cải tiến:

Giai đoạn 1

  • Các chỉ mục mảng số được loại bỏ và sắp xếp lại các mảng, các chỉ mục chuỗi như các hằng số ẩn

Giai đoạn 2

  • Thay thế intvalbằng ~~(lưu 8 byte, hai lần xuất hiện)
  • khởi tạo for-loop bị loại bỏ khi không cần thiết
  • file_get_contents($u)được thay thế bằng join('',file($u))(tiết kiệm 5 byte)
  • và một vài người khác

Thật không may, tất cả các cải tiến ở giai đoạn thứ hai chỉ chuyển thành mã được nén ít hơn 1 byte. : -D

Và mã này đã được sử dụng để tạo 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();');

Kiểm tra với php ocr.phar http://i.imgur.com/i8jkCJu.pnghoặc bất kỳ hình ảnh trường hợp thử nghiệm khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.