Erkennen Sie ASCII-Kunstnummern


15

Herausforderung

Erkennen Sie ASCII-Kunstnummern. Um die Sache interessant zu machen, können drei zufällige Punkte im Bild umgedreht werden. Beispielsweise:

 ***** 
 *  ** 
    ** 

   **  
  **   
 **    

Eingang

Eine 7x7-ASCII-Kunstnummer, die mit dem folgenden Python-Skript generiert wurde.

Ausgabe

Eine Ziffer.

Skript testen

Hier ist ein Python-Skript (2.6+) zum Generieren der Testfälle:

import random

digits = '''\
  ***  
 ** ** 
**   **
**   **
**   **
 ** ** 
  ***  

   *   
 ***   
   *   
   *   
   *   
   *   
 ***** 

  ***  
 *  ** 
     * 
    ** 
   **  
  **   
 ******

  ***  
 *  ** 
     * 
  ***  
     * 
 *  ** 
  ***  

   **  
  ***  
 * **  
*  **  
****** 
   **  
   **  

 ***** 
 **    
 ****  
     * 
     * 
 *   * 
  ***  

  **** 
 **    
 ***** 
 *   * 
 **  **
 **  * 
  **** 

 ***** 
    ** 
    ** 
   **  
   **  
  **   
 **    

  **** 
 **  **
 **  **
  **** 
 **  **
 **  **
  **** 

  ***  
 ** ** 
**   **
 **  * 
  **** 
    ** 
 ****  '''.split('\n\n')

def speckle(image, num_speckles):
    grid = [list(row) for row in image.split('\n')]

    for i in range(num_speckles):
        row = random.choice(grid)
        row[random.randint(0, 6)] = random.choice([' ', '*'])

    return '\n'.join([''.join(row) for row in grid])

digit = random.choice(digits)

print(speckle(digit, 3))

Sind Sie sicher, dass der Hamming-Abstand zwischen zwei Stellen mehr als 6 beträgt?
John Dvorak

@ JanDvorak: Ich habe die Schriftart so angepasst, dass dies kein Problem darstellt. Siehst du einen
Blender

Antworten:


9

APL ( 87 85)

1-⍨⊃⍒(,↑{7↑'*'=⍞}¨⍳7)∘(+.=)¨{49↑,(16/2)⊤⎕UCS⍵}¨↓10 3⍴'嵝䍝뫂傁ဣ␋䠁䊫낫䢝䊅넂垵僡ᑨ嘙쐅嘹䜝䪀슪퀪岹亝尵䌧뮢'

Erläuterung:

