Reconnaître les numéros d'art ASCII

15

Défi

Reconnaître les numéros d'art ASCII. Pour rendre les choses intéressantes, trois points aléatoires de l'image peuvent être inversés. Par exemple:

 ***** 
 *  ** 
    ** 

   **  
  **   
 **    

Contribution

Un numéro d'art ASCII 7x7 généré par le script Python ci-dessous.

Production

Un chiffre.

Script de test

Voici un script Python (2.6+) pour générer les cas de test:

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))
Mixeur
la source
Êtes-vous sûr que la distance de Hamming entre chacun des deux chiffres est supérieure à 6?
John Dvorak
@JanDvorak: J'ai modifié la police pour que ce ne soit pas un problème. En voyez-vous un?
Blender

Réponses:

9

APL ( 87 85)

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

Explication:

Chaque numéro ASCII possible est codé en 48 bits. (Le 49e bit est toujours zéro de toute façon). La chaîne 嵝䍝뫂傁ဣ␋䠁䊫낫䢝䊅넂垵僡ᑨ嘙쐅嘹䜝䪀슪퀪岹亝尵䌧뮢a trois caractères par numéro ASCII, chacun codant 16 bits.

  • ↓10 3⍴: divise la chaîne de données en 10 groupes de 3 caractères, chacun codant un nombre.
  • {... : pour chacun des groupes:
    • (16/2)⊤⎕UCS⍵: obtenez les 16 premiers bits de chacun des trois caractères
    • ,: concaténer les tableaux de bits dans un tableau
    • 49↑: prenez les 49 premiers éléments. Il n'y en a que 48, ce qui revient à ajouter un 0à la fin.
  • ,↑{7↑'*'=⍞}¨⍳7: lisez 7 lignes de 7 caractères sur le clavier, faites un tableau de bits pour chaque ligne où 1signifie que le caractère était un *, et joignez-les ensemble.
  • (+.=)¨: pour chaque chiffre possible, calculez combien de bits l'entrée avait en commun avec le chiffre.
  • : récupère les indices pour un tri vers le bas de cette liste, de sorte que le premier élément du résultat soit l'index du plus grand nombre de la liste précédente.
  • : prendre le premier élément, qui est l'index du chiffre
  • 1-⍨: soustrayez un, car les indices APL sont basés sur 1.
marinus
la source
3
wow 87? doit être le plus long programme APL jamais créé.
izabera
4
J'ai toujours pensé qu'APL ressemble toujours au grec. Maintenant chinois aussi?!?
Digital Trauma
5

Python

Je suis sûr qu'il y aura des solutions OCR, mais la probabilité que la mienne soit précise est beaucoup plus élevée.

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

Saisissez une ligne de texte à la fois.

Pas sûr d'une meilleure façon de gérer les astérisques sans augmenter le nombre de caractères.

grovesNL
la source
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))

Usage:

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

Version sans golf:

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)
)
Florent
la source
3
Est-ce que cela fonctionne si l'entrée n'est pas exactement égale à l'un des chiffres? Selon la question, trois pixels peuvent être retournés et cela devrait toujours fonctionner.
marinus
3

Bash + ImageMagick + tesseract, 316 caractères

Voici un aperçu d'une solution d'OCR. Ce n'est pas très précis cependant, même en disant à tesseract que nous n'avons qu'un seul caractère et que c'est un chiffre. Modérément golfé, mais encore un peu lisible:

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

Le script prend l'entrée de stdin, nous pouvons donc diriger à partir du script de test.

Remarque J'ai mis tee >( cat 1>&2 )dans le pipeline juste pour que nous puissions voir ce que le script de test a réellement généré.

Exemple de sortie (c'était une assez bonne course avec seulement 1 caractère incorrect sur 6):

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

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

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

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

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

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

$ 
Traumatisme numérique
la source
1

LÖVE2D, 560 octets

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)

Tout d'abord, dessine une représentation en blocs du texte d'entrée, puis, pour chaque nombre 0 - 9, superpose un nombre, vérifie le nombre de pixels similaires et imprime le nombre le plus proche. OCR très basique. Il correspond à tous les cas de test et fonctionne relativement bien avec les mutations.

Appeler avec:

love.exe "" "INPUT"
ATaco
la source