Algorithm challenge: Generate color scheme from an image

前端 未结 11 1798
猫巷女王i
猫巷女王i 2020-12-02 05:02

Background

So, I\'m working on a fresh iteration of a web app. And, we\'ve found that our users are obsessed with being lazy. Really lazy. In fact, the more wor

11条回答
  •  感情败类
    2020-12-02 05:28

    1. Divide the screen image into a grid of r-many rectangles, in an n by m "grid", each with width (total width / n) and height (total height / m).

      1a. Assign a weight to high-profile areas of the screen, such as the left-off-center area.

      1b. For each rectangle, assign the pixels into a space of (color,frequency)

    2. For each rectangle R, frequency distribution f_R, and weight W_R:

      2a. Determine the i-th scheme color (e.g. i = 1 <--> background color) by scanning the "top frequency", "second frequency" (i.e. f_R[i,:]) for each block.

      2b. For each i, put it in a score table, (color_i,score) where score = f_R[i,"frequency"] * W_R

      2c. The top scorer for each i will be the i-th scheme color.

    Theoretically, if you have a lot of "blue on white" or "red on black", you should get white primary, blue secondary, or black primary, red secondary, for example.

    For your text color, either base this directly on a calculation off of background color, or choose secondary color, and if the V difference of HSV is too low, base the color off of the computed scheme color, but augment the V value.

    PseudoCode:

    float[][] weights = 
        { { 1.0, 3.0, 5.0, 5.0, 3.0, 1.0, 1.0, 1.0, 1.0 },
          { 2.0, 6.0, 7.0, 7.0, 6.0, 2.0, 3.0, 3.0, 2.0 },
          { 2.0, 8.0, 9.0, 9.0, 7.0, 3.0, 6.0, 6.0, 3.0 },
          { 2.0, 8.0, 9.0, 9.0, 7.0, 2.0, 3.0, 3.0, 2.0 },
          { 2.0, 7.0, 9.0, 9.0, 7.0, 2.0, 1.0, 1.0, 1.0 },
          { 2.0, 6.0, 7.0, 7.0, 6.0, 2.0, 3.0, 3.0, 1.0 },
          { 1.0, 3.0, 5.0, 5.0, 3.0, 2.0, 6.0, 6.0, 2.0 },
          { 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 6.0, 6.0, 2.0 },
          { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 3.0, 3.0, 1.0 } };
    
    // Leave the following implementations to the imagination:
    void DivideImageIntoRegions( Image originalImage, out Image[][] regions );
    void GetNthMostCommonColorInRegion( Image region, int n, out Color color );
    TKey FindMaximum( Map map );
    
    // The method:
    Color[] GetPrimaryScheme( Image image, int ncolors, int M = 9, int N = 9 )
    {
        Color[] scheme = new Color[ncolors];
        Image[][] regions = new Image[M][N];
    
        DivideImageIntoRegions( image, regions );
    
        for( int i = 0; i < ncolors; i++ )
        {
            Map colorScores = new Map();
    
            for( int m = 0; m < M; m++ )
            for( int n = 0; n < N; n++ )
            {
                Color theColor;
                GetNthMostCommonColorInRegion( region, i, theColor );
    
                if( colorScores[theColor] == null )
                { colorScores[theColor] = 0; }
    
                colorScores[theColor] += weights[m][n];
            }
    
            scheme[i] = FindMaximum( colorScores );
        }
    
        return scheme;
    }
    

    Looking at the above, it's clear that if there is a region with little variability, it will have the same second-most-common color as most-common color. To adjust, the second-most-common color in such a case might be null, which one could guard against:

                if( theColor != null )
                    continue;
    
                if( colorScores[theColor] == null )
                { colorScores[theColor] = 0; }
    
                colorScores[theColor] += weights[m][n];
            }
    

提交回复
热议问题