Qual é esse ângulo?


12

O objetivo deste desafio é determinar o ângulo de uma linha em uma imagem.

Regras sobre a imagem:

  • O fundo da imagem ficará branco ( #FFFFFF)
  • O traço da linha será preto ( #000000)
  • A linha NÃO será anti-alias
  • A imagem terá 100x100 pixels
  • A linha começará no centro da imagem
  • A linha começará a apontar para baixo (6 horas)
  • A linha terá 50 pixels de comprimento
  • O ângulo da linha será medido indo no sentido anti-horário a partir da posição inicial
  • O codec de imagem será .jpgou.png

O formato de entrada será um nome de arquivo transmitido pela linha de comando arg, entrada de script ou função arg. O formato de saída é simples - basta gerar o número de graus (por exemplo 90).

As respostas podem ser de ± 1 grau da medida declarada. Aqui estão alguns exemplos de imagens:

1

Uma imagem de referência a 45 graus com fundo cinza

1

0 graus

2

45 graus

3

50 graus

4

130 graus

6

230 graus

7

324 graus

Aqui está o código usado para criar as imagens (isso é codificado com Processing ):

int deg = 45;

int centX = width/2, centY = height/2;

background(255);
noSmooth();
line(centX,
     centY,
     centX + sin(radians(deg))*50,
     centY + cos(radians(deg))*50);

saveFrame("line-"+deg+".png");// image codec can be changed here. use '.png' or '.jpg'

1
Eu recebi um voto negativo? Em caso afirmativo, o eleitor poderia explicar por quê?
J Atkins

Podemos apenas exibi-lo, não salvá-lo em um arquivo?
Ev3commander 28/11/2015

Claro, é assim que todas as outras respostas o fazem. Apenas imprima no console a resposta que seu programa gera.
J Atkins

1
@JAtkin Eu não me preocuparia com votos negativos em um post geralmente votado. c: Todos nós entendemos isso.
Addison Crump

Ah eu vejo. Pergunto-me porque eu tenho um porém ...
J Atkin

Respostas:


7

Pitão - 28 26 bytes

Usa o mesmo tipo de estratégia de força bruta que a resposta js.

f!@F+]'zm+50s*48.t.tT7d_U2

Recebe a entrada como nome do arquivo de stdin.

f                     Filters from 1 till predicate is matched
 !                    Boolean not so that only pixel with zero value matched
  @F+]                Folds by indexing to get pixel value  
   'z                 Reads image filename input
   m         _U2      Maps over both trig ratios
    +50               Adds 50 to pixel value
     *48              Multiplies pixel value by 48
      .t    d         Takes trig ratio with appropriate option
        .t 7          Degrees to radians
          T           Filter var

Uau, isso é legal, mas eu não falo pyth. Você se importaria de adicionar uma explicação?
J Atkins

1
Eu gostaria que o JavaScript tivesse a mesma contagem de bytes, por outro lado.
insertusernamehere

@insertusernamehere Desejo que o groovy ou o scala também possam praticar esse tipo de golfe.
J Atkin 27/11

@JAtkin explicação adicionada. Sinta-se à vontade para me enviar uma mensagem no chat se tiver alguma dúvida.
Maltysen

9

JavaScript (ES6), 225 227 244 bytes

Vamos fazer a bola rolar:

f=s=>{(i=new Image).src=s;c=document.createElement`canvas`.getContext`2d`;c.drawImage(i,0,0,100,100);for(a=360;a--,r=a/180*(m=Math).PI;)if(!c.getImageData(50+48*m.cos(r),50+48*m.sin(r),1,1).data[1]){alert((450-a)%360);break}}

Basta passar o URL da imagem para a função:

f('90deg.png');

Alertas graus dentro do intervalo ± 1. Passou em todos os casos de teste.

Ungolfed

f=s=>{
    // create new image and set source
    (i=new Image).src=s;
    // create canvas and get context
    c=document.createElement`canvas`.getContext`2d`;
    // set width/height to 100px and draw image on canvas
    c.drawImage(i,0,0,100,100);
    // check whether for any degree on the theoretical circle a black pixel is found
    for(a=360;a--,r=a/180*(m=Math).PI;)
        if(!c.getImageData(50+48*m.cos(r),50+48*m.sin(r),1,1).data[1]){
            // wait, it should be ccw and the board is rotated 90 degrees
            alert((450-a)%360);
            break
        }
}

Editar% s

  • Salva 17 bytes - calculado, não preciso definir a largura e a altura do elemento da tela.
  • Salva 2 bytes negando a condição.

Eu acho que isso deve funcionar (não testei). 206 bytes:s=>{(i=new Image).src=s;with(Math)with(document.createElement`canvas`.getContext`2d`)for(drawImage(i,0,0,100,100),a=360;r=--a/180*PI;)getImageData(50+48*cos(r),50+48*sin(r),1,1).data[1]||alert((450-a)%360)}
user81655

