Python 2 + PIL, sem erro, 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
Pega um nome de arquivo de imagem na linha de comando e imprime o resultado em STDOUT.
Dá o resultado correto para todos os testes en = 28 para o círculo.
Explicação
O algoritmo funciona caminhando ao longo do perímetro do polígono e contando o número de vértices encontrados (detectados como alterações na direção). Começamos no pixel mais distante da origem, oque é garantidamente um vértice e, portanto, adjacente a uma aresta (ou seja, um limite entre um pixel em primeiro plano e um pixel em segundo plano). Nós controlamos nossa posição, po vértice mais recente ve o "ponto de verificação" mais recente q, todos inicialmente iguais a o. Também acompanhamos a direção da borda d, em relação ao pixel atual; dinicialmente aponta para leste, o que é uma direção segura, pois sabemos que há uma borda a leste deo, ou não seria o mais distante da origem. Nós nos movemos ao longo da borda, em uma direção perpendicular a d, de modo que daponte para a esquerda, ou seja, no sentido horário. Sempre que "caímos da aresta", ou seja, em qualquer situação pfora do polígono, ou onde o pixel à nossa esquerda (na direção de d) esteja dentro do polígono, ajustamos pe de dacordo antes de continuar.
Toda vez que a distância entre pe o último ponto de verificação qfica maior que 5, tentamos determinar se passamos por um vértice entre qe p: Comparamos o ângulo entre vq(ou seja, o vetor de vpara q), que é a direção geral do lado do polígono em que estávamos caminhando quando alcançamos o último ponto de verificação e qpo deslocamento entre o último ponto de verificação e a posição atual. Se o ângulo for maior que cerca de 10 °, concluímos que estamos andando por um lado diferente do polígono, aumentamos a contagem de vértices e ajustamos vo vértice atual para p. Em cada ponto de verificação, independentemente de detectarmos um vértice ou não, atualizamos qo último ponto de verificação parap. Continuamos dessa maneira até chegarmos oao ponto de partida e retornar o número de vértices encontrados (observe que a contagem de vértices é inicialmente 1, pois o ponto de partida oé um vértice).
As imagens abaixo mostram os vértices detectados. Observe que p, assumindo , a posição atual em cada ponto de verificação, como a posição do novo vértice, não é ideal, pois o vértice real provavelmente está em algum lugar entre o último ponto de verificação qe pao longo do perímetro. Como você pode ver, todos os vértices que não sejam o primeiro (geralmente, o vértice inferior direito) estão um pouco fora. Corrigir isso custaria mais bytes, mas parece estar funcionando bem o suficiente. Dito isto, é um pouco difícil não se ajustar demais com apenas quatro casos de teste.
