Upgoat or Downgoat?

  • Given an image of a goat, your program should best try to identify whether the goat is upside down, or not.



    Examples



    These are examples of what the input may be. Not actual inputs



    Input:


    Downgoat



    Output:
    Downgoat



    Spec



    Your program should be at most 30,000 bytes




    • The input will contain the full goat

    • The picture will always contain a goat

    • If the goat is upside down, output Downgoat, otherwise Upgoat



    Input will be however you can take an image as an input (file name, base64 of the image, etc.)



    Don't rely on the image name or other metadata for containing "Upgoat" or "Downgoat" as the gist file names are just for reference.






    Please don't hardcode. It's boring, I can't enforce it completely but I can ask nicely.



    Test Cases



    Gist with images. images beginning with downgoat have Downgoat output and images beginning with upgoat have Upgoat output.



    Second Batch of Test Cases
    Make sure to test your images on all the test cases. These images are a jpgs. The image sizes do vary but not by that much.






    Note: A few test cases may be added before accepting an answer to avoid answers which hardcode and to check the general performance of the program.



    Bonus points for getting my avatar correct :P



    Scoring



    Score is a percent which can be calculated by: (number_correct / total) * 100


    Does "fitting" count as hard-coding?

    @NickT what do you mean by "fitting"?

    @Downgoat coming up parameters for a model (equation) that outputs if the goat is facing the correct way. By "*"fitting"*" I mean fitting the model to the entire data set, versus some training set.

    @NickT Well if it does comply with the rules you *can* post it. Though I will be adding a third batch of test cases and if your answer wouldn't handle different test cases too well I would advise against it (i.e. hardcoding).

    I'm curious to see how these solutions will handle two goats in one picture.

    Just noticed the github's captcha when creating a new account is basically this question

  • A Simmons

    A Simmons Correct answer

    5 years ago

    Mathematica, 100%, 141 bytes


    [email protected]_:=Count[1>0]@Table[ImageInstanceQ[x,"caprine animal",RecognitionThreshold->i/100],{i,0,50}];If[[email protected]#>[email protected]@#,"Up","Down"]<>"goat"&

    Well, this feels more than a little like cheating. It's also incredibly slow as well as being very silly. Function f sees roughly how high you can set the Recognition threshold in one of Mathematica's computer vision builtins, and still recognise the image as a Caprine animal.


    We then see whether the image or the flipped image is more goaty. Works on your profile image only because tie is broken in favour of downgoat. There are probably loads of ways this could be improved including asking it if the image represents Bovids or other generalisations of the Caprine animal entity type.


    Answer as written scores 100% for the first testing set and 94% for the second testing set, as the algorithm yields an inconclusive result for goat 1. This can be raised back up to 100% at the expense of an even longer computational time by testing more values of RecognitionThreshold. Raising from 100 to 1000 sufficies; for some reason Mathematica thinks that's a very ungoaty image! Changing the recognition entity from Caprine animal to Hoofed Mammal also seems to work.


    Ungolfed:


    goatness[image_] := Count[
    Table[
    ImageInstanceQ[
    image, Entity["Concept", "CaprineAnimal::4p79r"],
    RecognitionThreshold -> threshold
    ],
    {threshold, 0, 0.5, 0.01}
    ],
    True
    ]

    Function[{image},
    StringJoin[
    If[goatness[image] > goatness[ImageReflect[image]],
    "Up",
    "Down"
    ],
    "goat"
    ]
    ]



    Alternative solution, 100% + bonus


    g[t_][i_] := ImageInstanceQ[i, "caprine animal", RecognitionThreshold -> t]
    f[i_, l_: 0, u_: 1] := Module[{m = (2 l + u)/3, r},
    r = g[m] /@ {i, [email protected]};
    If[Equal @@ r,
    If[[email protected], f[i, m, u], f[i, l, m]],
    If[[email protected], "Up", "Down"] <> "goat"
    ]
    ]

    This one uses the same strategy as before, but with a binary search over the threshold. There are two functions involved here:



    • g[t] returns whether or not its argument is a goaty image with threshold t.

    • f takes three parameters: an image, and an upper and lower bound on the threshold. It is recursive; it works by testing a threshold m between the upper and lower thresholds (biased towards the lower). If the image and the reflected image are both goaty or non-goaty, it eliminates the lower or upper part of the range as appropriate and calls itself again. Otherwise, if one image is goaty and the other is non-goaty, it returns Upgoat if the first image is goaty and Downgoat otherwise (if the second, reflected image is goaty).


    The function definitions deserves a little explanation. First, function application is left-associative. This means that something like g[x][y] is interpreted as (g[x])[y]; "the result of g[x] applied to y."


    Second, assignment in Mathematica is roughly equivalent to defining a replacement rule. That is, f[x_] := x^2 does not mean "declare a function named f with parameter x that returns x^2;" its meaning is closer to, "whenever you see something like f[ ... ], call the thing inside x and replace the whole thing with x^2."


    Putting these two together, we can see that the definition of g is telling Mathematica to replace any expression of the form (g[ ... ])[ ... ] with the right-hand side of the assignment.


    When Mathematica encounters the expression g[m] (in the second line of f), it sees that the expression does not match any rules that it knows and leaves it unchanged. Then it matches the Map operator /@, whose arguments are g[m] and the list {i, [email protected]}. (/@ is infix notation; this expression is exactly equivalent to Map[g[m], { ... }].) The Map is replaced by applying its first argument to each element of its second argument, so we get {(g[m])[i], (g[m])[ ... ]}. Now Mathematica sees that each element matches the definition of g and does the replacement.


    In this way we got g to act like a function that returns another function; that is, it acts roughly like we wrote:


    g[t_] := Function[{i}, ImageInstanceQ[i, "caprine animal", RecognitionThreshold -> t]]

    (Except in this case g[t] on its own evaluates to a Function, whereas before g[t] on its own was not transformed at all.)


    The final trick I use is an optional pattern. The pattern l_ : 0 means "match any expression and make it available as l, or match nothing and make 0 available as l." So, if you call f[i] with one argument (the image to test) it is as if you had called f[i, 0, 1].


    Here is the test harness I used:


    gist = Import["https://api.github.com/gists/3fb94bfaa7364ccdd8e2", "JSON"];
    {names, urls} = Transpose[{"filename", "raw_url"} /. Last /@ ("files" /. gist)];
    images = Import /@ urls;
    result = f /@ images
    [email protected][StringContainsQ[##, IgnoreCase -> True] &, {names, result}]
    (* {{True, 18}} *)

    user = "items" /.
    Import["https://api.stackexchange.com/2.2/users/40695?site=codegolf", "JSON"];
    pic = Import[First["profile_image" /. user]];
    name = First["display_name" /. user];
    name == [email protected]
    (* True *)

    Mathematica has a builtin for determining goats. I don't know how to feel about that.

    Whaaat O.o there's a builtin for *this*.... Wow...

    You've goat to be kidding me...

    Really impressive. I had tried to exploit the asymmetry from the species detected, but failed.

    +1 for Mathematica being able to see which image is "more goaty".

    This is positively ridiculous. +1.

    How does this program respond to two goats in one image?

    Welcome to Mathematica, where there is quite literally, a built-in for everything!

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM