12
\$\begingroup\$

The goal of this challenge is to determine the angle of a line in a image.

Rules on the image:

  • The image background will be white (#FFFFFF)
  • The stroke of the line will be black (#000000)
  • The line will NOT be anti-aliased
  • The image will be 100x100 pixels
  • The line will start at the center of the image
  • The line will start pointing down (6-OClock)
  • The line will be 50 pixels long
  • The angle of the line will be measured going counterclockwise from the starting position
  • The image codec will be either .jpg or .png

Input format will be a file name passed by the command line arg, script input, or function arg. Output format is simple - just output the number of degrees (e.g. 90).

Answers can be ±1 degree of the stated measure. Here are a few example images:

1

A reference image at 45 degrees with gray background

1

0 degrees

2

45 degrees

3

50 degrees

4

130 degrees

6

230 degrees

7

324 degrees

Here is the code used to create the images (this is coded with 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'
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Did I get a downvote? If so could the voter explane why? \$\endgroup\$
    – J Atkin
    Commented Nov 28, 2015 at 5:12
  • \$\begingroup\$ Can we just display it, not save it to a file? \$\endgroup\$
    – user46167
    Commented Nov 28, 2015 at 14:40
  • \$\begingroup\$ Sure, that's how all the other answers do it. Just print to the console the answer your program generates. \$\endgroup\$
    – J Atkin
    Commented Nov 28, 2015 at 14:48
  • 1
    \$\begingroup\$ @JAtkin I wouldn't worry about downvotes on a generally upvoted post. c: We all get that. \$\endgroup\$ Commented Nov 28, 2015 at 15:29
  • \$\begingroup\$ Oh, I see. I wonder why I got one though... \$\endgroup\$
    – J Atkin
    Commented Nov 28, 2015 at 15:30

5 Answers 5

9
\$\begingroup\$

JavaScript (ES6), 225 227 244 bytes

Let's get the ball rolling:

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

Simply pass the URL of the image to the function:

f('90deg.png');

Alerts degrees within the ±1 range. Passed all test cases.

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

Edits

  • Saved 17 bytes – figured I don't need to set the width and height of the canvas element.
  • Saved 2 bytes by negating the condition.
\$\endgroup\$
4
  • \$\begingroup\$ I think this should work (haven't tested it). 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)} \$\endgroup\$
    – user81655
    Commented Nov 27, 2015 at 0:56
  • 1
    \$\begingroup\$ This code works because you are lucky. The canvas will be tainted almost everytime. Specially with file://. You need to set the crossOrigin property. Also, it won't work if the image loading takes 0.00001 seconds more than creating the canvas does. Also, you don't need the f=, cutting off 2 bytes. But it is a nice solution indeed!!! My upvote for it. \$\endgroup\$ Commented Nov 27, 2015 at 18:17
  • \$\begingroup\$ @IsmaelMiguel Thanks for your detailed feedback. You're right about the canvas. In the beginning I tried to rotate and mirror the image, so that the angle doesn't need to be transformed. You can say good-bye to that! Got blurry, couldn't find the right pixel. I've skipped the onload part as I was undercut in another challenge because of that. So I thought it's ok to assume that it loads fast enough. Regarding the anonymous function I'm not sure how to count it. If I cut off f= and I want to invoke it I have to wrap it in () like (s=>{})('arg');. Can I ignore this in byte count? \$\endgroup\$ Commented Nov 28, 2015 at 9:59
  • \$\begingroup\$ @insertusernamehere Yeah, you can ignore the byte count. But you have to specify that it is an anonymous function \$\endgroup\$ Commented Nov 28, 2015 at 14:57
7
\$\begingroup\$

Pyth - 28 26 bytes

Uses same sort of brute force strategy as the js answer.

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

Takes input as filename from 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
\$\endgroup\$
4
  • \$\begingroup\$ Wow, this is cool but I don't speak pyth. Would you mind adding an explanation? \$\endgroup\$
    – J Atkin
    Commented Nov 27, 2015 at 0:20
  • 1
    \$\begingroup\$ I wish JavaScript would have the same byte count on the other hand. \$\endgroup\$ Commented Nov 27, 2015 at 0:22
  • \$\begingroup\$ @insertusernamehere I wish groovy or scala could do this kind of golfing as well. \$\endgroup\$
    – J Atkin
    Commented Nov 27, 2015 at 0:30
  • \$\begingroup\$ @JAtkin explanation added. Feel free to message me on chat if you have any questions. \$\endgroup\$
    – Maltysen
    Commented Nov 27, 2015 at 1:00
5
\$\begingroup\$

Matlab, 118 104 bytes

I generate a matrix of the same size as the image with complex numbers (0 in the center) and exctract from that matrix the values which are on the line. The argument of the mean of those is then displayed.

Thanks to @ThomasKwa for suggesting an improvement in accuracy which also resulted in shorter code!!!

I=imread(input('','s'));
[y,x]=ndgrid(-50:49);
c=y+i*x;
disp(mod(angle(mean(c(~I(:,:,1))))*180/pi+360,360))
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Would it be shorter to find the argument of the mean of all of the points on the line? \$\endgroup\$
    – lirtosiast
    Commented Nov 26, 2015 at 23:57
  • \$\begingroup\$ Wow, this is far shorter than I expected answers to be, nice job! \$\endgroup\$
    – J Atkin
    Commented Nov 26, 2015 at 23:58
  • \$\begingroup\$ @ThomasKwa Absolutely, but then it would not be as accurate, as the pixels close to the center are absolutely inaccurate. If you want to try, you can run this code in Octave too, I think! \$\endgroup\$
    – flawr
    Commented Nov 26, 2015 at 23:58
  • \$\begingroup\$ Argument of the mean (which should give the argument of the center of the line to a pretty good accuracy), not mean of the arguments. I don't know if the accuracy would be acceptable. \$\endgroup\$
    – lirtosiast
    Commented Nov 27, 2015 at 0:00
  • 1
    \$\begingroup\$ @ThomasKwa Great idea, thanks! The accuracy is even better now and the code is a few bytes shorter=) \$\endgroup\$
    – flawr
    Commented Nov 27, 2015 at 0:06
5
\$\begingroup\$

Matlab, 86 77 bytes

Here's another way using Matlab:

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

This reads the file (stolen from flawr), and finds the indices of the black pixels. Then, it works out the vector that points from the centre of the image to each black pixel, and uses atan2d to find the angle, rounding to get integer angles, and doing mod(...,360) to get results in the right range. To get the correct angle (there is a bit of error for the pixels close to the centre), take the most commonly calculated angle.

Thanks to slvrbld for the im2bw suggestion!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Your code can be reduced to 77 bytes by replacing the part before mode(...) with [I,J]=find(~im2bw(imread(input('')))); \$\endgroup\$
    – slvrbld
    Commented Nov 27, 2015 at 10:34
  • \$\begingroup\$ Nice one! Thanks I was sure there was a way to do that more easily but couldn't remember it. \$\endgroup\$
    – David
    Commented Nov 28, 2015 at 1:48
3
\$\begingroup\$

Labview, 10098 Bytes

Let's put another labview code out there.

Since there is no official way to count bytes in labview i use the size of the file when saved. Alternatively counting every wire and function as 1and the case as 2 it would come out to 71.

1

Load image, flatten to 1D, scan for 0s from both sides and take the first, calc back to point and use geometry to get angle.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Nice, this is interesting. You may want to ask on meta how to score labview programs. \$\endgroup\$
    – J Atkin
    Commented Nov 27, 2015 at 15:35
  • \$\begingroup\$ there already is a thread on how to score but unfortunatly there is no answer yet \$\endgroup\$
    – Eumel
    Commented Nov 27, 2015 at 15:36
  • \$\begingroup\$ Oh, I see. I just edited your post to make the byte count more understandable to us in the US of A. \$\endgroup\$
    – J Atkin
    Commented Nov 27, 2015 at 15:39
  • \$\begingroup\$ @JAtkin As a european fellow it made me scratch my head, wondering how he got those fractions of byte. Wouldn't using a space please all sides? \$\endgroup\$
    – Aaron
    Commented Nov 27, 2015 at 17:04
  • \$\begingroup\$ Hehehe, I forgot you guys have , for decimal places. \$\endgroup\$
    – J Atkin
    Commented Nov 27, 2015 at 17:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.