Python 2 + PIL, pas d'erreur, 313 307 octets
from Image import*
I=open(sys.argv[1])
w,h=I.size;D=I.getdata()
B={i%w+i/w*1j for i in range(w*h)if D[i]!=D[0]}
n=d=1;o=v=q=p=max(B,key=abs)
while p-w:
p+=d*1j;e=2*({p}<B)+({p+d}<B)
if e!=2:e%=2;d*=1j-e*2j;p-=d/1j**e
if abs(p-q)>5:
t=(q-v)*(p-q).conjugate();q=p;w=o
if.98*abs(t)>t.real:n+=1;v=p
print n
Prend un nom de fichier image sur la ligne de commande et imprime le résultat sur STDOUT.
Donne le résultat correct pour tous les tests et n = 28 pour le cercle.
Explication
L'algorithme fonctionne en marchant le long du périmètre du polygone et en comptant le nombre de sommets rencontrés (détectés comme des changements de direction). Nous partons du pixel le plus éloigné de l'origine, o
qui est garanti d'être un sommet, et donc d'être adjacent à un bord (c'est-à-dire une frontière entre un pixel de premier plan et un pixel d'arrière-plan). Nous gardons une trace de notre position, p
du sommet le plus récent v
et du "point de contrôle" le plus récent q
, qui sont tous initialement égaux à o
. Nous suivons également la direction du bord d
,, par rapport au pixel actuel; d
pointe d'abord vers l'est, ce qui est une direction sûre, car nous savons qu'il y a un bord à l'est deo
, sinon il ne serait pas le plus éloigné de l'origine. Nous nous déplaçons le long du bord, dans une direction perpendiculaire à d
, telle qu'elle d
pointe vers notre gauche, c'est-à-dire dans le sens horaire. Chaque fois que nous «tombons du bord», c'est-à-dire dans toute situation où p
est en dehors du polygone, ou où le pixel à notre gauche (c'est-à-dire dans la direction de d
) est à l'intérieur du polygone, nous nous ajustons p
et en d
conséquence avant de reprendre.
Chaque fois que la distance entre p
et le dernier point de contrôle, q
devient supérieure à 5, nous essayons de déterminer si nous avons dépassé un sommet entre q
et p
: Nous comparons l'angle entre vq
(c'est-à-dire le vecteur de v
à q
), qui est la direction générale de la côté du polygone que nous marchions lorsque nous avons atteint le dernier point de contrôle, et qp
, le déplacement entre le dernier point de contrôle et la position actuelle. Si l'angle est supérieur à environ 10 °, nous concluons que nous marchons le long d'un côté différent du polygone, augmentons le nombre de sommets et définissons v
le sommet actuel sur p
. À chaque point de contrôle, que nous ayons détecté ou non un sommet, nous mettons à jour q
, le dernier point de contrôle,p
. Nous continuons de cette façon jusqu'à ce que nous arrivions au o
point de départ et retournions le nombre de sommets trouvés (notez que le nombre de sommets est initialement de 1, car le point de départ o
est lui-même un sommet).
Les images ci-dessous montrent les sommets détectés. Notez que la prise p
, la position actuelle à chaque point de contrôle, comme la position du nouveau sommet n'est pas optimale, car le sommet réel est probablement quelque part entre le dernier point de contrôle,, q
et p
, le long du périmètre. Comme vous pouvez le voir, tous les sommets autres que le premier (généralement le sommet en bas à droite) sont un peu décalés. Corriger cela coûterait plus d'octets, mais cela semble fonctionner assez bien tel quel. Cela étant dit, il est un peu difficile de ne pas surcharger avec seulement quatre cas de test.