1
Este código funciona porque você tem sorte. A tela será manchada quase sempre. Especialmente com file://. Você precisa definir a crossOriginpropriedade Além disso, não funcionará se o carregamento da imagem demorar 0,00001 segundos a mais do que a criação da tela. Além disso, você não precisa f=cortar 2 bytes. Mas é realmente uma boa solução !!! Meu voto positivo por isso.
Ismael Miguel

@IsmaelMiguel Obrigado pelo seu feedback detalhado. Você está certo sobre a tela. No começo, tentei girar e espelhar a imagem, para que o ângulo não precise ser transformado. Você pode dizer adeus a isso! Ficou embaçado, não foi possível encontrar o pixel certo. Eu pulei a onloadparte porque fui prejudicado em outro desafio por causa disso. Então eu pensei que não há problema em assumir que ele carrega rápido o suficiente. Em relação à função anônima, não sei como contá-la. Se eu corto f=e quero invocá-lo, tenho que envolvê-lo ()como (s=>{})('arg');. Posso ignorar isso na contagem de bytes?
insertusernamehere

@insertusernamehere Sim, você pode ignorar a contagem de bytes. Mas você tem que especificar que é uma função anônima #
Ismael Miguel

5

Matlab, 118 104 bytes

Gero uma matriz do mesmo tamanho da imagem com números complexos (0 no centro) e retiro dessa matriz os valores que estão na linha. O argumento da média desses é exibido.

Obrigado a @ThomasKwa por sugerir uma melhoria na precisão que também resultou em um código mais curto !!!

I=imread(input('','s'));
[y,x]=ndgrid(-50:49);
c=y+i*x;
disp(mod(angle(mean(c(~I(:,:,1))))*180/pi+360,360))

1
Seria mais curto encontrar o argumento da média de todos os pontos da linha?
lirtosiast

Uau, isso é muito menor do que eu esperava que as respostas fossem, bom trabalho!
J Atkins

@ThomasKwa Absolutamente, mas não seria tão preciso, pois os pixels próximos ao centro são absolutamente imprecisos. Se você quiser tentar, também pode executar esse código no Octave, eu acho!
flawr

Argumento da média (que deve dar o argumento do centro da linha com uma precisão bastante boa), não a média dos argumentos. Não sei se a precisão seria aceitável.
lirtosiast

1
@ThomasKwa Ótima idéia, obrigado! A precisão é ainda melhor agora e o código é alguns bytes mais curto =)
flawr

5

Matlab, 86 77 bytes

Aqui está outra maneira de usar o Matlab:

[I,J]=find(~im2bw(imread(input('','s'))));mode(mod(round(atan2d(J-51,I-51)),360))

Isso lê o arquivo (roubado do flawr ) e localiza os índices dos pixels pretos. Em seguida, elabora o vetor que aponta do centro da imagem para cada pixel preto e usa atan2dpara encontrar o ângulo, arredondando para obter ângulos inteiros e fazendo mod(...,360)para obter resultados no intervalo certo. Para obter o ângulo correto (há um pouco de erro nos pixels próximos ao centro), use o ângulo calculado com mais frequência.

Obrigado a slvrbld pela im2bwsugestão!


1
Seu código pode ser reduzido para 77 bytes , substituindo a peça antes do modo (...) por [I, J] = find (~ im2bw (imread (input (''))));
slvrbld

Agradável! Obrigado, eu tinha certeza de que havia uma maneira de fazer isso mais facilmente, mas não conseguia se lembrar.
David

3

Labview, 10098 bytes

Vamos colocar outro código do labview por aí.

Como não existe uma maneira oficial de contar bytes no labview, uso o tamanho do arquivo quando salvo. Contando alternativamente todos os fios e funcionando como 1 e o caso como 2, ele chegaria a 71.

1

Carregue a imagem, achatar para 1D, digitalize 0s de ambos os lados e pegue o primeiro, volte ao ponto e use a geometria para obter o ângulo.


1
Bom, isso é interessante. Você pode perguntar na meta como classificar os programas do labview.
J Atkins

já existe uma discussão sobre como marcar, mas infelizmente não há nenhuma resposta ainda
Eumel

Ah eu vejo. I acabou de editar o seu post para fazer o byte contar mais compreensível para nós nos EUA de A.
J Atkin

@JAtkin Como sujeito europeu, isso me fez coçar a cabeça, imaginando como ele conseguia essas frações de bytes. Usar um espaço não agradaria a todos os lados?
Aaron

Hehehe, esqueci que vocês têm ,casas decimais.
J Atkins
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.