Python 2 + PIL, sin error, 313 307 bytes
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
Toma un nombre de archivo de imagen en la línea de comando e imprime el resultado en STDOUT.
Da el resultado correcto para todas las pruebas, y n = 28 para el círculo.
Explicación
El algoritmo funciona caminando a lo largo del perímetro del polígono y contando el número de vértices encontrados (detectados como cambios en la dirección). Comenzamos en el píxel más alejado del origen, o
que se garantiza que es un vértice y, por lo tanto, adyacente a un borde (es decir, un límite entre un píxel de primer plano y un píxel de fondo). Llevamos un registro de nuestra posición, p
el vértice más reciente v
y el "punto de control" más reciente q
, todos los cuales son inicialmente iguales a o
. También hacemos un seguimiento de la dirección del borde d
, en relación con el píxel actual; d
inicialmente apunta al este, que es una dirección segura, ya que sabemos que hay un borde al este deo
o de lo contrario no estaría más lejos del origen. Nos movemos a lo largo del borde, en una dirección perpendicular a d
, de modo que d
apunta a nuestra izquierda, es decir, en el sentido de las agujas del reloj. Cada vez que "nos caemos del borde", es decir, en cualquier situación en la que p
está fuera del polígono, o donde el píxel a nuestra izquierda (es decir, en la dirección de d
) está dentro del polígono, nos ajustamos p
y, en d
consecuencia, antes de continuar.
Cada vez que la distancia entre p
y el último punto de control, q
es mayor que 5, tratamos de determinar si pasamos por un vértice entre q
y p
: comparamos el ángulo entre vq
(es decir, el vector de v
a q
), que es la dirección general de lado del polígono que estábamos caminando cuando llegamos al último punto de control y qp
el desplazamiento entre el último punto de control y la posición actual. Si el ángulo es mayor de aproximadamente 10 °, concluimos que estamos caminando a lo largo de un lado diferente del polígono, aumentamos el conteo de vértices y establecemos v
el vértice actual en p
. En cada punto de control, independientemente de si detectamos un vértice o no, actualizamos q
el último punto de control parap
. Continuamos de esta manera hasta que volvemos al o
punto de partida y devolvemos el número de vértices encontrados (tenga en cuenta que el conteo de vértices es inicialmente 1, ya que el punto de partida o
es en sí mismo un vértice).
Las imágenes a continuación muestran los vértices detectados. Tenga en cuenta que tomar p
la posición actual en cada punto de control, ya que la posición del nuevo vértice no es óptima, ya que el vértice real probablemente esté en algún lugar entre el último punto de control q
, y p
, a lo largo del perímetro. Como puede ver, todos los vértices que no sean el primero (generalmente, el vértice inferior derecho) están un poco alejados. Arreglar esto costaría más bytes, pero parece estar funcionando lo suficientemente bien como está. Dicho esto, es un poco difícil no equiparse con solo cuatro casos de prueba.