Jede mögliche ASCII-Nummer ist in 48 Bit codiert. (Das 49. Bit ist sowieso immer Null). Die Saite嵝䍝뫂傁ဣ␋䠁䊫낫䢝䊅넂垵僡ᑨ嘙쐅嘹䜝䪀슪퀪岹亝尵䌧뮢 besteht aus drei Zeichen pro ASCII-Nummer, von denen jedes 16 Bits codiert.

  • ↓10 3⍴: Teilen Sie den Datenstring in 10 3-Zeichen-Gruppen auf, von denen jede eine Zahl codiert.
  • {... : für jede der Gruppen:
    • (16/2)⊤⎕UCS⍵: Holen Sie sich die ersten 16 Bits von jedem der drei Zeichen
    • ,: Verketten Sie die Bit-Arrays zu einem Array
    • 49↑: nimm die ersten 49 Elemente. Es gibt nur 48, dies entspricht also dem Hinzufügen eines 0am Ende.
  • ,↑{7↑'*'=⍞}¨⍳7: 7 Zeilen mit 7 Zeichen von der Tastatur lesen, für jede Zeile ein Bit-Array erstellen, wobei 1das Zeichen a bedeutet* , und füge sie zusammen.
  • (+.=)¨: Berechnen Sie für jede mögliche Ziffer, wie viele Bits die Eingabe mit der Ziffer gemeinsam hatte.
  • : Ruft die Indizes für eine abwärts gerichtete Sortierung dieser Liste ab, sodass das erste Element im Ergebnis der Index der größten Zahl in der vorherigen Liste ist.
  • : nimm den ersten Punkt, der der Index der Ziffer ist
  • 1-⍨: subtrahiere eins, da APL-Indizes 1-basiert sind.

3
wow 87? muss das längste APL-Programm aller Zeiten sein.
Izabera

4
Ich dachte immer, dass APL immer wie Grieche aussieht. Jetzt auch chinesisch?!?
Digital Trauma


5

Python

Ich bin mir sicher, dass es OCR-Lösungen geben wird, aber die Wahrscheinlichkeit meiner Genauigkeit ist viel höher.

import difflib as x;r=range;s='2***3**1**1**3****3****3**1**1**3***23*4***6*6*6*6*4*****12***3*2**6*5**4**4**4******2***3*2**6*3***7*2*2**3***23**4***3*1**2*2**2******4**5**21*****2**5****7*6*2*3*3***22****2**5*****2*3*2**2**1**2*3****11*****5**5**4**5**4**4**42****2**2**1**2**2****2**2**1**2**2****12***3**1**1**3**1**2*3****5**2****2'
for c in r(8):s=s.replace(str(c),' '*c)
s=map(''.join,zip(*[iter(s)]*7));a=[raw_input("") for i in r(7)];l=[[x.SequenceMatcher('','|'.join(a),'|'.join(s[i*7:(i+1)*7])).ratio()] for i in r(10)];print l.index(max(l))

Geben Sie jeweils eine Textzeile ein.

Ich bin mir nicht sicher, wie ich besser mit den Sternchen umgehen kann, ohne die Anzahl der Zeichen zu erhöhen.


4

JavaScript (ES6), 89

f=n=>(a=1,[a=(a+a^c.charCodeAt())%35 for(c of n)],[4,25,5,16,0,11,32,13,10,1].indexOf(a))

Verwendung:

> f("  ***  \n *  ** \n     * \n    ** \n   **  \n  **   \n ******")
2

Ungolf-Version:

f = (n) => (
  // Initialize the digit's hash.
  a=1,
  // Hash the digit.
  // 35 is used because the resulting hash is unique for the first ten digits.
  // Moreover, it generates 4 1-digit hashes.
  [a = (a + a ^ c.charCodeAt()) % 35 for(c of n)],
  // Compare the hash to pre-computed digit hash.
  // The matching hash index is the digit.
  [4,25,5,16,0,11,32,13,10,1].indexOf(a)
)

3
Funktioniert dies, wenn die Eingabe nicht genau einer der Ziffern entspricht? Entsprechend der Frage können drei Pixel umgedreht werden und es sollte immer noch funktionieren.
Marinus

3

Bash + ImageMagick + Tesseract, 316 Zeichen

Hier ist ein Vorgeschmack auf eine OCR-Lösung. Es ist allerdings nicht sehr genau, selbst wenn man Tesseract sagt, dass wir nur ein Zeichen haben und es eine Ziffer ist. Mäßig golfen, aber immer noch etwas lesbar:

w=0
c()((w=${#2}>w?${#2}:w))
mapfile -c1 -Cc -t l
h=${#l[@]}
{
echo "# ImageMagick pixel enumeration: $w,$h,1,gray"
for y in ${!l[@]};{
for((x=0;x<w;x++));{
[ "${l[$y]:$x:1}" != " " ]
echo "$x,$y: ($?,$?,$?)"
}
}
}|convert txt:- i.png
tesseract i.png o -psm 10 <(echo "tessedit_char_whitelist 0123456789")
cat o.txt

Das Skript nimmt Eingaben von stdin entgegen, sodass wir das Testskript weiterleiten können.

Hinweis Ich habe tee >( cat 1>&2 )die Pipeline so eingestellt, dass wir sehen können, was das Testskript tatsächlich generiert hat.

Beispielausgabe (Dies war ein ziemlich guter Lauf mit nur 1 falschen Zeichen von 6):

$ python ./asciitest.py | tee> (katze 1> & 2) | ./scanascii.sh
  ***  
 ** ** 
* **
 ** * 
  **** 
    ***
 ****  
Tesseract Open Source OCR Engine v3.02 mit Leptonica
9

$ python ./asciitest.py | tee> (katze 1> & 2) | ./scanascii.sh
   *   
 *** *
   *   
   *   
   *   
   *   
 ***** 
Tesseract Open Source OCR Engine v3.02 mit Leptonica
1

$ python ./asciitest.py | tee> (katze 1> & 2) | ./scanascii.sh
  ***  
 ** ** 
** **
** **
** **
  * ** 
  ***  
Tesseract Open Source OCR Engine v3.02 mit Leptonica
0

$ python ./asciitest.py | tee> (katze 1> & 2) | ./scanascii.sh
 ***** 
 **    
 ****  
     * 
     * 
 ** * 
  ***  
Tesseract Open Source OCR Engine v3.02 mit Leptonica
5

$ python ./asciitest.py | tee> (katze 1> & 2) | ./scanascii.sh
  **** 
 **    
 ***** 
 * * 
*** ***
 ** **
  **** 
Tesseract Open Source OCR Engine v3.02 mit Leptonica
5

$ python ./asciitest.py | tee> (katze 1> & 2) | ./scanascii.sh
  ***  
 * ** 
     * 
    ** 
   *** 
  **   
 ******
Tesseract Open Source OCR Engine v3.02 mit Leptonica
2

$ 

1

LÖVE2D, 560 Bytes

t=...;g=love.graphics g.setNewFont(124)g.setBackgroundColor(255,255,255)A=g.newCanvas()B=g.newCanvas()x=1 y=1 g.setColor(255,255,255)g.setCanvas(B)g.clear(0,0,0)for i=1,#t do x=x+1 if t:sub(i,i)=="\n"then x=1 y=y+1 end if t:sub(i,i)=="*"then g.rectangle("fill",x*16,y*16,16,16)end end u=B:newImageData()g.setCanvas(A)S={}for i=0,9 do g.clear(0,0,0,0)g.print(i,48,0)r=A:newImageData()s={i=i,s=0}for x=0,16*8 do for y=0,16*8 do a=u:getPixel(x,y)b=r:getPixel(x,y)s.s=s.s+math.abs(a-b)end end S[i+1]=s end table.sort(S,function(a,b)return a.s<b.s end)print(S[1].i)

Zeichnet zunächst eine blockartige Darstellung des eingegebenen Texts, überlagert dann für jede Zahl 0 - 9 eine Zahl, überprüft, wie viele ähnliche Pixel vorhanden sind, und druckt die Zahl aus, die am nächsten gekommen ist. Sehr einfache Texterkennung. Es passt zu allen Testfällen und schneidet bei Mutationen recht gut ab.

Rufen Sie an mit:

love.exe "" "INPUT"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.