kwg / InfiniteArtGallery

Infinite Art Gallery is a game that uses established methods of evolving art with Compositional Pattern Producing Networks (CPPNs) to allow users to explore a world of art tailored to their preferences.
https://people.southwestern.edu/~schrum2/SCOPE/iag.php
3 stars 0 forks source link

Investigate Red/White/Black bias in artworks #83

Closed kwg closed 5 years ago

kwg commented 5 years ago

Art is being very similar in colors... makes me think that we are not ranging the values for HSV correctly. Investigate this range for Color(f, f, f, f) in Unity and then compare to code.

kwg commented 5 years ago

@schrum2 This is "working" now. we should talk about it. There are no right ways to do this, and my solution has trade-offs, however test so far has shown good results. We can keep this change for the study or we can shelve it and explore it later. I have some other ideas I want to test out on this topic after the study, so I will leave this issue open until we decide what to do about it.

schrum2 commented 5 years ago

If you are just doing what I did in the MM-NEAT Java code, then I'm not sure why there would be a difference or problem ... unless some of the low-level Color library commands you are using in C# are different than what Java has in a meaningful way.

Still, I suppose results are what matter most. I don't know when I'll have time to talk about this (I have an advising appointment after Comp Org). Can you send me a code snippet of the relevant section, or link to the actual file in GitHub that I should look at? @kwg

kwg commented 5 years ago

I need to look into how/why java doesn't have this problem, but java also doesn't have the HSVToRGB step Unity needs to get the color into a state that I can change the material with, so I suspect I will start there.

code wise, this was the change I made:

    float MaxValue = float.NegativeInfinity;
    float MinValue = float.PositiveInfinity;
....
    private void GenerateImageFromCPPN()
    {
....
                float[] hsv = ProcessCPPNInput(scaledX, scaledY, distCenter, BIAS);
....
                for (int i = 0; i < 3; i++)
                {
                    MaxValue = Mathf.Max(MaxValue, hsv[i]);
                    MinValue = Mathf.Min(MinValue, hsv[i]);
                }
....
}

    private float[] FormatHSV(float[] hsv)
    {
        float[] result = new float[hsv.Length];
        float range = MaxValue - MinValue;
        for(int h = 0; h < hsv.Length; h++)
        {
            result[0] = ((hsv[0] - MinValue) / range);
            result[1] = ActivationFunctions.Activation(FTYPE.HLPIECEWISE, hsv[1]);
            result[2] = Mathf.Abs(ActivationFunctions.Activation(FTYPE.PIECEWISE, hsv[2]));
        }
        return result;
    }

Firstly, I am now formatting the HSV directly instead of after the HSVToRGB method, which clamped everything to 0..1 anyway so that was never going to work correctly. I am using the same adjustments as MM-NEAT on the saturation and the brightness values, but I changed the hue value to remap to 0..1 from a rather arbitrary guess on the previous range - but it comes out to 0..range with this method. this keeps values that are <0 or >1 from being changed to 0 and 1... we had a LOT of 0 and 1 hue values. Which after HSVToRGB, were red.

schrum2 commented 5 years ago

@kwg This is confusing to me. Are MaxValue and MinValue being calculated as the maxes and mins across the Hue, Saturation, and Brightness of a single pixel's color? That doesn't make any sense (also, please avoid the magic numbers). It is also unclear why the loop in FormatHSV even exists ... you look from 0 to hsv.Length, which is 3 right? But in the loop you directly set values for indices 0, 1, and 2 ... so what's the point of the loop in the first place?

In the MM-NEAT code ( https://github.com/schrum2/MM-NEAT/blob/master/src/main/java/edu/southwestern/util/graphics/GraphicsUtil.java ), the getHSBFromCPPN method calls the CPPN to process the inputs and immediately sends the outputs to rangeRestrictHSB. At this point, the output of the CPPN (which could be any activation function output, most of which are already bound to [-1,1], but not all) is clipped by FullLinearPiecewiseFunction.fullLinear. Why not just do this? This happens before any color range conversions that would mess up the range, so it should be fine to do this.

kwg commented 5 years ago

MM-NEAT rangeRestrictHSB Method, 15th generation, static seed, ID only artwork_4_not_selected negative values are treated differently in unity. Values outside of 0..1 are treated as HDR data if HDR is enabled

"Ranged" method (with above errors corrected), 15th generation, static seed, ID only artwork_4_not_selected lowest hue value becomes 0, highest becomes 1, all in between are scaled accordingly

ABS(MM-NEAT rangeRestrictHSB) method, 15th generation, static seed, ID only artwork_4_not_selected no more negative values causing issues, but values over 1 have become 1, compressing the color change area and turning the remaining color area to red. also visible is 0 as ABS() reflects the values

kwg commented 5 years ago

in reference to the unneeded loop and other issues with the ranged method, that was the product of a few hours of changing and rerunning to test the method and a lot of junk needed cleaned out. The loop was from an attempt to scale all of the values and just zombied along. The min/max over all values was from an attempt to add more variation to the color range... anyway, I slept since then and all those have been fixed now.

Side note: the only change in the three above images was the range restriction method used for hue. Same seed, same path/selections. S and V were not changed. I am saving the outputs from each of those tests to look at later.

schrum2 commented 5 years ago

The second/middle result looks the best, with one caveat: is it still possible for stark black lines to appear, as they do in the 1st and 3rd examples? It is important to retain this ability (I think that this is primarily caused by the use of absolute value on Brightness, but want to check). The third example looks pretty good too, but we don't want to have a systematic bias toward red.

We're at a point where we just have to pick something I guess, but I think the middle result will work.

kwg commented 5 years ago

Using the ranged method: examples of deep blackness artwork_4_not_selected

artwork_4_not_selected

this one makes me think we should verify the output on the brightness values artwork_3_not_selected

artwork_4_not_selected

kwg commented 5 years ago

artwork and sculptures are set to use the ranged method

closing issue for prototype build. We can open a new one for continued work if we want to investigate this further.