What is that angle?

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: A reference image at 45 degrees with gray background 0 degrees 45 degrees 50 degrees 130 degrees 230 degrees 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,

saveFrame("line-"+deg+".png");// image codec can be changed here. use '.png' or '.jpg'
• Did I get a downvote? If so could the voter explane why? Nov 28 '15 at 5:12
• Can we just display it, not save it to a file?
– user46167
Nov 28 '15 at 14:40
• Sure, that's how all the other answers do it. Just print to the console the answer your program generates. Nov 28 '15 at 14:48
• @JAtkin I wouldn't worry about downvotes on a generally upvoted post. c: We all get that. Nov 28 '15 at 15:29
• Oh, I see. I wonder why I got one though... Nov 28 '15 at 15:30

JavaScript (ES6), 225 227244 bytes

Let's get the ball rolling:

f=s=>{(i=new Image).src=s;c=document.createElementcanvas.getContext2d;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){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.createElementcanvas.getContext2d;
// 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){
// wait, it should be ccw and the board is rotated 90 degrees
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.
• I think this should work (haven't tested it). 206 bytes: s=>{(i=new Image).src=s;with(Math)with(document.createElementcanvas.getContext2d)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||alert((450-a)%360)} Nov 27 '15 at 0:56
• 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. Nov 27 '15 at 18:17
• @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? Nov 28 '15 at 9:59
• @insertusernamehere Yeah, you can ignore the byte count. But you have to specify that it is an anonymous function Nov 28 '15 at 14:57

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
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           Filter var
• Wow, this is cool but I don't speak pyth. Would you mind adding an explanation? Nov 27 '15 at 0:20
• I wish JavaScript would have the same byte count on the other hand. Nov 27 '15 at 0:22
• @insertusernamehere I wish groovy or scala could do this kind of golfing as well. Nov 27 '15 at 0:30
• @JAtkin explanation added. Feel free to message me on chat if you have any questions. Nov 27 '15 at 1:00

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

[y,x]=ndgrid(-50:49);
c=y+i*x;
disp(mod(angle(mean(c(~I(:,:,1))))*180/pi+360,360))
• Would it be shorter to find the argument of the mean of all of the points on the line? Nov 26 '15 at 23:57
• Wow, this is far shorter than I expected answers to be, nice job! Nov 26 '15 at 23:58
• @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! Nov 26 '15 at 23:58
• 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. Nov 27 '15 at 0:00
• @ThomasKwa Great idea, thanks! The accuracy is even better now and the code is a few bytes shorter=) Nov 27 '15 at 0:06

Matlab, 86 77 bytes

Here's another way using Matlab:

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!

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

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

• Nice, this is interesting. You may want to ask on meta how to score labview programs. Nov 27 '15 at 15:35
• there already is a thread on how to score but unfortunatly there is no answer yet Nov 27 '15 at 15:36
• Oh, I see. I just edited your post to make the byte count more understandable to us in the US of A. Nov 27 '15 at 15:39
• @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? Nov 27 '15 at 17:04
• Hehehe, I forgot you guys have , for decimal places. Nov 27 '15 at 17:48
{"ft_lang_label":"__label__en","ft_lang_prob":0.7888597,"math_prob":0.81005675,"size":1222,"snap":"2022-05-2022-21","text_gpt3_token_len":319,"char_repetition_ratio":0.17980295,"word_repetition_ratio":0.018604651,"special_character_ratio":0.2888707,"punctuation_ratio":0.109311745,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9654512,"pos_list":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16],"im_url_duplicate_count":[null,5,null,5,null,5,null,5,null,5,null,5,null,5,null,5,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2022-01-20T21:39:45Z\",\"WARC-Record-ID\":\"<urn:uuid:075c3935-0e99-4d9c-8340-bdcae7a43202>\",\"Content-Length\":\"213754\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:1e39837d-4739-47ff-b81e-bb459fc962bc>\",\"WARC-Concurrent-To\":\"<urn:uuid:e29adf68-d5af-4e4f-8063-85992014cc60>\",\"WARC-IP-Address\":\"151.101.65.69\",\"WARC-Target-URI\":\"https://codegolf.stackexchange.com/questions/64929/what-is-that-angle/64935#64935\",\"WARC-Payload-Digest\":\"sha1:524COPBCOGVQKDBDED6V5366KA34KRSI\",\"WARC-Block-Digest\":\"sha1:R6KYDFEKE5WF6LZLXWB7ZFG3SNKMJBDB\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2022/CC-MAIN-2022-05/CC-MAIN-2022-05_segments_1642320302622.39_warc_CC-MAIN-20220120190514-20220120220514-00078.warc.gz\"}"}