Change one colour from a PNG to another one

edited January 2016 in Programming Questions

hello! I have PNG with transparency, green, and white I will like to be able to change the green to another colour and the white for another.

I imagine it will go something like this

PImage myImage = loadImage("apples.jpg");
image(myImage, 0, 0);

loadPixels();
get () green pixel
change green pixel to  x pixel
get () white pixel
change white pixel to  y pixel
updatePixels();

I am a bit confuse on how to proceed between loadPixels(); and updatePixels(); if it the right way, any help will be appreciated.

Answers

  • Answer ✓

    You need to use a loop to look at each pixel in your image in turn. If you're looking at a pixel and it's green, store a different color in that pixel instead. Or if the pixel you are looking at is white, store a different color in that pixel.

    This process translates almost directly into code.

    for( int i=0; i<pixels.length; i++){ // Look at each pixel.
      if( pixels[i] == color(0,255,0){ // If it's green,
        pixels[i] = color(255,0,0); // turn it into red.
      }
    }
    

    I'll leave changing the white ones up to you.

  • edited January 2016
    /**
     * SwapPixelColor (v1.11)
     * GoToLoop (2015-Jul-29)
     *
     * forum.Processing.org/two/discussion/14352/
     * change-one-colour-from-a-png-to-another-one
     *
     * forum.Processing.org/two/discussion/11880/
     * how-can-i-speed-up-this-basic-image-processing-code
     */
    
    static final String URL = "http://" + "www.TfGuy44.com/people/i/Tr.jpg";
    
    PImage original, swapped;
    boolean isSwapped;
    
    void setup() {
      if (original == null)  original = loadImage(URL);
    
      getSurface().setSize(original.width, original.height); // P3
      //size(original.width, original.height); // P2 & P1
    
      noLoop();
      frameRate(10);
    
      swapped = swapPixelColor(original.get(), 0, #FFFF00);
    }
    
    void draw() {
      background(isSwapped? swapped : original);
    }
    
    void mousePressed() {
      isSwapped ^= redraw = true;
    }
    
    void keyPressed() {
      mousePressed();
    }
    
    static final PImage swapPixelColor(PImage img, color old, color now) {
      old &= ~#000000;
      now &= ~#000000;
    
      img.loadPixels();
      color p[] = img.pixels, i = p.length;
    
      while (i-- != 0)  if ((p[i] & ~#000000) == old)  p[i] = p[i] & #000000 | now;
    
      img.updatePixels();
      return img;
    }
    
  • Cool image. :))

  • edited January 2016

    Already knew that pic was from your own site. This is an old sketch after all: :))

    http://forum.Processing.org/two/discussion/11880/how-can-i-speed-up-this-basic-image-processing-code

  • Thanks! TFguy44 the code work good, but it is missing some pixel. I have changed the original colour to black colour (00, 00, 00) I imagine that some pixel on the edge is not exactly the same number. Is there an easy way to get all the colour near black, it is the same thing with the white? I imagine that if I have a better contrast in colour it will be easy to change for others.

  • Answer ✓

    all the colour near black

    sounds like a job for dist()...

  • Koogs, I have looked at dist() function but I do not think it is the good function. When I said all the colour near black I do not tall near in terms of distance but near in terms of colour. how to change the pixel that is not pure black (0,0,0)

    float ImgColOrg= get all the color between (color(0), color(10,10,10);
     int ImgChCol = colarray[3];
    
    loadPixels();
      for ( int i=0; I<pixels.length; i++) { // Look at each pixel.
        if ( pixels[I] == color (ImgColOrg)) { // If it's black,
          pixels[I] = color(ImgChCol2); // turn it into red.
        }
      }
      updatePixels();
    

    hope it better to understand.

  • edited January 2016 Answer ✓

    If you consider the red, green and blue components of a color as coordinates in a 3d-space, you could use dist to calculate the distance betwen colors.

    int col1 = #ffffff;
    int col2 = #eeeeee;
    
    println(dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2)));
    

    and if that distance is below a certain treshold, you can exchange the color.

  • Benja, I am not able to find a way to get.

    and if that distance is below a certain treshold, you can exchange the color.

    int col1 = color(0, 0, 0);
      int col2 = color(10, 10, 10);
      float DcolB = dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2));
    
    int ImgColOrg= color(col1)< color (col1+DcolB);  //I do not find good formulation to use the DcolB
     int ImgChCol1 = colarray[3];
    
    loadPixels();
      for ( int i=0; i<pixels.length; i++) { // Look at each pixel.
        if ( pixels[i] == color(ImgColOrg)) { 
          pixels[i] = color(ImgChCol1); 
        }
      }
    updatePixels();
    

    I feel confused on how to use the number I get. 8-}

  • You want to include a colour if its distance is within a certain threshold. So just

    if (DcolB < threshold)
    

    will do.

    Hint: don't start variables with upper case letters, you'll just confuse people. Go read the Java naming conventions.

  • edited January 2016

    But you need to calculate the distance for every pixel so it needs to be inside the loop.

  • I still need help. I imagine it needs to be added here. loadPixels(); for ( int i=0; i<pixels.length; i++) { // Look at each pixel. if ( pixels[i] == color(col1)) { // If it's color 1 or near pixels[i] = color(imgChCol1); // turn it into red. } } updatePixels();

    How do I mix col1 with if (dcolB < threshold) do I need to make If () { if()}} if inside an if Or I create an If inside col1

    Thanks to let me know about Java naming conventions, I will have a look..

  • Colors that are similar have about the same amount of red, green, and blue in them.

    Here is a red color: color(255,0,0) Here is an almost red color: color(200,30,30) Here is a black color: color(0,0,0)

    How "far apart" from each other are these colors? If you treat the red, green, and blue values like x, y, and z co-ordinates, your colors can be treated like points in space. And you can determine how far apart they are using dist():

    dist(x1,y1,z1,x2,y2,z2)
    

    The red and almost red colors are fairly "close". The red and black colors are not. By using a threshold and a conditional statement, you can do certain code for colors that are close to a given color.

    You can get the red, green, and blue values from a color by using red(), green(), and blue(). Look again at benja's 4th line of code.

  • edited January 2016

    if i do this int col1 = color(0, 0, 0); int col2 = color(10, 10, 10); float dcolB = dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2));

        println(dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2)));
    

    That print the number 17.320509 Thit number is the distance between the color 1 and 2 or it convert to a color like this float dcolB = color(dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2)));

  • edited January 2016

    here, screenshot to let you see the problem

    Screen Shot 2016-01-11 at 23.07.33

    and also a small problem. i get this on the screen, Screen Shot 2016-01-11 at 23.07.22 but if i use saveFrame(); it do not save the color change screen-0011

  • Can you format your code please. Highlight it, hit ctrl-o.

  • if i do this

    int col1 = color(0, 0, 0); 
    int col2 = color(10, 10, 10); 
    float dcolB = dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2));
    println(dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2)));
    

    That print the number 17.320509. Thit number is the distance between the color 1 and 2. Or i can convert to a color like this

    float dcolB = color(dist(red(col1), green(col1), blue(col1), red(col2), green(col2), blue(col2)));

  • Answer ✓

    No, the example was only to show how you could find the distance between two colors. You can use that value (i.e. 17) as your threshold.

    What you want to do is test all pixels from an image against your color (i.e. white) and replace it with a second color, if the distance between your first color and the current pixel-color is lower than your desired threshold.

    int col1 = #ffffff;  // color that shall be replaced
    int col2 = #ff0000;  // color to use for replacement
    float treshold = 30;
    PImage img;
    
    void setup() {
      size(400, 300);
    
      // load an image
      img = loadImage("http://"+"www.exploreoneida.com/wp-content/uploads/frog.jpg");
    
    
      img.loadPixels();
    
      // iterate over all pixels
      for ( int i=0; i<img.pixels.length; i++) { 
    
        // cet color from current pixel
        int curPix = img.pixels[i];
    
        // calculate distance
        float colDist = dist(red(col1), green(col1), blue(col1), red(curPix), green(curPix), blue(curPix));
    
        // replace with second color if distance below treshold
        if ( colDist <= treshold) { 
          img.pixels[i] = col2;
        }
      }
    
      img.updatePixels();
    
      image(img, 0, 0);
    }
    
  • Thanks Benja, it works. I don’t think I will have been able to figure all by myself but when I see it, I understand it.

    But this code change brings other problems. Is it better if continue here on this tread or make a new one for a new problem?

    now I try to mix the benja code with https://forum.processing.org/one/topic/combine-two-pimages-into-one.html

     PGraphics output = createGraphics(1600, 1000, JAVA2D);
          output.beginDraw();
          ImagePosition(); // this function place and change size randomly
          ImagePosition();
          ImagePosition();
          output.endDraw();
    
          output.loadPixels();
    
          // iterate over all pixels
    for ( int i=0; I<output.pixels.length; i++) { 
    
            // cet color from current pixel
    int curPix = output.pixels[I];
    
            // calculate distance
    float colDist = dist(red(col1), green(col1), blue(col1), red(curPix), green(curPix), blue(curPix));
    
            // replace with second color if distance below treshold
    if ( colDist <= treshold) { 
              output.pixels[I] = imgChCol2;
            }
          }
    
          output.updatePixels();
    

    But the color change do not apply. Maybe it will be better to understand if you have the complete code?

  • for ( int i=0; I<output.pixels.length; i++) {

    i != I, variables are case sensitive

    and how are you saving the image? because that snippet only updates the offscreen PImage, 'output', not the visible image.

Sign In or Register to comment.