I am trying to achieve a fisheye effect on a BitMap image in Android. Is there an existing library or algorithm which can help?
I recommend you to use Android Media Effects API. If you want to have more control on the effect (or target older Android versions) you can also directly use opengl to apply a fisheye effect to your photo. Some tutorials on the subject : http://www.learnopengles.com/android-lesson-four-introducing-basic-texturing/ . Learning opengl will permit you to be able to apply all kind of effects to your photo, shader codes can be easily found on the internet (eg : https://github.com/BradLarson/GPUImage/tree/master/framework/Source)
Here is a shader code for a fisheye effect :
private static final String FISHEYE_FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform sampler2D u_Texture;\n" +
"uniform vec2 vScale;\n" +
"const float alpha = float(4.0 * 2.0 + 0.75);\n" +
"varying vec2 v_TexCoordinate;\n" +
"void main() {\n" +
" float bound2 = 0.25 * (vScale.x * vScale.x + vScale.y * vScale.y);\n" +
" float bound = sqrt(bound2);\n" +
" float radius = 1.15 * bound;\n" +
" float radius2 = radius * radius;\n" +
" float max_radian = 0.5 * 3.14159265 - atan(alpha / bound * sqrt(radius2 - bound2));\n" +
" float factor = bound / max_radian;\n" +
" float m_pi_2 = 1.570963;\n" +
" vec2 coord = v_TexCoordinate - vec2(0.5, 0.5);\n" +
" float dist = length(coord * vScale);\n" +
" float radian = m_pi_2 - atan(alpha * sqrt(radius2 - dist * dist), dist);\n" +
" float scalar = radian * factor / dist;\n" +
" vec2 new_coord = coord * scalar + vec2(0.5, 0.5);\n" +
" gl_FragColor = texture2D(u_Texture, new_coord);\n" +
"}\n";
Have a look at OpenCV for Android:
http://opencv.org/platforms/android.html
And this answer:
How to simulate fisheye lens effect by openCV?
Perhaps a more simple solution would be using the Android Media Effects API. It's only available from API 14 and above however.
Related
I am using https://github.com/natario1/CameraView this library for capturing a negative image to positive and it is using the openGl shaders. I need a filter in which I can capture a negative image to positive in Black & White mode not in the normal color mode (which is currently available in the library). I tried to mix the two filters i.e first capture the negative image to positive in color mode and then apply the Black & White mode filter but as I am new to openGl, I was unable to do this. Please help me in this regard. It would be highly appreciated. The shaders which I am using are as follows :
This shader is used to convert the negative to positive in color mode.
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+";\n"
+ "uniform samplerExternalOES sTexture;\n"
+ "void main() {\n"
+ " vec4 color = texture2D(sTexture, "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+");\n"
+ " float colorR = (1.0 - color.r) / 1.0;\n"
+ " float colorG = (1.0 - color.g) / 1.0;\n"
+ " float colorB = (1.0 - color.b) / 1.0;\n"
+ " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n"
+ "}\n";
This shader is used to change the normal positive image in Black & White mode.
private final static String FRAGMENT_SHADER = "#extension GL_OES_EGL_image_external : require\n"
+ "precision mediump float;\n"
+ "varying vec2 "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+";\n"
+ "uniform samplerExternalOES sTexture;\n" + "void main() {\n"
+ " vec4 color = texture2D(sTexture, "+DEFAULT_FRAGMENT_TEXTURE_COORDINATE_NAME+");\n"
+ " float colorR = (color.r + color.g + color.b) / 3.0;\n"
+ " float colorG = (color.r + color.g + color.b) / 3.0;\n"
+ " float colorB = (color.r + color.g + color.b) / 3.0;\n"
+ " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n"
+ "}\n";
Please help in making a filter which can direct capture the negative image to positive in Black & White mode.
Thanks.
You can do that with a one-liner in a single shader:
gl_FragColor = vec4(vec3(dot(1.0 - color.rgb, vec3(1.0/3.0))), color.a);
Explanation:
the inverse color is:
vec3 inverseColor = 1.0 - color.rgb;
For the gray scale there are 2 opportunities. Either straight forward
float gray = (inverseColor.r + inverseColor.g + inverseColor.b) / 3.0;
Or by using the dot product:
float gray = dot(1.0 - inverseColor.rgb, vec3(1.0/3.0));
Finally construct a vec3 from gray:
gl_FragColor = vec4(vec3(gray), color.a);
My code is
vec4 textureColor = texture2D(uTextureSampler, vTextureCoord);
if(textureColor.r* 0.299 + textureColor.g * 0.587 + textureColor.b * 0.114 < 0.1) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
} else {
gl_FragColor = vec4(textureColor.r, textureColor.g, textureColor.b, textureColor.w);
}
My problem is how to judge the pixel is black? How can I do that, should change rgb to hsv?
return "precision mediump float; \n"+
" varying highp vec2 " + VARYING_TEXTURE_COORD + ";\n" +
" \n" +
" uniform sampler2D " + TEXTURE_SAMPLER_UNIFORM + ";\n" +
" \n" +
" void main()\n" +
" {\n" +
" vec3 keying_color = vec3(0.0, 0.0, 0.0);\n" +
" float thresh = 0.45; // [0, 1.732]\n" +
" float slope = 0.1; // [0, 1]\n" +
" vec3 input_color = texture2D(" + TEXTURE_SAMPLER_UNIFORM + ", " + VARYING_TEXTURE_COORD + ").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" +
" }";
In the keying_color variable is stored the actual color we want to replace. It is using classic RGB model, but intensity is not expressed as 0-255 integer. It is a float value in range 0-1. (So 0 = 0, 255 = 0, 122 = 0.478…) In our case, the green color has value (0.647, 0.941, 0.29), but if you are using different video, measure the color yourself.
Note: Make sure you have the right color. Some color measurement software automatically converts colors to slightly different formats, such as AdobeRGB.
So where’s the magic?
We load current pixel color in the input_color, then calculate difference between input and keying color. Based on this difference, alpha value is calculated and used for specific pixel.
You can control how strict the comparison is using the slope and threshold values. It is a bit more complicated, but the most basic rule is: The more threshold you have, the bigger tolerance.
So, we are done, right? Nope.
You can look this link: http://blog.csdn.net/u012847940/article/details/47441923
I want to do a fisheye effect on android useing opengl 2.0,i can do it not use the opengl,but this not i want ,because this is inefficient and not support video texture. I also test the fisheye effect using Android Media Effects API,but the effect looks not good.
i also search fishshader as follows:
private static final String FISHEYE_FRAGMENT_SHADER =
"precision mediump float;\n" +
"uniform sampler2D u_Texture;\n" +
"uniform vec2 vScale;\n" +
"const float alpha = float(4.0 * 2.0 + 0.75);\n" +
"varying vec2 v_TexCoordinate;\n" +
"void main() {\n" +
" float bound2 = 0.25 * (vScale.x * vScale.x + vScale.y * vScale.y);\n" +
" float bound = sqrt(bound2);\n" +
" float radius = 1.15 * bound;\n" +
" float radius2 = radius * radius;\n" +
" float max_radian = 0.5 * 3.14159265 - atan(alpha / bound * sqrt(radius2 - bound2));\n" +
" float factor = bound / max_radian;\n" +
" float m_pi_2 = 1.570963;\n" +
" vec2 coord = v_TexCoordinate - vec2(0.5, 0.5);\n" +
" float dist = length(coord * vScale);\n" +
" float radian = m_pi_2 - atan(alpha * sqrt(radius2 - dist * dist), dist);\n" +
" float scalar = radian * factor / dist;\n" +
" vec2 new_coord = coord * scalar + vec2(0.5, 0.5);\n" +
" gl_FragColor = texture2D(u_Texture, new_coord);\n" +
"}\n";
this is i want to ,but i donot know how to use it .Can someone give me some clue.
Android OpenGL ES does (normally) support video textures. It's not strictly part of the OpenGL ES API, but you can normally import video surfaces as EGL External Images via Android SurfaceViews.
There are lots of similar questions on the web, but this SO question should provide a useful starting point:
Android. How play video on Surface(OpenGL)
I have a texel (rectangle) and I need to access its 4 corners.
vec2 offset = vec2(1,1)/vec2(texWidth, texHeight)
texture2D (texSource, texCoord + 0.5 * offset * ???? )
what should I fill here to get both top 2 and bottom 2 corners.?
[Edit] : Code as per Tommy's answer
" vec2 pixelSize = vec2(offsetx,offsety);\n" +
" vec2 halfPixelSize = pixelSize * vec2(0.5);\n" +
" vec2 texCoordCentre = vTextureCoord - mod(vTextureCoord, pixelSize) + halfPixelSize;\n" +
" vec2 topLeft = texCoordCentre - halfPixelSize;\n" +
" vec2 bottomRight = texCoordCentre + halfPixelSize;\n" +
" vec2 topRight = texCoordCentre + vec2(halfPixelSize.x, -halfPixelSize.y);\n" +
" vec2 bottomLeft = texCoordCentre + vec2(-halfPixelSize.x, halfPixelSize.y);\n" +
" vec4 p00 = texture2D(sTexture, topLeft);\n" +
" vec4 p02 = texture2D(sTexture, bottomRight);\n" +
" vec4 p20 = texture2D(sTexture, topRight);\n" +
" vec4 p22 = texture2D(sTexture, bottomLeft);\n" +
" vec4 pconv = 0.25*(p00 + p02 + p20 + p22);\n" +
A texture is always addressed by numbers in the range [0, 1). Taking a texel as being an individual pixel within a texture, each of those is an equal subdivision of the range [0, 1), hence if there are 16 of them the first occupies the region [0, 1/16), the next [1/16, 2/16), etc.
So the boundaries of the texel at n in a texture of size p are at n/p and n+1/p, and the four corners are at the combinations of the boundary positions for x and y.
If you have linear filtering enabled then you'll get an equal mix of the four adjoining texels by sampling at those locations; if you've got nearest filtering enabled then you'll get one of the four but be heavily subject to floating point rounding errors.
So, I think:
vec2 pixelSize = vec2(1.0) / vec2(texWidth, texHeight);
vec2 halfPixelSize = pixelSize * vec2(0.5);
vec2 texCoordCentre = texCoord - mod(texCoord, pixelSize) + halfPixelSize;
vec2 topLeft = texCoordCentre - halfPixelSize;
vec2 bottomRight = texCoordCentre + halfPixelSize;
vec2 topRight = texCoordCentre + vec2(halfPixelSize.x, -halfPixelSize.y);
vec2 bottomLeft = texCoordCentre + vec2(-halfPixelSize.x, halfPixelSize.y);
(... and if you were targeting ES 3 instead of 2, you could just use the textureSize function instead of messing about with uniforms)
I try to write a small program in OpenGL ES 2.0. But i found i quit hard to inspect the variable in shader language.
For example i want to know the value in ver vertex shader. I will pass the value to fragment shader and put the value as the Red in glFragColor. But i found it quit hard to pass the value. If i declare the value using varying, then the value will change.
Here is the code, the log is the value i want to print.
public static final String VERTEX_SHADER =
"attribute vec4 position;\n" +
"attribute vec2 inputTextureCoordinate;\n" +
"\n" +
"uniform float texelWidthOffset; \n" +
"uniform float texelHeightOffset; \n" +
"\n" +
"varying vec2 centerTextureCoordinate;\n" +
"varying vec2 oneStepLeftTextureCoordinate;\n" +
"varying vec2 twoStepsLeftTextureCoordinate;\n" +
"varying vec2 oneStepRightTextureCoordinate;\n" +
"varying vec2 twoStepsRightTextureCoordinate;\n" +
"varying float log;\n" +
"\n" +
"void main()\n" +
"{\n" +
"log = -0.1;\n" +
"gl_Position = position;\n" +
"vec2 firstOffset;\n" +
"vec2 secondOffset;\n" +
// "if (sqrt(pow(position.x, 2) + pow(position.y, 2)) < 0.2) {\n" +
// "log = -position.x;\n" +
"if (position.x < 0.3) {\n" +
"log = 0.7;\n" +
"firstOffset = vec2(3.0 * texelWidthOffset, 3.0 * texelHeightOffset);\n" +
"secondOffset = vec2(3.0 * texelWidthOffset, 3.0 * texelHeightOffset);\n" +
"} else {\n" +
"firstOffset = vec2(texelWidthOffset, texelHeightOffset);\n" +
"secondOffset = vec2(texelWidthOffset, texelHeightOffset);\n" +
"log = -0.1;\n" +
"}\n" +
"\n" +
"centerTextureCoordinate = inputTextureCoordinate;\n" +
"oneStepLeftTextureCoordinate = inputTextureCoordinate - firstOffset;\n" +
"twoStepsLeftTextureCoordinate = inputTextureCoordinate - secondOffset;\n" +
"oneStepRightTextureCoordinate = inputTextureCoordinate + firstOffset;\n" +
"twoStepsRightTextureCoordinate = inputTextureCoordinate + secondOffset;\n" +
"}\n";
public static final String FRAGMENT_SHADER =
"precision highp float;\n" +
"\n" +
"uniform sampler2D inputImageTexture;\n" +
"\n" +
"varying vec2 centerTextureCoordinate;\n" +
"varying vec2 oneStepLeftTextureCoordinate;\n" +
"varying vec2 twoStepsLeftTextureCoordinate;\n" +
"varying vec2 oneStepRightTextureCoordinate;\n" +
"varying vec2 twoStepsRightTextureCoordinate;\n" +
"varying float log;\n" +
"\n" +
"void main()\n" +
"{\n" +
"if (log != -0.1) {\n" +
"gl_FragColor.rgba = vec4(log, 0.0, 0.0, 1.0);\n" +
// "return;\n" +
// "}\n" +
"} else { \n" +
"lowp vec4 fragmentColor;\n" +
"fragmentColor = texture2D(inputImageTexture, centerTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, oneStepLeftTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, oneStepRightTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, twoStepsLeftTextureCoordinate) * 0.2;\n" +
"fragmentColor += texture2D(inputImageTexture, twoStepsRightTextureCoordinate) * 0.2;\n" +
"\n" +
"gl_FragColor = fragmentColor;\n" +
// "gl_FragColor.rgba = vec4(0.0, 1.0, 0.0, 1.0);\n" +
// "}\n" +
"}\n";
Or is there any better method to do this.
When comparing floating point values, instead of doing this :
if (log != -0.1)
You should allow a little delta/tolerance on the value to account for floating point precision and the eventual value "change" you may get from passing it as a varying.
So you should do something like :
if (abs(log - (-0.1)) >= 0.0001)
Here the 0.0001 I chosen is a bit arbitrary ... It has to be a small value ...
Another example with ==
Instead of :
if (log == 0.7)
do
if (abs(log - 0.7) <= 0.0001)
However here you probably also have another issue:
The vertex shader executes for each 3 vertex of all your triangles (or quads)
So for a specific triangle, you may set different values (-0.1 or 0.7) for log for each vertex
Now the problem is that in the fragment shader the GPU will interpolate between the 3 log values depending on which pixel it is rendering ... so in the end you can get any value in [-0.1,0.7] interval displayed on screen :-(
To avoid this kind of issue, I personally use #ifdefs in my shaders to be able to switch them between normal and debug mode, and can switch between the two with a keypress. I never try to mix normal and debug displays based on if tests, especially when the test is based on a vertex position.
So in your case I would first create a specific debug version of the shader, and then use 0.0 and 1.0 as values for log, like this what you will see are red gradients, the more red the color is, the closer you are to the case you want to test.