processing_计算图像的梯度与切向,并用箭头和流线表示
标签(空格分隔): java\processing
1、彩色图像转灰色
将RGB三个色彩转变成一样的即可。
void bgrTogray(){
for(int i=0;i<p1.width;i++){
for(int j=0;j<p1.height;j++){
int xy = i + p1.width * j;
float r = red(p1.pixels[xy]);
float g = green(p1.pixels[xy]);
float b = blue(p1.pixels[xy]);
int mix = int(r * 0.299f + g * 0.587f + b * 0.114f);
if(mix>255)mix = 255;
color c1 = color(mix,mix,mix);
p1.pixels[xy] = c1;
}
}
}
效果:
2、计算灰度图像的梯度场与切线场。
遍历整幅图像,用和上一行对应点的灰度值之查和右边点的灰度值之查的来代表该点的一个梯度向量(△x,△y),然后根据两直线垂直可以得到切线长的向量(-△y,△x)。
代码:
void calculateTangrads(){
for(int i=0;i<grads.size();i++){
ArrayList a = (ArrayList)grads.get(i);
float temc = (float)a.get(0);
float temp2 = (float)a.get(1);
ArrayList b = new ArrayList();
b.add(-temp2);
b.add(temc);
tangrads.add(b);
}
}
void calculateGrads(){
for(int i=0;i<c.height;i++){
if(i == c.height - 1){ // copy
for(int k = 0;k<c.width;k++){
grads.add(grads.get( (i-1)*c.width + k ));
}
break;
}
for(int j=0;j<c.width;j++){
int xy = j + c.width * i;
int x1y = j + 1 +c.width * i;
int xy1 = j + c.width * (i + 1);
if( j == c.width - 1){ //copy the last list
grads.add(grads.get(grads.size()-1));
continue;
}
ArrayList a = new ArrayList();
float g_x = red(c.pixels[x1y]) - red(c.pixels[xy]);
float g_y = red(c.pixels[xy1]) - red(c.pixels[xy]);
a.add(g_x);a.add(g_y);
grads.add(a);
}
}
value++;
}
3、用箭头表示梯度场和切线场
直线好画,知道点及其对应向量,可以画出一段从该点出发的向量。关键是如何画箭头。这里我的想法是通过求出三个点,然后根据三个点画一个三角形代表箭头。
那么三个点如何选取呢?第一个点是向量的末端点,第二、第三个点是在垂直于向量的直线上找到的关于向量对称的两个点。
代码:
//draw arrow of a vetor
void drawTriangle(float x1,float y1,float x2,float y2){
float detx = x2 - x1;float dety = y2 - y1;
float x3,y3; // one point on the line x1/y1 x2/y2
float length = sqrt(detx*detx + dety*dety);
float interval_distance = length/10.0f; // distance
x3 = x2 - interval_distance * (detx / length);
y3 = y2 - interval_distance * (dety / length);
float cx,cy,p2x,p2y;
cx = x3 - interval_distance * (-dety / length);
cy = y3 - interval_distance * ( detx / length);
p2x = x3 + interval_distance * (-dety / length);
p2y = y3 + interval_distance * ( detx / length);
triangle(x2, y2, cx, cy, p2x, p2y);
}
效果:
4、用流线表示切线场
流线主要运用切向量场,随机选定图片上一个点,画出它的切向量,再取切向量末端点的切向量,继续画下去,直到画出图像或者切向量为零向量或者达到一定的步数。
代码:
void seed(){
for(int i=0;i<num_max;i++){
ArrayList pos = new ArrayList();
float randomx = random(0,c.width-1);
float randomy = random(0,c.height-1);
pos = (ArrayList)(tangrads.get(((int)randomx + (int)randomy * c.width)));
drawStreamLine(pos,randomx,randomy);
}
}
//draw stream line
void drawStreamLine(ArrayList seed,float x,float y){
ArrayList oldpos = new ArrayList();
ArrayList pos = new ArrayList();
oldpos.add(x);oldpos.add(y);
pos.add(x);pos.add(y);
int maxstep = 1000;
float step = 0.1f;
stroke(255,0,0);
noFill();
beginShape();
int n = 0;
while(n<= maxstep)
{
vertex((float)pos.get(0), (float)pos.get(1));
if((float)seed.get(0) == 0.0f &&(float)seed.get(1) == 0.0f) break;
ArrayList newpos = new ArrayList();
float newx = (float)oldpos.get(0) + (float)seed.get(0) * step;
float newy = (float)oldpos.get(1) + (float)seed.get(1) * step;
if(newx<0||newx>c.width-1||newy<0||newy>c.height-1) break;
seed = (ArrayList)tangrads.get(((int)newx + c.width * (int)newy));
newpos.add(newx);newpos.add(newy);
pos = newpos;
oldpos = pos;
n++;
}
endShape();
}
效果: