Get just one channel of RGB photos?

Hello,

I’m stuck…

If I have an RGB image how to I display just the red channel (or just the blue, or green)?

If I wanted to show a combination of two channels is there a faster way (faster as in computer speed) to show that combination?

Thanks,

–Darin

1 Like

you mean like this?

hm, try

   img.pixels[i] = color(green(c),0,red(c));
1 Like

Hi,

If speed is really one of your concern, you can also use bit shifting to get the RGB values:

For red: float r2 = c >> 16 & 0xFF;
For green: float r2 = c >> 8 & 0xFF;
For blue: float b2 = c & 0xFF;

Of course you can find that on the reference page:
https://processing.org/reference/

I guess you meant: int g = c >> 8 & 0xff; :thinking:

1 Like

Thanks jb4x and thank GoToLoop for the correction.

O.K., fast is good.

Can you expand on exactly what is happening here? I’m a photographer not a programmer so much. :slight_smile:

I understand that I have a color (in c) that is twenty-four bits long. I understand that each of the three primaries is represented by eight of those bits, thus twenty-four total.

I also get the basic idea that I can use 0xFF (which I know is hexadecimal, which I understand is base 16, but I don’t use it enough to really be comfortable using it other than cutting and pasting). And so I also see (but don’t really full understand) that we are using 0xFF in some way to look at just the last eight bits of c, and so with blue we just look at them, with the other colors we shift the bits rightward the so the last eight bits are then green, then red, looking at each in turn.

So I can use what you are saying no problem at all but I don’t really feel I’m 100% understanding it. Can anyone step me through it?

Thanks,

–Darin

1 Like

Oh! I’ve never used the pixels method before–now I get it, seems super useful. Thanks.

–Darin

hi, sorry, but i have a hard time to test that speed up,
any measurements with millis produce “16” or “32”
so i changed and do that job inside draw()
and show FPS
and try frameRate(120)
and still reach 105 fps in both ways,
( with a very old win7 PC )


or do i need a bigger picture ?

test a too big picture for my computer: 2500x1250.jpg // 8 fps / 8 fps

possibly the byte coding speed improvement is just an often-copied myth


pls confirm that you have tested that.

my code using

// https://discourse.processing.org/t/get-just-one-channel-of-rgb-photos/10732
// show red channel only
// compare red(c) with r2 = c >> 16 & 0xFF
// speed test measuring millis only show 16 or 32 nothing else, so switch to FPS show

String infile = "data/sunflower.jpg";
PImage img;
int r2, g2, b2;

void setup() {
  size(510, 340);
  img = loadImage(infile);
  println("picture "+infile+" w * h "+img.width+" * "+img.height);
  frameRate(120);
}

void show() {
  img.loadPixels();
  for (int i=0; i< img.pixels.length; i++) {
    img.pixels[i] = color(red(img.pixels[i]), 0, 0);  // 105
//    img.pixels[i] = color(img.pixels[i] >> 16 & 0xFF, 0, 0);  // 105

/*
    //   img.pixels[i] = color(0,green(c),0);
    //   img.pixels[i] = color(0,0,blue(c));
    //   img.pixels[i] = color(green(c),0,red(c)); // re-mix
 
    //   r2 = c >> 16 & 0xFF;
    //   g2 = c >>  8 & 0xFF;
    //   b2 = c & 0xFF;
*/

  }
  img.updatePixels();
  image(img, 0, 0);
}

// move to draw and measure FPS
void draw() {
  surface.setTitle("my colors, FPS "+(int)frameRate+" for "+img.pixels.length+" pix");
  show();
}


but i did verify that this is slower ( 95 fps ) ( but snappy )

  for (int i=0; i< img.width; i++) for (int j=0; j< img.height; j++) img.set(color(red(img.get(i,j)),0,0),i,j);  //95

Hi @kll, this is from the reference:

The red() function is easy to use and understand, but it is slower than a technique called bit shifting.


Yep, although I did not bother to write it down I just copy-pasted the text from the green() reference.

I opened a new ticket for that.

thanks for the link,
sorry, but i can not reproduce that,
you see a mistake in my code?
but yes, i have low end hardware, but usually, that is perfect for speed tests.

actually, i am also not sure if the declaration & usage of variables costs time?
so my idea is

img.pixels[i] = color(img.pixels[i] >> 16 & 0xFF, 0, 0);

should be fastest??

but nice to read:

color c = img.pixels[i];
float r1 = red(c);
int r2 = c  >> 16 & 0xFF;
img.pixels[i] = color(r2, 0, 0);

can you suggest me a way to verify that speed difference?

Funny enough with the following test code I’m getting the bitshift technic 3% slower:

final int pixSize = 1000 * 1000;

void setup() {
  size(1000, 1000);
  background(20);

  int start, end;
  float r = 0;
  color c = 0;

  for (int k = 0; k < 100; k++) {
    loadPixels();
    start = millis();
    for (int i = 0; i < 10000; i++) {
      for (int j = 0; j < pixSize; j++) {
        c = pixels[j];
        // r = c >> 16 & 0xFF;
        r = red(c);
      }
    }
    end = millis();
    println(end - start);
  }

  rect(r, r, r, r);
}

And putting my variables global is making it 8 times slower oO:

final int pixSize = 1000 * 1000;
int start, end;
float r = 0;
color c = 0;

void setup() {
  size(1000, 1000);
  background(20);

  for (int k = 0; k < 100; k++) {
    loadPixels();
    start = millis();
    for (int i = 0; i < 10000; i++) {
      for (int j = 0; j < pixSize; j++) {
        c = pixels[j];
        // r = c >> 16 & 0xFF;
        r = red(c);
      }
    }
    end = millis();
    println(end - start);
  }

  rect(r, r, r, r);
}

For detail resulta I’m getting (in average):
312ms for red() functions and local variables
321ms for bitshifting and local variables
2626ms for red() function and global variables

I did not know that global variables could impact tht much the performance…

1 Like

and to confuse you more:

  • the color is a integer?
    so the result of a bitshift should goto integer, not real
  • the result of red is float ( need to, as you might use like colorMode(RGB,1.0); )

i changed the test little bit and make many of them,
and see the problem is actually with

c=pixels[j]

esp. if c is global color.
find my data in the respective line
and note my win7 PC is about double as slow as your hardware.
not to mention the RPI


final int pixSize = 1000 * 1000;
final int manyruns = 10000, repeat = 10;
// global vars

  long start, end, dtime, avg = 0;
  int r1 = 0;
  float r2 = 0;
  color c = 0;


void setup() {
  size(1000, 1000);
  background(20);
/*
  // local vars
  long start, end, dtime, avg = 0;
  int r1 = 0;
  float r2 = 0;
  color c = 0;
*/
  for (int k = 0; k < repeat; k++) {
    loadPixels();
    start = millis();
    for (int i = 0; i < manyruns; i++) {
      for (int j = 0; j < pixSize; j++) {  // only loop   avg 4                       ||global vars avg 5
        //c = pixels[j];                   // only c      avg 3                       ||global vars avg 6848
        //r1 = c >> 16 & 0xFF;             // int   shift avg 629 || NO c=pixels[j] 3 ||global vars avg 7176 ||globalvars NO c=pixels[j] 656
        //r2 = c >> 16 & 0xFF;             // float shift avg 632 || NO c=pixels[j] 3 ||global vars acg 7775 ||globalvars NO c=pixels[j] 640
        //r2 = red(c);                     // red         avg 626 || NO c=pixels[j] 6 ||global vars avg 8039 ||globalvars NO c=pixels[j] 643
      }
    }
    end = millis();
    dtime = end - start;
    avg += dtime;
    println("k "+k+" dtime "+dtime);
  }
  //rect(r, r, r, r);
  println("avg "+avg/repeat);
  exit();
}


update
now check again with all that features inside of draw ( and show FPS )

// https://discourse.processing.org/t/get-just-one-channel-of-rgb-photos/10732
// show red channel only
// compare red(c) with int r2 = c >> 16 & 0xFF
// check @jb4x  https://discourse.processing.org/t/get-just-one-channel-of-rgb-photos/10732/11

// add test data from run on Raspberry Pi ( RPI )

String infile = "data/sunflower.jpg";    // format 1000 * 1000 with paint
PImage img;
//color c;

void setup() {
  size(1000, 1000);
  img = loadImage(infile);
  println("picture: "+infile+" w * h "+img.width+" * "+img.height);
  frameRate(120);
}

void make_red_pixels() {
  img.loadPixels();                                             // FPS: 67
  for (int i=0; i< img.pixels.length; i++) {                    // FPS: 67
    img.pixels[i] = color(red(img.pixels[i]), 0, 0);          // FPS: 21     // RPI FPS 4
//    img.pixels[i] = color(img.pixels[i] >> 16 & 0xFF, 0, 0);  // FPS: 21
//    c = img.pixels[i];                                        // FPS: 63   // recheck on the global variable problem? NOT here
//    img.pixels[i] = color(red(c), 0, 0);                      // FPS: 21
//    img.pixels[i] = color(c >> 16 & 0xFF, 0, 0);              // FPS: 21 
    ;
  }  
  img.updatePixels();
}

void make_red_setget() {
    for (int i=0; i< img.width; i++) for (int j=0; j< img.height; j++)  img.set(i,j,color(red(img.get(i,j)),0,0));  // FPS: 15  //RPI FPS 2
}

void draw() {                                       // move to draw and measure FPS
  surface.setTitle("my colors, FPS "+(int)frameRate+" for "+img.pixels.length+" pix");
  make_red_pixels();
//  make_red_setget();
  image(img, 0, 0);                                             // FPS: 80
}


/*
       img.pixels[i] = color(0,green(c),0);
       img.pixels[i] = color(0,0,blue(c));
       img.pixels[i] = color(green(c),0,red(c)); // re-mix

  int r2, g2, b2;
 
       r2 = c >> 16 & 0xFF;
       g2 = c >>  8 & 0xFF;
       b2 = c & 0xFF;
*/


test with a 1000 * 1000 picture ( old win 7 PC and RPI )

  • a- the global variable color c problem i not see there again
  • b- the bit shift speedup v.s. red() is a myth ( or in the whole context can be neglected )
  • c- the pixels[] v.s. set ( get ) is faster like 21/80 to 15/80