Creating a linear gradient in 2D array

前端 未结 4 1181
北海茫月
北海茫月 2021-02-06 13:05

I have a 2D bitmap-like array of let\'s say 500*500 values. I\'m trying to create a linear gradient on the array, so the resulting bitmap would look something like this (in gray

相关标签:
4条回答
  • 2021-02-06 13:21

    In your example image, it looks like you have a radial gradient. Here's my impromtu math explanation for the steps you'll need. Sorry for the math, the other answers are better in terms of implementation.

    1. Define a linear function (like y = x + 1) with the domain (i.e. x) being from the colour you want to start with to the colour your want to end with. You can think of this in terms of a range the within Ox0 to OxFFFFFF (for 24 bit colour). If you want to handle things like brightness, you'll have to do some tricks with the range (i.e. the y value).
    2. Next you need to map a vector across the matrix you have, as this defines the direction that the colours will change in. Also, the colour values defined by your linear function will be assigned at each point along the vector. The start and end point of the vector also define the min and max of the domain in 1. You can think of the vector as one line of your gradient.
    3. For each cell in the matrix, colours can be assigned a value from the vector where a perpendicular line from the cell intersects the vector. See the diagram below where c is the position of the cell and . is the the point of intersection. If you pretend that the colour at . is Red, then that's what you'll assign to the cell.
                 |
                 c
                 |
                 |
        Vect:____.______________
                 |
                 |
    
    
    0 讨论(0)
  • 2021-02-06 13:28

    This is really a math question, so it might be debatable whether it really "belongs" on Stack Overflow, but anyway: you need to project the coordinates of each point in the image onto the axis of your gradient and use that coordinate to determine the color.

    Mathematically, what I mean is:

    1. Say your starting point is (x1, y1) and your ending point is (x2, y2)
    2. Compute A = (x2 - x1) and B = (y2 - y1)
    3. Calculate C1 = A * x1 + B * y1 for the starting point and C2 = A * x2 + B * y2 for the ending point (C2 should be larger than C1)
    4. For each point in the image, calculate C = A * x + B * y
    5. If C <= C1, use the starting color; if C >= C2, use the ending color; otherwise, use a weighted average:

      (start_color * (C2 - C) + end_color * (C - C1))/(C2 - C1)

    I did some quick tests to check that this basically worked.

    0 讨论(0)
  • 2021-02-06 13:33

    There are two parts to this problem.

    1. Given two colors A and B and some percentage p, determine what color lies p 'percent of the way' from A to B.

    2. Given a point on a plane, find the orthogonal projection of that point onto a given line.

    The given line in part 2 is your gradient line. Given any point P, project it onto the gradient line. Let's say its projection is R. Then figure out how far R is from the starting point of your gradient segment, as a percentage of the length of the gradient segment. Use this percentage in your function from part 1 above. That's the color P should be.

    Note that, contrary to what other people have said, you can't just view your colors as regular numbers in your function from part 1. That will almost certainly not do what you want. What you do depends on the color space you are using. If you want an RGB gradient, then you have to look at the red, green, and blue color components separately.

    For example, if you want a color "halfway between" pure red and blue, then in hex notation you are dealing with

    ff 00 00

    and

    00 00 ff

    Probably the color you want is something like

    80 00 80

    which is a nice purple color. You have to average out each color component separately. If you try to just average the hex numbers 0xff0000 and 0x0000ff directly, you get 0x7F807F, which is a medium gray. I'm guessing this explains at least part of the problem with your picture above.

    Alternatively if you are in the HSV color space, you may want to adjust the hue component only, and leave the others as they are.

    0 讨论(0)
  • 2021-02-06 13:35

    I'll just post my solution.

    int ColourAt( int x, int y )
    {
      float imageX = (float)x / (float)BUFFER_WIDTH;
      float imageY = (float)y / (float)BUFFER_WIDTH;
    
      float xS = xStart / (float)BUFFER_WIDTH;
      float yS = yStart / (float)BUFFER_WIDTH;
      float xE = xEnd / (float)BUFFER_WIDTH;
      float yE = yEnd / (float)BUFFER_WIDTH;
      float xD = xE - xS;
      float yD = yE - yS;
    
      float mod = 1.0f / ( xD * xD + yD * yD );
    
      float gradPos = ( ( imageX - xS ) * xD + ( imageY - yS ) * yD ) * mod;
    
      float mag = gradPos > 0 ? gradPos < 1.0f ? gradPos : 1.0f : 0.0f;
    
      int colour = (int)( 255 * mag );
      colour |= ( colour << 16 ) + ( colour << 8 );
      return colour;
    }
    

    For speed ups, cache the derived "direction" values (hint: premultiply by the mag).

    0 讨论(0)
提交回复
热议问题