Not sure this is the right forum for GLSL, let me know if not.
I am currently working on an implementation of canny to run in a shader.
I’m using the processing language.
First I produce a gaussian then a sobel. The sobel store the gradient values of each pixel in the r and g channel respectively, then the blue channel is used for the magnitude or intensity.
It works fine in java/processing code, however produces issues when the code is converted to glsl shader.
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PROCESSING_TEXTURE_SHADER;
uniform sampler2D texture;
uniform float mult;
varying vec4 vertColor;
varying vec4 vertTexCoord;
uniform vec2 resolution;
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main(void) {
float x = 1.0 / resolution.x;
float y = 1.0 / resolution.y;
float PI = 3.14159265359;
vec4 horizEdge = vec4( 0.0 );
horizEdge -= texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y - y ) ) * 1.0;
horizEdge -= texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y ) ) * 4.0;
horizEdge -= texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y + y ) ) * 1.0;
horizEdge += texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y - y ) ) * 1.0;
horizEdge += texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y ) ) * 4.0;
horizEdge += texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y + y ) ) * 1.0;
vec4 vertEdge = vec4( 0.0 );
vertEdge -= texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y - y ) ) * 1.0;
vertEdge -= texture2D( texture, vec2( vertTexCoord.x , vertTexCoord.y - y ) ) * 4.0;
vertEdge -= texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y - y ) ) * 1.0;
vertEdge += texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y + y ) ) * 1.0;
vertEdge += texture2D( texture, vec2( vertTexCoord.x , vertTexCoord.y + y ) ) * 4.0;
vertEdge += texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y + y ) ) * 1.0;
vec3 edge = sqrt((horizEdge.rgb * horizEdge.rgb) + (vertEdge.rgb * vertEdge.rgb));
float x1 = (horizEdge.r+horizEdge.g+horizEdge.b)/3.0;
float y1 = (vertEdge.r+vertEdge.g+vertEdge.b)/3.0;
float m = 0.5;
float n = 1.0;
float x2 = map(x1,0.0-m,m,0.0,n);
float y2 = map(y1,0.0-m,m,0.0,n);
float sum = (edge.r+edge.g+edge.b)/3.0;
//gl_FragColor = vec4(n-x2,n-y2,1.0-sum*mult,1.0);
gl_FragColor = vec4(x2,y2,1.0-sum*mult,1.0);
//gl_FragColor = vec4(1.0-x1,1.0-y1,1.0-sum*mult,1.0);
}
which produces this image.
I then use a canny algorithm to thin the lines, its not perfect but its ok for now.
void getNeighboursMax2(int x, int y,float t) {
boolean k = false;
int p = x + y * img.width;
float c = brightness(sobel.pixels[p]);
float g
= gradient[x][y];
//= red(sobelG.pixels[p]);
//= atan2(red(sobely.pixels[p]),red(sobelx.pixels[p]));
float q = 255;
float r = 255;
int p1 = 0;
//angle 0
if ((0 <= g && g < (22.5))){
if((x+1)+(y)*img.width<img.pixels.length&&(x+1)+(y)*img.width>=0)q = brightness(sobel.pixels[(x+1)+(y)*img.width]);
if((x-1)+(y)*img.width<img.pixels.length&&(x-1)+(y)*img.width>=0)r = brightness(sobel.pixels[(x-1)+(y)*img.width]);
//angle 45
}else if ((22.5) <= g && g < (67.5)){
if((x+1)+ (y+1)*img.width<img.pixels.length&&(x+1)+ (y+1)*img.width>=0)q = brightness(sobel.pixels[(x+1)+ (y+1)*img.width]);
if((x-1)+ (y-1)*img.width<img.pixels.length&&(x-1)+ (y-1)*img.width>=0)r = brightness(sobel.pixels[(x-1)+ (y-1)*img.width]);
//angle 90
}else if ((67.5) <= g && g< (112.5)){
if((x)+ (y+1)*img.width<img.pixels.length&&(x)+ (y+1)*img.width>=0)q = brightness(sobel.pixels[(x)+ (y+1)*img.width]);
if((x)+ (y-1)*img.width<img.pixels.length&&(x)+ (y-1)*img.width>=0)r = brightness(sobel.pixels[(x)+ (y-1)*img.width]);
//angle 135
}else if ((112.5) <= g && g < (157.5)){
if((x-1)+(y+1)*img.width<img.pixels.length&&(x-1)+(y+1)*img.width>=0)q = brightness(sobel.pixels[(x-1)+(y+1)*img.width]);
if((x+1)+(y-1)*img.width<img.pixels.length&&(x+1)+(y-1)*img.width>=0)r = brightness(sobel.pixels[(x+1)+(y-1)*img.width]);
//angle 180
}else if ((157.5) <= g && g < (202.5)){
if((x-1)+(y)*img.width<img.pixels.length&&(x-1)+(y)*img.width>=0)q = brightness(sobel.pixels[(x-1)+(y)*img.width]);
if((x+1)+(y)*img.width<img.pixels.length&&(x+1)+(y)*img.width>=0)r = brightness(sobel.pixels[(x+1)+(y)*img.width]);
//angle 225
}else if ((202.5) <= g && g < (247.5)){
if((x-1)+(y-1)*img.width<img.pixels.length&&(x-1)+(y-1)*img.width>=0)q = brightness(sobel.pixels[(x-1)+(y-1)*img.width]);
if((x+1)+(y+1)*img.width<img.pixels.length&&(x+1)+(y+1)*img.width>=0)r = brightness(sobel.pixels[(x+1)+(y+1)*img.width]);
//angle 270
}else if ((247.5) <= g && g < (292.5)){
if((x-1)+(y+1)*img.width<img.pixels.length&&(x-1)+(y+1)*img.width>=0)q = brightness(sobel.pixels[(x-1)+(y+1)*img.width]);
if((x+1)+(y-1)*img.width<img.pixels.length&&(x+1)+(y-1)*img.width>=0)r = brightness(sobel.pixels[(x+1)+(y-1)*img.width]);
//angle 315
}else if ((292.5) <= g && g < (337.5)){
if((x)+(y-1)*img.width<img.pixels.length&&(x)+(y-1)*img.width>=0)q = brightness(sobel.pixels[(x)+(y-1)*img.width]);
if((x)+(y+1)*img.width<img.pixels.length&&(x)+(y+1)*img.width>=0)r = brightness(sobel.pixels[(x)+(y+1)*img.width]);
//angle 360
}else if ((337.5) <= g && g <= (360)){
if((x+1)+(y)*img.width<img.pixels.length&&(x+1)+(y)*img.width>=0)q = brightness(sobel.pixels[(x+1)+(y)*img.width]);
if((x-1)+(y)*img.width<img.pixels.length&&(x-1)+(y)*img.width>=0)r = brightness(sobel.pixels[(x-1)+(y)*img.width]);
}
//println(q,r);
if (q<t&&(brightness(sobel.pixels[x+y*img.width]) <= q) && (r<t&&brightness(sobel.pixels[x+y*img.width]) <= r)) sobelMax.pixels[x+y*img.width] = 0;
else sobelMax.pixels[x+y*img.width] = color(255);
};
and this produces the following image.
again not perfect but a great start, lines can be tweaked by changing some parameters, however when I try converting the code to a glsl shader I get issues I’m unsure how to resolve.
// Adapted from:
// <a href="http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html" target="_blank" rel="nofollow">http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html</a>
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PROCESSING_TEXTURE_SHADER;
uniform sampler2D texture;
uniform float thresh;
varying vec4 vertColor;
varying vec4 vertTexCoord;
uniform vec2 resolution;
float map(float value, float min1, float max1, float min2, float max2) {
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}
void main(void) {
float x = 1.0 / resolution.x;
float y = 1.0 / resolution.y;
float PI = 3.14159265359;
float q = 1.0;
float r = 1.0;
vec4 p1 = vec4( 0.0 );
vec4 p2 = vec4( 0.0 );
float m = 2.0;
float n = 1.0;
vec4 mCol = texture2D( texture, vec2( vertTexCoord.x, vertTexCoord.y ) );
//float x1 = map(mCol.r,0.0,m,0.0-n,n);
//float y1 = map(mCol.g,0.0,m,0.0-n,n);
float x1 = mCol.r;
float y1 = mCol.g;
float a1 = atan(y1,x1);
float myGrad = map(a1,0.0-PI,PI,0.0,360.0);
float myCol = mCol.b;
if ((0 <= myGrad && myGrad < (22.5))){
p1 = texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y ) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y ) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 45
else if ((22.5) <= myGrad && myGrad < (67.5)){
p1 = texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y + y) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y - y) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 90
else if ((67.5) <= myGrad && myGrad< (112.5)){
p1 = texture2D( texture, vec2( vertTexCoord.x, vertTexCoord.y + y) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x, vertTexCoord.y - y) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 135
else if((112.5) <= myGrad && myGrad < (157.5)){
p1 = texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y + y) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y - y) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 180
else if ((157.5) <= myGrad && myGrad < (202.5)){
p1 = texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y ) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y ) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 225
else if ((202.5) <= myGrad && myGrad < (247.5)){
p1 = texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y - y) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y + y) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 270
else if ((247.5) <= myGrad && myGrad < (292.5)){
p1 = texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y + y) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y - y) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 315
else if ((292.5) <= myGrad && myGrad < (337.5)){
p1 = texture2D( texture, vec2( vertTexCoord.x, vertTexCoord.y - y) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x, vertTexCoord.y + y) ) * 1.0;
q = p1.b;
r = p2.b;
}
//angle 360
else if ((337.5) <= myGrad && myGrad <= (360)){
p1 = texture2D( texture, vec2( vertTexCoord.x + x, vertTexCoord.y ) ) * 1.0;
p2 = texture2D( texture, vec2( vertTexCoord.x - x, vertTexCoord.y ) ) * 1.0;
q = p1.b;
r = p2.b;
}
if((r<thresh&&myCol<=r)&&(q<thresh&&myCol<=q)){
//gl_FragColor = vec4(1.0-myCol,1.0-myCol,1.0-myCol,1.0);
gl_FragColor = vec4(0.0,0.0,0.0,1.0);
}else{
gl_FragColor = vec4(1.0 ,1.0,1.0,1.0);
}
};
this produces the following output.
I’m fairly new to shaders, I’ve only been using them for a month, so I’m not sure if there is something obvious I’m missing.
Thanks in advance.
apologies I can only seem to post one image as a new user…