Working with one color channel

Helllo. I need to work with color blue channel from RGB video frame. I’d like to iterate over it later. How can I get blue channel as the integer array?

void ofApp::update(){
    camera.update();
    if (camera.isFrameNew()) {
        pixelData = camera.getPixels().getData();
        int blueIndex = 2;
        for (int i = 0; i < 480; i++) {
            for (int j = 0; j < 640; j++) {
                blue = pixelData[blueIndex];
                std::cout << blue << std::endl;
                blueIndex += 3;
            }
        }
    }
}

This is what I tried to do by myself. Thank you up front.

Hi,
Hopefully this example helps

    ofPixels p;
    p.allocate(10, 10, 3);
    p.setColor(ofColor::black);
    p.setColor(0, 0, ofColor::white);
    p.setColor(1, 0, ofColor::red);
    p.setColor(2, 0, ofColor::blue);
    
    auto d = p.getData();
    for(int y=0; y<p.getWidth(); y++){ // Check all channels
        for(int x=0; x<p.getHeight(); x++){
            for(int c=0; c<3; c++){
                int index = c + (x*3) + (y*(3*10));
                cout << (int)d[index] << ", ";
            }
            cout << endl;
        }
    }
    
    for(int y=0; y<p.getWidth(); y++){ // Check blue channel
        for(int x=0; x<p.getHeight(); x++){
            int index = 2 + (x*3) + (y*(3*10)); // The 2 gets the blue channel
            cout << (int)d[index] << endl;
        }
    }

Unfortunately not, because when I try to access pixels from camera (ofVideoGrabber) I get only 0. I think there’s some kind of problem with getPixels().getData().

Hmm are you seeing the camera when you draw it to the screen?
It might be you need to set a different device id ( see top of the following example )

Here is a complete example which shows you also how to grab just the blue channel as an ofPixels object and load it to a b&w texture.

#include "ofApp.h"

ofVideoGrabber camera;
ofTexture singleChannelTex;

//--------------------------------------------------------------
void ofApp::setup(){
	camera.listDevices();
	camera.setDeviceID(0);
	camera.initGrabber(640, 480);
}

//--------------------------------------------------------------
void ofApp::update(){
	camera.update();
	if (camera.isFrameNew()) {
	
		auto pixels = camera.getPixels();
		
		//you can also just grab the blue channel like this
		auto bluePixels = pixels.getChannel(2); //0 = red, 1 = green, 2 = blue
		
		int index = 0;
		int indexRgb = 2;
		
		for (int i = 0; i < bluePixels.getHeight(); i++) {
			for (int j = 0; j < bluePixels.getWidth(); j++) {

				int blueToo = pixels[indexRgb];
				
				//can work with the blue channel this way too
				int blue = bluePixels[index];

				//comment this out if you want realtime performance 
				cout << " blue pixel in rgb array is " << blueToo << " from single channel bluePixels "<< blue << endl;
			
				index++;
				indexRgb+=3;
			}
		}
		
		singleChannelTex.loadData(bluePixels);
	}
	
}

//--------------------------------------------------------------
void ofApp::draw(){
	ofSetColor(255);
	camera.draw(0, 0);
	singleChannelTex.draw(camera.getWidth(), 0);
}
2 Likes

Still isn’t working. I can see the picture from camera (both rgb and blue) but both variables blue and blueToo are still 0, I can see it in debugger.

I’m thinking things are working just fine if you can see the images of the camera and singleChannelTex on the screen. If there were a problem, you would not see one or the other or both. Can you see the camera and the ofTexture singleChannelText?

Edit: I just ran Theo’s code from above and it works great if I comment out this line:

    cout << " blue pixel in rgb array is " << blueToo << " from single channel bluePixels "<< blue << endl;

Yes, this part works, but what I need to do is iterating over the unsigned char array, I need blue pixels values - this part doesn’t work because the variables contains 0. There’s everything in screenshots.
https://drive.google.com/drive/folders/1Vj0WIJe2PkgAy_FOJsqbU1t87ET-SO6c?usp=sharing

Maybe add a member to ofApp to capture the values. Here’s one that stores the values for the blue channel in an ofPixels object, and then prints the first and last values in the application window:

#include "ofApp.h"

ofVideoGrabber videoGrabber;
ofPixels bluePixels;
ofTexture singleChannelTex;
//--------------------------------------------------------------
void ofApp::setup(){
    int width = 640;
    int height = 480;
    videoGrabber.initGrabber(width, height);
    bluePixels.allocate(width, height, 1);
}
//--------------------------------------------------------------
void ofApp::update(){
    videoGrabber.update();
    if(videoGrabber.isFrameNew()) {
        bluePixels = videoGrabber.getPixels().getChannel(2);
        singleChannelTex.loadData(bluePixels);
    }
}
//--------------------------------------------------------------
void ofApp::draw(){
    singleChannelTex.draw(0.f, 0.f);
    int firstValue = bluePixels[0];
    int num = bluePixels.size();
    int lastValue = bluePixels[num - 1];
    ofDrawBitmapStringHighlight("0: " + ofToString(firstValue), 20.f, 20.f);
    ofDrawBitmapStringHighlight("num: " + ofToString(num) + " : " + ofToString(lastValue), 20.f, 40.f);
}