Camera on the fly filter

Hi, i am a newbie here. Testing the camera demo app. Is it possible to add filters on the fly? Like showing black and white image, or only red channel.?
Thanks

Yes you can. Using shaders is one way, but since you’re a newbie you probably don’t have shader experience. I don’t have time right now to go into more detail but you can do a forum search to see what you can find.

EDIT: Try a forum search for camera filters.

No, although I’m sure someone has probably written code for that kind of thing.

Having said that, check out the blend function, discussion here
https://codea.io/talk/discussion/4989/blendmodes

And code here
https://gist.github.com/anonymous/6b42853df4823cd326ba

If blend doesn’t do it, you will probably need to use a shader to do fast pixel manipulation. You can get some help with that if you post your exact requirements.

@aamato Here’s something to play with.

EDIT: Made some changes to the code.
EDIT: Changed the way rgb is averaged.

function setup() 
    parameter.number("red",0,1,0)
    parameter.number("green",0,1,0)
    parameter.number("blue",0,1,0)
    parameter.integer("grey",0,1,0)
    m=mesh()
    m:addRect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
    m:setColors(color(255,255,255))
    m.shader=shader(DefaultShader.vertexShader,DefaultShader.fragmentShader)
end

function draw() 
    background(40, 40, 50) 
    img=image(CAMERA)
    if img~=nil then
        collectgarbage()
        m.texture=img 
        m.shader.red=red 
        m.shader.green=green 
        m.shader.blue=blue 
        m.shader.grey=grey 
        m:draw()
    end
end

DefaultShader = 
    {   vertexShader = [[
        precision highp float;
        uniform mat4 modelViewProjection;
        attribute vec4 position; 
        attribute vec4 color; 
        attribute vec2 texCoord;
        varying vec4 vColor; 
        varying vec2 vTexCoord;
        void main() 
        {   vColor=color;
            vTexCoord = texCoord;
            gl_Position = modelViewProjection * position;
        }    ]],

        fragmentShader = [[
        precision highp float;
        uniform sampler2D texture;
        varying vec4 vColor; 
        varying vec2 vTexCoord;
        uniform float red;
        uniform float green;
        uniform float blue;
        uniform float grey;   
        void main() 
        {   vec4 col = texture2D( texture, vTexCoord) * vColor;
            col.r=col.r+red-green-blue;        // changed
            col.g=col.g+green-red-blue;      // changed
            col.b=col.b+blue-red-green;      // changed
            if (grey == 1.0)
            { float avg=0.0;
               avg=col.r*.21+col.g*.72+col.b*.07;     // changed
             //avg=(col.r+col.g+col.b)/3.0;
              col.r=avg;
              col.g=avg;
              col.b=avg;
            }
            gl_FragColor = col; 
        }    ]]
    }

@dave1707 Why can’t you use tint? It seems to work unless you need greyscale.

@MattthewLXXIII You can use tint, but like you said, greyscale doesnt give a black/white image. @aamato also wanted black and white and the shader wasn’t hard to use.

@dave1707 - averaging rgb may not be best, see here

http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/

@ignatz I changed the above code to use luminosity averaging. There was just a slight difference, but lumonisity was a little better.

:slight_smile:

@dave1707 amazing. Thank you. I am impressed with the tool, and the responsiveness of this forum. Thank everyone.

@aamato - if you substitute this shader for Dave’s, I think it may give a truer picture of the red, green or blue components of the image. Slide R,G or B values to 1 to see a colour, 0 to exclude it. B/W works as before.

DefaultShader = 
    {   vertexShader = [[
        precision highp float;
        uniform mat4 modelViewProjection;
        attribute vec4 position; 
        attribute vec4 color; 
        attribute vec2 texCoord;
        varying vec4 vColor; 
        varying vec2 vTexCoord;
        void main() 
        {   vColor=color;
            vTexCoord = texCoord;
            gl_Position = modelViewProjection * position;
        }    ]],

        fragmentShader = [[
        precision highp float;
        uniform sampler2D texture;
        varying vec4 vColor; 
        varying vec2 vTexCoord;
        uniform float red;
        uniform float green;
        uniform float blue;
        uniform float grey;   
        void main() 
        {   vec4 col = texture2D( texture, vTexCoord) * vColor*vec4(red,green,blue,1);
            if (grey == 1.0)
            { float avg=0.0;
               avg=col.r*.21+col.g*.72+col.b*.07;     // changed
             //avg=(col.r+col.g+col.b)/3.0;
              col.r=avg;
              col.g=avg;
              col.b=avg;
            }
            gl_FragColor = col; 
        }    ]]
    }

Amazing people. thanks. Working with img=image(CAMERA) is it possible to add text or an overlay image in the front of the camera?

Of course.

Just do that at the end of the draw function, after drawing the camera image (which is a static image so you can draw over it).

@aamato In my code above, the img from the camera is updated 60 times per second. Since that is constantly changing, you can’t draw on that image itself. You can draw on the screen so it looks like you’re drawing on the image, but once you move the camera, you’ll still have what you drew on the screen, but the camera image will be different. If you want to actually draw on the camera image, then the above code will have to change.

@aamato Here’s an example of a program that will let you capture an image and then draw on it. Move the camera around until you get the image you want, double tap the screen to capture the image, then draw on the image.

displayMode(FULLSCREEN)

function setup() 
    tab={}
end

function draw() 
    background(40, 40, 50) 
    fill(255)
    if img~=nil then
        sprite(img,WIDTH/2,HEIGHT/2)
    end
    if not done then
        text("Double tap the screen to capture an image.",WIDTH/2,HEIGHT-20)
        img=image(CAMERA)
        collectgarbage()
    end
    for a,b in pairs(tab) do
        ellipse(b.x,b.y,15)
    end
end

function touched(t)
    if t.state==BEGAN and t.tapCount==2 and not done then
        img=image(CAMERA)
        done=true
    end
    if t.state==MOVING and done then
        table.insert(tab,vec2(t.x,t.y))
    end
end

@dave1707 what do you use collectgarbage() for, and what does it mean when you call it without arguments?

@MattthewLXXIII See this link http://luatut.com/collectgarbage.html

Just so you know, you can set mesh.texture directly to CAMERA and it doesn’t need image() or garbage collection.

@John I tried CAMERA with mesh.texture without calling garbagecollection and Codea crashed after about 5 seconds.

@John Ignore the previous post. I forgot to remove the img=image(CAMERA) statement. Once I remove it, Codea ran fine.