Number Plate Golf: การรับรู้


20

ดูเพิ่มเติมที่: การแยก

บทนำ

คุณกำลังทำงานกับทีมเขียนโปรแกรมของรัฐบาลซึ่งเป็นผู้เขียนโปรแกรมกล้องจับความเร็ว อย่างไรก็ตามกลุ่มคนที่ตั้งโปรแกรมคำนวณความเร็วได้ใช้พื้นที่มากเกินไปดังนั้นคุณต้องทำให้ซอฟต์แวร์จดจำหมายเลขทะเบียนมีขนาดเล็กที่สุดเท่าที่จะทำได้

ท้าทาย

รับภาพของแผ่นป้ายทะเบียนคืนข้อความบนแผ่นป้าย

แผ่นป้ายทะเบียนหมายเลข

ต่อไปนี้เป็นอักขระทั้งหมดที่โปรแกรมของคุณต้องจดจำ:

ABCDEFG

H1JKLMN0

PQRSTUVW

XYZ01234

56789

บันทึก

บนป้ายหมายเลขอังกฤษอักขระสำหรับ I (i) และ 1 (หนึ่ง) จะเหมือนกันและอักขระสำหรับ O (o) และ 0 (ศูนย์) จะเหมือนกัน ด้วยเหตุนี้ให้ถือว่าตัวละครเป็นตัวเลขเสมอ คือหมายเลขทะเบียนต่อไปนี้คือ 10 (หนึ่งศูนย์):

ตัวอย่าง

C0D3 GLF

B3T4 DCY

M1NUS 15

YET1CGN

กฎอื่น ๆ

ไม่อนุญาตให้เข้าถึงอินเทอร์เน็ตและ OCR ไลบรารีและฟังก์ชั่น

ป้ายหมายเลขจะมีลักษณะเหมือนกับที่แสดงไว้ด้านบนเสมอ แผ่นตัวเลขทั้งหมดจะมีขนาดเท่ากัน (จะมีความไม่ถูกต้องเนื่องจากวิธีการครอบตัด)

หากคุณต้องการแผ่นป้ายหมายเลข PNG ในเวอร์ชั่น lossless ใด ๆ ฉันจะส่งให้คุณ

เกณฑ์การให้คะแนน

โปรแกรมที่สั้นที่สุดในหน่วยไบต์ชนะ

แผ่นตัวเลขทั้งหมดเป็นภาพหน้าจอของแถบค้นหาที่เว็บไซต์นี้


8
เตือนฉันให้ขับรถผ่านกับดักความเร็วของคุณ (ป้ายทะเบียนของฉันมีตัวอักษร O. )
Neil

3
ใช่ชื่อคำถามนี้ค่อนข้างไม่ถูกต้อง แล้ว"OCR ป้ายทะเบียนอังกฤษ"ล่ะ
ลินน์

3
@Neil My number UK มีทั้งตัว O และ 0 และพวกมันดูเหมือนกัน มีกฎของหลักสูตรที่กำหนดว่าการตีความที่ถูกต้องคืออะไร แต่นั่นจะเป็นความท้าทายอื่น ๆ
Level River St

2
มันแย่มากที่ตัวละครไม่ใช่ความกว้างคงที่ ที่สามารถทำให้เป็นไปได้สำหรับรหัสสั้น ๆ
GuitarPicker

1
@YetiCGN ความปรารถนาของคุณคือคำสั่งของฉัน;)
เบต้าการสลายตัว

คำตอบ:


11

C, 409 ไบต์ (และฉันก็ประหลาดใจเหมือนทุกคน)

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

ใช้เป็นอินพุต: ความกว้าง ( w) และความสูง ( h) ของภาพตามด้วยข้อมูล RGB ที่บรรจุเป็นอาร์เรย์ของchars ( d) พารามิเตอร์ฟังก์ชั่นอื่น ๆ ทั้งหมดคือการประกาศตัวแปรในการปลอมตัว ละเว้นทุกอย่างยกเว้นช่องสีเขียวและใช้เกณฑ์ 32 เป็นผ่านครั้งแรก

