ofImage: How to toggle between grayscale and colored

Hi, I’m trying to toggle an image between grayscale and colored by key press.
I could change the image to grayscale but I could not get back to colored mode.
Could this be a bug? Here’s my test code below.

//--------------------------------------------------------------
void ofApp::setup(){
    
    image.load("image.jpg");
}
//--------------------------------------------------------------
void ofApp::draw(){

    image.draw(0, 0, ofGetWidth(), ofGetHeight());
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

    if (key == 'g')
        image.setImageType(OF_IMAGE_GRAYSCALE);
    else if (key == 'c')
        image.setImageType(OF_IMAGE_COLOR);
    else if (key == 'a')
        image.setImageType(OF_IMAGE_COLOR_ALPHA);
}

I don’t think so there’s a way back to do it after setting to OF_IMAGE_GRAYSCALE.

You can do something like this:

 //--------------------------------------------------------------
void ofApp::setup(){
    image.load("image.jpg");
    imageClone.clone(image);
}
//--------------------------------------------------------------
void ofApp::draw(){
    imageClone.draw(0, 0);
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){

if (key == 'g') {
	imageClone.clone(image);
	imageClone.setImageType(OF_IMAGE_GRAYSCALE);
}
else if (key == 'c') {
	imageClone.clone(image);
	imageClone.setImageType(OF_IMAGE_COLOR);
}
else if (key == 'a') {
	imageClone.clone(image);
	imageClone.setImageType(OF_IMAGE_COLOR_ALPHA);
}
}

Thanks for your suggestion but I don’t want to make unnecessary copy if possible.

If it is not a bug, what is the reason for it being able to change to grayscale but can’t get back to colored mode using ofImage::setImageType? Shouldn’t it be consistent?

you can use shader to acheive it

#define GLSL(version, shader)  "#version " #version "\n" #shader
ofImage image;
ofShader shader;
int bnw = 0;

void ofApp::setup(){
    ofDisableArbTex();
    
    image.load("image.jpg");
    
    std::string vert = GLSL(120,
        varying vec2 texCoord;
        void main(){
            gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
            texCoord = gl_MultiTexCoord0.xy;
        }
    );
    std::string frag = GLSL(120,
        uniform sampler2D image;
        uniform int bnw;
        varying vec2 texCoord;
        void main(){
            vec2 texCoord90 = vec2((texCoord.x-.5),texCoord.y-.5)*mat2(cos(1.5708),sin(1.5708),-sin(1.5708),cos(1.5708));
            texCoord90 += vec2(.5);
            vec3 c = bnw == 0 ? texture2D(image, texCoord90).rgb : texture2D(image, texCoord90).ggg;
            gl_FragColor = vec4(c, 1.);
        }
    );
    shader.setupShaderFromSource(GL_VERTEX_SHADER, vert);
    shader.setupShaderFromSource(GL_FRAGMENT_SHADER, frag);
    shader.linkProgram();
}

void ofApp::draw(){
    shader.begin();
    {
        shader.setUniformTexture("image", image.getTexture(), 0);
        shader.setUniform1i("bnw", bnw);
    
        float _w = image.getWidth(), _h = image.getHeight();
        glBegin(GL_QUADS);
        {
            glVertex3f( 0,  0, 0), glTexCoord2f(  0,   0);
            glVertex3f( 0, _h, 0), glTexCoord2f(  0, 1.f);
            glVertex3f(_w, _h, 0), glTexCoord2f(1.f, 1.f);
            glVertex3f(_w,  0, 0), glTexCoord2f(1.f,   0);
        }
        glEnd();
    }
    shader.end();
}

void ofApp::keyReleased(int key){
    if(key == '1')
        bnw = 0;
    else if(key == '2')
        bnw = 1;
}

I had to rotate uv by following code in fragment shader to show the image right, but not sure why I have to. Perhaps, I’m doing in a wrong order when I added verticies & texcoords in draw loop?

vec2 texCoord90 = vec2((texCoord.x-.5),texCoord.y-.5)*mat2(cos(1.5708),sin(1.5708),-sin(1.5708),cos(1.5708));
            texCoord90 += vec2(.5);
1 Like

Hi,
First of all I would like to say that I am not an expert in this area and I am trying to learn something also. I took a look to setImageType() method and it is related to some FreeImage_ methods.
For example setImageType(OF_IMAGE_GRAYSCALE) calls FreeImage_ConvertToGreyscale().

As you can see here:


FreeImage_ConvertToGreyscale() - converts a bitmap to a 8-bit greyscale image with a linear ramp.

I think information are compressed here and we can’t bring them back. But I can be wrong :slight_smile:
regards

1 Like

yeah we are loosing information when you convert to grayscale. it’s the same like in photoshop, if you take a color image and make it grayscale, you can’t make it color again with the original color information – it will just be color but with exact same values for red green and blue so it looks grayscale, which is similar to what you are seeing here – you are loosing info on color->grayscale conversion and when you convert back it now looks like grayscale (but is color).

3 Likes

That makes sense. Thank you so much @zach