Help needed to manually mix ARGB pixels.

edited August 2017 in Questions about Code

I'm trying to manually mix ARGB pixels and the mix is coming out rather dull.

Is there a better way to manually mix ARGB?

EDIT: I found the correct way to do this. The corrected program is down a few posts ( if anyone is interested in the method).

PImage A, B,C;
boolean showMix = false;
void setup(){

     size(600,600);
     A = createImage(600,600,ARGB);
     B = createImage(600,600,ARGB);
     C = createImage(600,600,ARGB);
     A.loadPixels();
     for(int i = 0; i < 300; i++){
          for(int j = 0;j < 300; j++){
               A.pixels[i * 600 + j]= 0x7FFF0000;
          }
     }
     A.updatePixels();
     B.loadPixels();
     for(int i = 150; i < 450; i++){
          for(int j = 150;j < 450; j++){
               B.pixels[i * 600 + j]= 0x7F00FF00;
          }
     } 
     B.updatePixels();  
     mix();  

}
void draw(){
     background(255);
     if(showMix)
          image(C,0,0);
     else{
          image(A,0,0);
          image(B,0,0);
     }
}
void keyPressed(){
     showMix = !showMix;
}
void mix(){
     float ba,br,bg,bb; //background a,r,g,b
     float fa,fr,fg,fb; //foreground
     float oa, or,og,ob; //output
     int a,r,g,b;
     A.loadPixels();
     B.loadPixels();
     C.loadPixels();
     for(int i = 0; i < 600;i++){
          for(int j= 0;j<600;j++){
               int index = i * 600 + j;
               ba=A.pixels[index]>>24 & 0xFF; fa=B.pixels[index]>>24 & 0xFF;
               br=A.pixels[index]>>16 & 0xFF; fr=B.pixels[index]>>16 & 0xFF;
               bg=A.pixels[index]>>8 & 0xFF; fg=B.pixels[index]>>8 & 0xFF;
               bb=A.pixels[index] & 0xFF; fb=B.pixels[index] & 0xFF;
               ba/=255;fa/=255;      //convert alpha to 0.0 - 1.0
               oa = fa + ba *(1.0-fa);
               or = (fr * fa) + ( br*ba*(1.0-fa) );
               og = (fg * fa) + ( bg*ba*(1.0-fa) );
               ob = (fb * fa) + ( bb*ba*(1.0-fa) );
               oa *= 255;  // convert to 0-255
               a=Math.round(oa); r=Math.round(or); g=Math.round(og); b=Math.round(ob);               
               C.pixels[index]= a<<24|r<<16|g<<8|b;
          }  
     }
     C.updatePixels();
}   

Answers

  • Assuming you want red and green to mix to yellow rather then brown
    convert A and B to HSB
    mix them the way you're doing it now,
    convert A and B back to RGB

  • I am working on shader functions that can be very useful for these sorts of thing where your'e looping through lots of pixels.

    https://github.com/Prince-Polka/HSB-HSV----RGB

    This is the math behind it http://www.rapidtables.com/convert/color/rgb-to-hsv.htm

    Note that hsb = hsv, but hsl is different.

    You could write java functions doing it but you're kind of re-inventing the wheel as lerpColor() exists.

    color a = 0x7FFF0000;
    color b = 0x7F00FF00;
    color c;
    color d;
    void setup(){
      colorMode(RGB);
      c=lerpColor(a,b,0.5);
      colorMode(HSB);
      d=lerpColor(a,b,0.5);
      fill(a);
      rect(0,0,50,50);
      fill(b);
      rect(50,50,50,50);
      fill(c);
      rect(50,0,50,50);
      fill(d);
      rect(0,50,50,50);
    }
    
  • edited August 2017

    Thanks for the response. I'm going to give it a try. The problem I see is processing is not displaying the alpha as I mix it or how I expect. Changing color modes might fix it.

    I tried another technique. I have a drawing routine that works great when mixing colors on an opaque white canvas. I tried using that same routine and stripping away the white and using what was taken away to create the alpha. If it worked, I could place the white stripped image over a white background and it would look like the original. I could place it over any other image and it should look mixed with the other image. But it doesn't work when displaying the images with:

    image( A,0,0);
    image(B,0,0);
    

    If you had a rgb pixel that was say 255, 200, 45, I tried stripping the white by subtracting 45 from each color component and making the alpha value 45. I wind up with a ARGB pixel 45,210,155,0. That didn't work and the lower alpha pixels tend to be gray.

    I could write my own display routine to mix these pixels how I expect ( i.e., r+backgroundR,g+backgroundG, b+backgroundB ) but the alpha .png image couldn't be used elsewhere and surely my manual mixing would be much slower than image(img,0,0);

    I'm going to try the different color mode. I'll let you know.

  • edited August 2017

    I found the correct way to do this. The algorithm I was using wasn't right. I found the correct way on this site : https://www.gamedev.net/forums/topic/387607-rgba--rgba--/

    Here's the corrected test program. Edit: Since this uses floating point division, the values or the red green and blue components should be checked to make sure they are not NaN as division by 0 is possible. ( simple check and fix if( red!=red) red = 0).

    PImage A, B,C;
    boolean showMix = false;
    void setup(){
    
         size(600,600);
         A = createImage(600,600,ARGB);
         B = createImage(600,600,ARGB);
         C = createImage(600,600,ARGB);
         A.loadPixels();
         for(int i = 0; i < 300; i++){
              for(int j = 0;j < 300; j++){
                   A.pixels[i * 600 + j]= 0x7FFF0000;
              }
         }
         A.updatePixels();
         B.loadPixels();
         for(int i = 150; i < 450; i++){
              for(int j = 150;j < 450; j++){
                   B.pixels[i * 600 + j]= 0x3F00FF00;
              }
         } 
         B.updatePixels();  
         mix();  
    
    }
    void draw(){
         background(255);
         if(showMix){
              image(C,0,0);
              ellipse(150,150,30,30);
         }
         else{
              image(A,0,0);
              image(B,0,0);
         }
    }
    void keyPressed(){
         showMix = !showMix;
    }
    void mix(){
         float ba,br,bg,bb; //background a,r,g,b
         float fa,fr,fg,fb; //foreground
         float oa, or,og,ob; //output
         int a,r,g,b;
         A.loadPixels();
         B.loadPixels();
         C.loadPixels();
         for(int i = 0; i < 600;i++){
              for(int j= 0;j<600;j++){
                   int index = i * 600 + j;
                   ba=A.pixels[index]>>24 & 0xFF; fa=B.pixels[index]>>24 & 0xFF;
                   br=A.pixels[index]>>16 & 0xFF; fr=B.pixels[index]>>16 & 0xFF;
                   bg=A.pixels[index]>>8 & 0xFF; fg=B.pixels[index]>>8 & 0xFF;
                   bb=A.pixels[index] & 0xFF; fb=B.pixels[index] & 0xFF;
    
                   ba /=255; fa /=255; br/=255;fr /=255;
                   bg/=255;fg/=255;bb/=255;fb/=255;
    
                   oa = 1-(1-fa)*(1-ba);
                   or = (ba *(1-fa)*br + fa* fr)/oa;
                   og = (ba *(1-fa)*bg + fa* fg)/oa;
                   ob = (ba *(1-fa)*bb + fa* fb)/oa;
    
                   oa *=255;or *=255;og *=255; ob *=255;
    
                   C.pixels[index]= (int)oa<<24|(int)or<<16|(int)og<<8|(int)ob;
              }  
         }
         C.updatePixels();
    }   
    
Sign In or Register to comment.