¿Cuál es ese ángulo?

12

El objetivo de este desafío es determinar el ángulo de una línea en una imagen.

Reglas sobre la imagen:

  • El fondo de la imagen será blanco ( #FFFFFF)
  • El trazo de la línea será negro ( #000000)
  • La línea NO será anti-alias
  • La imagen tendrá 100x100 píxeles.
  • La línea comenzará en el centro de la imagen.
  • La línea comenzará a apuntar hacia abajo (6-OClock)
  • La línea tendrá 50 píxeles de largo.
  • El ángulo de la línea se medirá en sentido antihorario desde la posición inicial
  • El códec de imagen será .jpgo.png

El formato de entrada será un nombre de archivo pasado por la línea de comando arg, entrada de script o función arg. El formato de salida es simple: simplemente envíe el número de grados (por ejemplo 90).

Las respuestas pueden ser ± 1 grado de la medida indicada. Aquí hay algunas imágenes de ejemplo:

1

Una imagen de referencia a 45 grados con fondo gris.

1

0 grados

2

45 grados

3

50 grados

4 4

130 grados

6 6

230 grados

7 7

324 grados

Aquí está el código utilizado para crear las imágenes (esto está codificado con 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'
J Atkin
fuente
1
¿Recibí un voto negativo? Si es así, ¿podría el votante explicar por qué?
J Atkin
¿Podemos mostrarlo, no guardarlo en un archivo?
ev3commander
Claro, así es como lo hacen todas las otras respuestas. Simplemente imprima en la consola la respuesta que genera su programa.
J Atkin
1
@JAtkin No me preocuparía por los votos negativos en una publicación generalmente votada. c: Todos lo entendemos.
Addison Crump
Oh ya veo. Sin embargo, me pregunto por qué tengo uno ...
J Atkin

Respuestas:

7

Pyth - 28 26 bytes

Utiliza el mismo tipo de estrategia de fuerza bruta que la respuesta js.

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

Toma la entrada como nombre de archivo desde 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
Maltysen
fuente
Wow, esto es genial pero no hablo pyth. ¿Te importaría agregar una explicación?
J Atkin
1
Desearía que JavaScript tuviera el mismo número de bytes por otro lado.
insertusernamehere
@insertusernamehere Me gustaría que groovy o scala también pudieran hacer este tipo de golf.
J Atkin
Explicación @JAtkin agregada. No dude en enviarme un mensaje por chat si tiene alguna pregunta.
Maltysen
9

JavaScript (ES6), 225 227 244 bytes

Hagamos rodar la pelota:

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

Simplemente pase la URL de la imagen a la función:

f('90deg.png');

Alerta grados dentro del rango ± 1. Pasó todos los casos de prueba.

Sin golf

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

Ediciones

  • Guardado 17 bytes : supuse que no necesito establecer el ancho y la altura del elemento de lienzo.
  • Ahorró 2 bytes al negar la condición.
insertusernamehere
fuente
Creo que esto debería funcionar (no lo he probado). 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 tienes suerte. El lienzo estará contaminado casi siempre. Especialmente con file://. Necesita establecer la crossOriginpropiedad. Además, no funcionará si la carga de la imagen tarda 0.00001 segundos más que la creación del lienzo. Además, no necesita f=, cortando 2 bytes. ¡Pero es una buena solución! Mi voto a favor por ello.
Ismael Miguel
@IsmaelMiguel Gracias por sus comentarios detallados. Tienes razón sobre el lienzo. Al principio intenté rotar y reflejar la imagen, de modo que el ángulo no necesita ser transformado. ¡Puedes decir adiós a eso! Se volvió borrosa, no pude encontrar el píxel correcto. Me salteé la onloadparte porque fui socavada en otro desafío debido a eso. Así que pensé que estaba bien suponer que se carga lo suficientemente rápido. En cuanto a la función anónima, no estoy seguro de cómo contarla. Si corto f=y quiero invocarlo, tengo que envolverlo ()como (s=>{})('arg');. ¿Puedo ignorar esto en el recuento de bytes?
insertusernamehere
@insertusernamehere Sí, puede ignorar el recuento de bytes. Pero debes especificar que es una función anónima
Ismael Miguel
5

Matlab, 118104 bytes

Genero una matriz del mismo tamaño que la imagen con números complejos (0 en el centro) y extraigo de esa matriz los valores que están en la línea. Entonces se muestra el argumento de la media de esos.

¡Gracias a @ThomasKwa por sugerir una mejora en la precisión que también resultó en un código más corto!

I=imread(input('','s'));
[y,x]=ndgrid(-50:49);
c=y+i*x;
disp(mod(angle(mean(c(~I(:,:,1))))*180/pi+360,360))
falla
fuente
1
¿Sería más corto encontrar el argumento de la media de todos los puntos en la línea?
lirtosiast el
Wow, esto es mucho más corto de lo que esperaba respuestas, ¡buen trabajo!
J Atkin
@ThomasKwa Absolutamente, pero entonces no sería tan preciso, ya que los píxeles cercanos al centro son absolutamente inexactos. Si quieres probar, ¡también puedes ejecutar este código en Octave!
falla
Argumento de la media (que debería dar el argumento del centro de la línea con bastante precisión), no la media de los argumentos. No sé si la precisión sería aceptable.
lirtosiast el
1
@ThomasKwa Gran idea, gracias! La precisión es aún mejor ahora y el código es unos bytes más corto =)
error
5

Matlab, 86 77 bytes

Aquí hay otra forma de usar Matlab:

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

Esto lee el archivo (robado de flawr ) y encuentra los índices de los píxeles negros. Luego, calcula el vector que apunta desde el centro de la imagen a cada píxel negro, y lo utiliza atan2dpara encontrar el ángulo, redondear para obtener ángulos enteros y hacer mod(...,360)para obtener resultados en el rango correcto. Para obtener el ángulo correcto (hay un pequeño error para los píxeles cerca del centro), tome el ángulo calculado más comúnmente.

Gracias a slvrbld por la im2bwsugerencia!

David
fuente
1
Su código puede reducirse a 77 bytes reemplazando la parte anterior al modo (...) con [I, J] = find (~ im2bw (imread (input (''))));
slvrbld
¡Buena esa! Gracias, estaba seguro de que había una manera de hacerlo más fácilmente, pero no podía recordarlo.
David
3

Labview, 10098 bytes

Pongamos otro código labview por ahí.

Como no hay una forma oficial de contar bytes en labview, uso el tamaño del archivo cuando lo guardo. Alternativamente, contando cada cable y función como 1 y el caso como 2, saldría a 71.

1

Cargue la imagen, aplánelo a 1D, escanee 0s desde ambos lados y tome el primero, calcule de nuevo al punto y use la geometría para obtener el ángulo.

Eumel
fuente
1
Bien, esto es interesante. Es posible que desee preguntar en meta cómo calificar los programas de labview.
J Atkin
ya hay un hilo sobre cómo anotar, pero desafortunadamente aún no hay respuesta
Eumel
Oh ya veo. Acabo de editar su publicación para que el byte cuente más comprensible para nosotros en los EE. UU. De A.
J Atkin
@JAtkin Como compañero europeo, me hizo rascarme la cabeza, preguntándome cómo consiguió esas fracciones de byte. ¿No usaría un espacio por favor todos los lados?
Aaron
Jejeje, olvidé que ustedes tienen ,para decimales.
J Atkin