I managed to come up with a basic way to implement this with the video playback functionality offered in the Vuforia SDK. Here's a snippet of the OpenGL ES shader code that I used:
static const char videoPlaybackFragmentShader[] = "#extension GL_OES_EGL_image_external : require \n" "precision mediump float; \n" "uniform samplerExternalOES texSamplerOES; \n" " varying vec2 texCoord;\n" " varying vec2 texdim0;\n" " void main()\n\n" " {\n" " vec3 keying_color = vec3(%f, %f, %f);\n" " float thresh = 0.8; // [0, 1.732]\n" " float slope = 0.2; // [0, 1]\n" " vec3 input_color = texture2D(texSamplerOES, texCoord).rgb;\n" " float d = abs(length(abs(keying_color.rgb - input_color.rgb)));\n" " float edge0 = thresh * (1.0 - slope);\n" " float alpha = smoothstep(edge0, thresh, d);\n" " gl_FragColor = vec4(input_color, alpha);\n" " }";UPDATE: I forgot to add I also needed to run these commands in order for the fragment shader above to work:
glDepthFunc(GL_LEQUAL); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
UPDATE #2: 2013/04/04:
Some people were reporting they had problems with their video content turning black. Re-reading this article I realised I'd missed out the vertex shader code as well so here it is. If I recall rightly, the variable "texCoord" that is used in the fragment shader must have the same name as in the vertex shader. Using the sample Video Playback app with the Vuforia SDK, if there are any problems with compiling your shader source code then there'll be some errors printed in LogCat that you can use to help debug.
static const char* videoPlaybackVertexShader = "attribute vec4 vertexPosition; \n" "attribute vec4 vertexNormal; \n" "attribute vec2 vertexTexCoord; \n" "varying vec2 texCoord; \n" "varying vec4 normal; \n" "uniform mat4 modelViewProjectionMatrix; \n" "void main() \n" "{ \n" " gl_Position = modelViewProjectionMatrix * vertexPosition; \n" " normal = vertexNormal; \n" " texCoord = vertexTexCoord; \n" "} \n";In the VideoPlayback sample code, then in VideoPlayback.cpp, inside the renderFrame() function I inserted these 3 lines above all the calls to SampleUtils::scalePoseMatrix. For those of you who have studied the source code of the Video Playback project that can be downloaded with the Vuforia SDK you can see this is a modified version the source code for the fragment shader for the video frames. What it does is, for any colour that is close to the specified colour that is processed by the fragment shader (any pixel to render on the screen from rasterization), that colour will be made transparent by modifying its alpha channel. The same code can be used for the keyframe's fragment shader too. Notice I have 3 %fs. These, in order, are the RGB values of the colour to chroma key - i.e. to make transparent. I used sprintf to replace the string with actual float values. Note the range of these numbers is 0.0-1.0. They're float numbers, not the integer range you often see of 0-255.
Unfortunately I don't have a project I can share this time as the source code I originally implemented this in is mixed in with other code I'm not able to release publicly.
To be a little more adventurous and dynamic you could consider implementing a function to dynamically change the value of the colour that is made transparent on-the-fly using a colour picker dialog or some other input method. Other input methods could be a text input field for the 0x RGB value or a different kind of colour picker like the ones often found in paint programs where the user touches a part of the screen and the colour value of that pixel is read in as the input. This would be handy so users could just touch the area of the background they want to remove and it would automatically detect the colour.
Splendid code you have there..
ReplyDeleteBut unfortunately it isn't working for me.. The video either becomes black or stays the same..
Hi. How are you setting the value of keying_color? Are you using sprintf? If so try hardcoding a value, for example white, so you'll have:
Delete" vec3 keying_color = vec3(1.0, 1.0, 1.0);\n"
Most videos will have some degree of white in them so if this works then you'll have patchy transparent areas.
Oh! I just recalled, I forgot I also had to run some extra gl* commands. I'll update the blog article so read above! Sorry about that ;-)
hi soliax,
Deletethanks a lot for your code, its works well,
but my one prblm is that if i set vec3 keying_color = vec3(0.21, 0.71, 0.29);
///green
then it also make transparent the black shadows in video,
what could be reason for that ? plz help..
i had success with vec3(0.0, 1.0, 0.0);
DeleteThis comment has been removed by the author.
DeleteThis comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeletegreat work sollax, appreciate it :)
ReplyDeleteThis is working correctly for me but, when I press "play" on the video, the background (camera stream) and the part of video that I'm filtering (all that have green color) becomes black...do you have any idea about how to solve it ?
ReplyDeleteThanks in advance
I got this problem too. any way to solve it?
DeleteI added UPDATE #2. I'm not sure if this will solve your problems but compare the vertex shader source codes and also check LogCat for any compile time problems OpenGL might be having trying to load your shaders.
ReplyDeleteHi, your program is great. I managed it work now. sorry, I am very new to GL and Android.
ReplyDeletethe tricks to Danno's problem, I got it work after I add some "cleaning" code:
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
so after glEnable(GL_BLEND), you must disable it. or you will see anything else is black
Worked perfectly! After line QCAR::Renderer::getInstance().end();, at the end of the function Java_com_qualcomm_QCARSamples_VideoPlayback_VideoPlaybackRenderer_renderFrame
DeleteThnk you so much you and Sollax, great code.
Thanks alot for your reply, I'm going to test in the next days your solution and will give you a feedback.
ReplyDeleteI've just added:
ReplyDeleteglDepthFunc(GL_LESS);
glDisable(GL_BLEND);
at the end of "renderFrameQCAR" function (as last comment says), followed Sollax instructions and it's all working perfectly.
Thanks alot!
Note: I didn't tested yet what Sollax says in "UPDATE #2: 2013/04/04", but it's all working good anyway !
Hi, I'm trying to apply this on iOS, but I have a "glError (0x502)" runtime error, if I comment :
ReplyDelete#extension GL_OES_EGL_image_external : require
and
uniform samplerExternalOES texSamplerOES;
the error disapear, but the video still with the color I want to remove.
Any idea?
Thanks!
Hi,
DeleteThe error 0x502 is the OpenGL error for INVALID OPERATION. OES is required in order to play videos on a surface with Vuforia, so my best guess is your phone's OpenGL is too old to support this. From my experience only Android 4 and above support this feature.
Can you solve the problem?? I have the same issue and i can´t solve it!!
DeleteHi soliax,
ReplyDeleteI made my project in unity. and it works with shaders. but when i tried to use with vuforia it doesnt work. Video just disappeared. I googled and iam here. Honestly i didnt understood your solition.
Could you pls share your project source? That would be so helpful for me.
Thanks for nice tutorial, have a nice day.
Sorry but the project is a commerical product so I can't release the source code.
ReplyDeletehi soliax, can you help me to show the code that can make my 3d object transparent ? i'm using ImageTarget sample by vuforia.
ReplyDeletethanks before,
denmasmr
Hi, great article, thanks.
ReplyDeleteIm interested in the Vuforia video playback tool, and im not a developer . do you happen know which iOS app i can download to test this feature and see how the video playback is working in the Vuforia sdk ?
I have used other AR platforms and now would like to check this one
Thanks
Lior
I don't know of any iOS apps like that sorry.
DeleteThanks Soliax...this worked like a charm on Android.
ReplyDeleteSo it works fine for me when I hard-code the keying colors. Would appreciate if you can provide some pointers on where to look for help on making it dynamic like you mentioned in the last paragraph. I understand we use %f to accept the value as input at runtime, but how do I pass this value to my VideoPlaybackFragmentShader? Any help would be appreciated.
ReplyDeleteExactly what i want to do but seems Vuforia does not support Webcam! :(
ReplyDeletehi soliax,
ReplyDeletethanks a lot for your code, its works well,
but my one prblm is that if i set vec3 keying_color = vec3(0.21, 0.71, 0.29);
///green
then it also make transparent the black shadows in video,
what could be reason for that ? plz help..
Hi Soliax,
ReplyDeleteCan we do frame animation using Vuforia SDK..
Hi,
ReplyDeleteI'm facing the following problem:
extension 'GL_OES_EGL_image_external' is not supported
what could be reason for that ? help
Hi, How to implement this is in Unity?
ReplyDeletehttps://unexpectedend.wordpress.com/2014/11/04/unity3d-chroma-key-shader/
DeleteHi Soliax!!Thanks for the code, its work for me on android device, but I dont know how integrate it on ios device. Can you help me?
ReplyDeletehi frenando..
Deletewhere you use this code either u use to make shader or to add this code in videoplaybackbehavior script
]
Hello is this still working in unity vuforia ?
ReplyDeleteIs it still working?
ReplyDeleteCan you please write it
ReplyDeletefor iOS too?
Please share the shader file for iOS too,i have implemented the same using the above code,but i get gl error
ReplyDeletewhere to use this is code in videoplaybackbehaviour or to create/make a shader and use its material.
ReplyDeleteplz tell
tengo la misma duda... solucionaste?
Deletecompartís el código modificado a gabriel.gar@hotmail.com.ar.
ReplyDeletesaludos
How can I use chromakey live on vuforia?
ReplyDelete