ส่วนใหญ่เป็นเช่นเดียวกับวิธีการของ @ DavidC ยกเว้นว่าจะตรวจสอบว่ามีการเติมเต็มอย่างน้อย 35% ของกล่องตัวอย่างแต่ละกล่อง หวังว่ามันจะทำให้การเปลี่ยนแปลงมีความแข็งแกร่งขึ้น

ฉันใช้วิธีการเดรัจฉานเพื่อหาว่าขนาดการ resampling และเปอร์เซ็นต์การครอบคลุมใดที่จะใช้เพื่อความน่าเชื่อถือที่ดีที่สุด ปรากฎว่าตาราง 4x5 ที่มีความครอบคลุม 35% นั้นดีที่สุด ฉันใช้วิธีการแบบ brute-force ครั้งที่สองในการคำนวณการจัดเรียงบิตที่ดีที่สุดและค่าโมดูโลเพื่อบรรจุข้อมูลอักขระลงในสตริงสั้น - บิตต่ำที่มุมบนซ้ายเพิ่มขึ้นใน x จาก y ด้วยค่าสุดท้าย% 101 หัน ออกมาให้ดีที่สุดโดยให้ตารางการค้นหานี้:

-------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 หมายถึงสามารถลบรายการเริ่มต้นได้และสามารถลบ 2 รายการสุดท้ายได้โดยไม่ต้องทำงานพิเศษใด ๆ การลบนี้หมายความว่าอินพุตที่ไม่ถูกต้องบางอย่างอาจทำให้เกิดการอ่านหน่วยความจำที่ไม่ถูกต้องดังนั้นจึงสามารถแยกไฟล์ในบางภาพได้

การใช้งาน:

เพื่อให้ภาพเป็นมันฉันเขียน wrapper โดยใช้ libpng นอกจากนี้ยังปรากฎว่าแม้ชื่อไฟล์จะเป็นรูปภาพในคำถามจริงๆแล้ว jpegs (!) ดังนั้นคุณจะต้องส่งออกด้วยตนเองเป็น 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;
}

ชำรุด

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 สำหรับการตีงูหลามและ Mathemetica กับเลวC Oooollllld school, yo
Robert Fraser

+1 สำหรับการชนะด้วย C เช่นไม่เคยคิดว่าอาจเกิดขึ้นได้
HyperNeutrino

12

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 bytes ที่บันทึกไว้ผ่านแนวคิดของ 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

ภาพรวม

แนวคิดพื้นฐานคือการตรวจสอบว่าการสุ่มตัวอย่างพิกเซลของระบบจากภาพที่ป้อนเข้านั้นตรงกับพิกเซลจากตำแหน่งเดียวกันบนภาพที่อยู่ใน bonafide หรือไม่ รหัสส่วนใหญ่ประกอบด้วยลายเซ็นบิตสำหรับตัวละครแต่ละตัว

แผนภาพแสดงพิกเซลที่สุ่มตัวอย่างจากตัวอักษร "J", "P", "Q" และ "R"

jpqr

ค่าพิกเซลสามารถแสดงเป็นเมทริกซ์ได้ ความมืดและตัวหนา1สอดคล้องกับเซลล์สีดำ 0สอดคล้อง 's ไปยังเซลล์สีขาว

jjjj

นี่คือกฎการเปลี่ยนการถอดรหัสสำหรับ 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 พิกเซล

platecrop


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) ในเวอร์ชัน golfed จะใช้ฐาน 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", "V", "W"}
{"X", "Y", "Z", "0", "1", "2", "3", "4"}
{"5", "6", "6", "7", "8", "9"}


แข็งแรงเล่นกอล์ฟ

รหัสสั้นลงโดยใช้เลขทศนิยมเดียวเพื่อแทน 24 บิตทั้งหมด (สีขาวหรือสีดำ) สำหรับแต่ละอักขระ ตัวอย่างเช่นตัวอักษร "J" ใช้กฎการแทนที่ต่อไปนี้: 1118623 -> "J".

1118623 สอดคล้องกับ

IntegerDigits[1118623 , 2, 24]

{0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 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"]

@DavidC ดูเหมือนว่า SE จะทำให้เกิดปัญหา ลองเปลี่ยน{1118623, 2518818, ..., 16645599}ด้วยนี้
LegionMammal978

@ LegionMammal978 ข้อเสนอแนะของคุณนำไปสู่การย่อของรหัสโดยกว่า 100 ไบต์ ตอนนี้ฉันเข้าใจดียิ่งขึ้นว่า Mathematica จัดการกับฐานได้อย่างไร
DavidC

@DavidC นอกจากนี้ยังปรากฏขึ้นราวกับว่ามีบางช่องว่างแอบเข้าไปในรหัส golfed ของคุณและฉันนับ 571 ไบต์โดยไม่ได้ นอกจากนี้บางฟังก์ชั่นสามารถแปลงเป็นรูปแบบมัด สามารถถูกแทนที่ด้วยx[[All,2,1]] เทียบเท่ากับและเทียบเท่ากับ มีการเพิ่มประสิทธิภาพย่อยอื่น ๆ อีกเล็กน้อยที่สามารถทำได้ รหัส 551- ไบต์หลังจากกอล์ฟเหล่านี้ x[[;;,2,1]]Flatten[x,1]Join@@xFlatten[#,1]&/@xJoin@@@x
LegionMammal978

คำแนะนำที่ดีและการอ่านอย่างระมัดระวัง ขอบคุณ
DavidC

คุณพยายามลดจำนวนจุดการสุ่มตัวอย่างโดยการเคลื่อนย้ายไปมาหรือไม่?
Sparr

4

C #, 1040 1027 ไบต์

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

โดยทั่วไปฉันพบจุดอ้างอิงเฉพาะเพื่อตรวจสอบสีเหลือง / ดำเพื่อระบุตัวตนของแต่ละตัวอักษร


คุณแน่ใจหรือไม่ว่าไม่มีภาพเกินขนาดที่ให้มาและมันจะจดจำแผ่นป้ายทะเบียนซึ่งตัวอักษรนั้นถูกเลื่อนไปเช่น 10 พิกเซล?
YetiCGN

@ YetiCGN มันควรจะรับรู้ตราบใดที่ขนาดเท่ากันและพวกเขาอยู่ในตำแหน่งแนวตั้งเดียวกัน ฉันได้ลองกับตัวอย่างที่ให้มาทั้งหมดและใช้งานได้ โปรดแจ้งให้เราทราบหากคุณพบที่ที่ไม่เหมาะสม
Nick Mertin

ฉันไม่ต้องการติดตั้ง Visual Studio สำหรับสิ่งนี้ แต่คุณสามารถลองi.imgur.com/i8jkCJu.pngซึ่งมีขนาดเล็กลงเล็กน้อย ฉันคิดว่ามันปลอดภัยที่จะสมมติว่าการส่งทั้งหมดจะเป็นภาพจากเว็บไซต์นั้น ตอนแรกความคิดเห็นของฉันมีมากขึ้นตามสายของ "ถ้ามันเป็นสแกนแผ่นจริงหรือไม่" / "จะเกิดอะไรขึ้นถ้ามีคนเปลี่ยนอักขระทั้งหมดในแนวตั้ง 10 พิกเซลเพื่อสร้างแผ่น"
YetiCGN

@ YetiCGN คุณไม่ควรใช้ VisualStudio ในการรวบรวมเพียงcsc.exe main.cs /r:System.Drawing.dll
VisualMelon

2

PHP - 1741 1674 1143 ไบต์

มันถูกสร้างขึ้นเป็นครั้งแรกโดยการเรียนรู้โปรไฟล์ของตัวละครจากตัวอย่างแรก ๆ จากนั้นจึงสรุปตัวละครแต่ละตัวเป็นตัวเลขหกตัว ฉันเลือกหกเพราะครั้งแรกฉันมีห้าและมันไม่ได้ทำงานที่ดีเท่าที่ฉันต้องการ แต่หกดูเหมือนจะทำงานได้ดีขึ้นมาก การเพิ่มประสิทธิภาพส่วนใหญ่เกี่ยวข้องกับการบีบโปรไฟล์เหล่านี้เป็นจำนวนไบต์ที่เล็กลงและเล็กลง

โปรไฟล์แรกและตัวที่สอง*lhdfdnและ|nnmmkkเป็นหยดสีน้ำเงินที่มี "GB" ที่ด้านล่าง*และขอบด้านขวา|ซึ่งเราไม่สนใจ การรวมไว้ในที่ที่ปลอดภัยกว่านั้นเพื่อให้หยดและขอบด้านขวามีสิ่งที่จะเทียบได้

ควรจัดการกับรูปแบบภาพใด ๆ การปรับขนาดที่เหมาะสมหากอัตราส่วนภาพไม่เปลี่ยนแปลงมากเกินไปความเข้มของแสงและแม้กระทั่งเสียงรบกวนและการแรเงาเล็กน้อย!

มันต้องการเส้นขอบอย่างน้อยที่สุดที่ด้านบนและล่างนั่นคือส่วนหนึ่งของโปรไฟล์

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

บันทึกเป็นocr.phpจากนั้นเรียกใช้จากบรรทัดคำสั่ง:

$ 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

สำหรับผู้ที่สนใจนี่คือรหัสการเรียนรู้ บันทึกเป็นlearn.phpและเรียกใช้จากบรรทัดคำสั่งไม่มีข้อโต้แย้ง

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

?>

คุณควรรวมช่องว่างในผลลัพธ์
เบต้าการสลายตัว

3
ไม่อยู่ในข้อมูลจำเพาะภายใต้ตัวอักษรต่อไปนี้เป็นอักขระทั้งหมดที่โปรแกรมของคุณต้องจดจำเพียงตัวอักษร AH, JN, PZ และ 0-9 ไม่มีการพูดถึงช่องว่าง

โอเคคุณเป็นคนดีแล้ว
สลายตัวของเบต้า

"โปรไฟล์แรกและตัวที่สอง [... ] เป็นหยดสีน้ำเงินที่มี" GB "ที่ด้านล่างและขอบด้านขวาซึ่งเราไม่สนใจ" แล้วทำไมคุณรวมไว้ในรหัสโดยเฉพาะอย่างยิ่งหากคีย์อาร์เรย์ที่มีสตริงว่างถูกเขียนทับ บวก: ได้รับอนุญาตให้ใช้ไวยากรณ์เปิดสั้น ๆ สำหรับการตีกอล์ฟ! :-)
YetiCGN

@YetiCGN - หากไม่ใช่รหัสจะพยายามจับคู่กับสิ่งอื่น! ฉันไม่ทราบว่าพวกเขาถูกเขียนทับรหัสยังคงทำงานอยู่ การแก้ไข คุณอาจสามารถปรับการเปลี่ยนแปลงบางอย่างของฉันกับคำตอบของคุณ

0

PHP, 971 970 ไบต์

ดึงคำตอบของYimin Rongซึ่งสามารถลงสนามได้อย่างจริงจังโดยเฉพาะดัชนีอาเรย์และวางลงใน Phar ด้วยการบีบอัด gzip

ดาวน์โหลด phar

นี่คือรุ่นพื้นฐานของฉันที่ได้รับการปรับปรุงที่1557 1535 bytes บันทึกได้ง่ายภายใต้ชื่อไฟล์ "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;}

การปรับปรุง:

ขั้นตอนที่ 1

  • ดัชนีอาเรย์ตัวเลขจะถูกลบออกและจัดลำดับอาเรย์อีกครั้งดัชนีสตริงเป็นค่าคงที่โดยนัย

ขั้นตอนที่ 2

  • แทนที่ intvalด้วย~~(บันทึก 8 ไบต์, เกิดขึ้นสองครั้ง)
  • for-loop initialization ถูกลบเมื่อไม่จำเป็น
  • file_get_contents($u) แทนที่ด้วย join('',file($u)) (บันทึก 5 ไบต์)
  • และอีกสองสามคน

น่าเสียดายที่การปรับปรุงขั้นตอนที่สองทั้งหมดแปลเป็นรหัส gzipped ที่น้อยกว่า 1 ไบต์เท่านั้น :-D

และรหัสนี้ใช้เพื่อสร้าง 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();');

ทดสอบด้วยphp ocr.phar http://i.imgur.com/i8jkCJu.pngหรืออื่น ๆ ของภาพกรณีทดสอบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.