canny算子进行边缘检测的步骤是:
(1)使用高斯滤波器平滑图形
(2)使用一阶偏导的有限差分方程来计算梯度的赋值和方向
(3)对梯度幅值进行非极大值抑制
(4)用双阀值算法检测和连接边缘
案例:
public class ImageJAndroid3Activity extends Activity {
ImageView sourceImage;
ImageView destinationImage;
int[] data;
int[] magnitude;
int[] orientation;
int width;
int height;
int derivative_mag[];
int threshold1;
int threshold2;
int threshold=128;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1){
destinationImage.setImageBitmap((Bitmap)msg.obj);
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
sourceImage=(ImageView) findViewById(R.id.source);
destinationImage=(ImageView) findViewById(R.id.destination);
}
public void remove(View v){
new Thread(){
public void run(){
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.gg);
width=bitmap.getWidth();
height=bitmap.getHeight();
int widGaussianKernel=5;
data=new int[width*height];
bitmap.getPixels(data, 0, width, 0, 0, width, height);
magnitude=new int[width*height];
orientation=new int[width*height];
float f = 1.0F;
canny_core(f, widGaussianKernel); //生成高斯算子5
threshold1=50;
threshold2=230;
thresholding_tracker(threshold1, threshold2);//50,230
for (int i = 0; i < width*height; i++)
if (data[i] > threshold)//大于128
data[i] = 0xff000000; //为黑
else
data[i] = -1; //为白
Bitmap newBitmap=Bitmap.createBitmap(width,height,Config.RGB_565);
newBitmap.setPixels(data, 0, width, 0, 0, width, height);
Message message=Message.obtain();
message.what=1;
message.obj=newBitmap;
handler.sendMessage(message);
}
}.start();
}
private void canny_core(float f, int i) { //1.0,5.0
boolean flag = false;
boolean flag1 = false;
derivative_mag = new int[width*height];
float af4[] = new float[i]; //大小为5
float af5[] = new float[i];
float af6[] = new float[i];
image2pixels(); //将data中数据变成灰度数据
int k4 = 0;//k4最大为4
do {
if (k4 >= i) //进行5次
break;
float f1 = gaussian(k4, f); //e(0/2),e(-1/2),e(-4/2),e(-9/2),e(-16/2),
if (f1 <= 0.005F && k4 >= 2)//?
break;
float f2 = gaussian((float) k4 - 0.5F, f); //生成5个
float f3 = gaussian((float) k4 + 0.5F, f);
float f4 = gaussian(k4, f * 0.5F);//k4,0.5f
af4[k4] = (f1 + f2 + f3) / 3F / (6.283185F * f * f);
af5[k4] = f3 - f2;
af6[k4] = 1.6F * f4 - f1;
k4++;
} while (true);
int j = k4; //k4为4
float af[] = new float[width*height]; //计算af[]
float af1[] = new float[width*height]; //计算af1[]
int j1 = width - (j - 1); //width-3
int l = width * (j - 1); //width*3
int i1 = width * (height - (j - 1)); //width*(height-3)
for (int l4 = j - 1; l4 < j1; l4++) {//3,width-3
for (int l5 = l; l5 < i1; l5 += width) { //width*3,width*(height-3)
int k1 = l4 + l5;
float f8 = (float) data[k1] * af4[0];
float f10 = f8;
int l6 = 1;
int k7 = k1 - width;//l4+l5-width
for (int i8 = k1 + width; l6 < j; i8 += width) { //l6小于4,并且每次i8相加width
f8 += af4[l6] * (float) (data[k7] + data[i8]);
f10 += af4[l6] * (float) (data[k1 - l6] + data[k1 + l6]);
l6++; //只能循环3
k7 -= width;
}
af[k1] = f8;
af1[k1] = f10;
}
}
float af2[] = new float[width*height]; //计算af2[]
for (int i5 = j - 1; i5 < j1; i5++) {
for (int i6 = l; i6 < i1; i6 += width) {
float f9 = 0.0F;
int l1 = i5 + i6;
for (int i7 = 1; i7 < j; i7++)
f9 += af5[i7] * (af[l1 - i7] - af[l1 + i7]);
af2[l1] = f9;
}
}
af = null;
float af3[] = new float[width*height]; //计算af3[]
for (int j5 = k4; j5 < width - k4; j5++) {
for (int j6 = l; j6 < i1; j6 += width) {
float f11 = 0.0F;
int i2 = j5 + j6;
int j7 = 1;
for (int l7 = width; j7 < j; l7 += width) {
f11 += af5[j7] * (af1[i2 - l7] - af1[i2 + l7]);
j7++;
}
af3[i2] = f11;
}
}
af1 = null;
j1 = width - j;
l = width * j;
i1 = width * (height - j);
for (int k5 = j; k5 < j1; k5++) {
for (int k6 = l; k6 < i1; k6 += width) {
int j2 = k5 + k6;
int k2 = j2 - width;
int l2 = j2 + width;
int i3 = j2 - 1;
int j3 = j2 + 1;
int k3 = k2 - 1;
int l3 = k2 + 1;
int i4 = l2 - 1;
int j4 = l2 + 1;
float f6 = af2[j2];
float f7 = af3[j2];
float f12 = hypotenuse(f6, f7);
int k = (int) ((double) f12 * 20D);
derivative_mag[j2] = k >= 256 ? 255 : k; //初始化dervative[]数组,大小为面积
float f13 = hypotenuse(af2[k2], af3[k2]);
float f14 = hypotenuse(af2[l2], af3[l2]);
float f15 = hypotenuse(af2[i3], af3[i3]);
float f16 = hypotenuse(af2[j3], af3[j3]);
float f18 = hypotenuse(af2[l3], af3[l3]);
float f20 = hypotenuse(af2[j4], af3[j4]);
float f19 = hypotenuse(af2[i4], af3[i4]);
float f17 = hypotenuse(af2[k3], af3[k3]);
float f5;
if (f6 * f7 <= (float) 0
? Math.abs(f6) >= Math.abs(f7)
? (f5 = Math.abs(f6 * f12))
>= Math.abs(f7 * f18 - (f6 + f7) * f16)
&& f5
> Math.abs(f7 * f19 - (f6 + f7) * f15) : (
f5 = Math.abs(f7 * f12))
>= Math.abs(f6 * f18 - (f7 + f6) * f13)
&& f5
> Math.abs(f6 * f19 - (f7 + f6) * f14) : Math.abs(f6)
>= Math.abs(f7)
? (f5 = Math.abs(f6 * f12))
>= Math.abs(f7 * f20 + (f6 - f7) * f16)
&& f5
> Math.abs(f7 * f17 + (f6 - f7) * f15) : (
f5 = Math.abs(f7 * f12))
>= Math.abs(f6 * f20 + (f7 - f6) * f14)
&& f5 > Math.abs(f6 * f17 + (f7 - f6) * f13)) {
magnitude[j2] = derivative_mag[j2]; //初始化magnitude[],大小我面积
orientation[j2] = (int) (Math.atan2(f7, f6) * (double) 40F); //初始化orientation[]大小为面积
}
}
}
derivative_mag = null;
af2 = null;
af3 = null;
}
//将data中数据变成灰度数据
public void image2pixels(){
for(int y=0;y<height;y++){
for(int x=0;x<width;x++){
int a=data[y*width+x]>>24&0xff;
int red=data[y*width+x]>>16&0xff;
int green=data[y*width+x]>>8&0xff;
int blue=data[y*width+x]&0xff;
int grey=(int)(0.299 * red + 0.587 * green+ 0.114 * blue);
data[y*width+x]=a<<24|grey<<16|grey<<8|grey;
}
}
}
//返回高斯数据
private float gaussian(float f, float f1) {
return (float) Math.exp((-f * f) / ((float) 2 * f1 * f1));
}
//hypotenuse方法
private float hypotenuse(float f, float f1) {
if (f == 0.0F && f1 == 0.0F)
return 0.0F;
else
return (float) Math.sqrt(f * f + f1 * f1);
}
private void thresholding_tracker(int i, int j) {
for (int k = 0; k < width*height; k++)
data[k] = 0; //初始化
for (int l = 0; l < width; l++) {
for (int i1 = 0; i1 < height; i1++)
if (magnitude[l + width * i1] >= i) //像素值大于等于50
follow(l, i1, j); //x,y,230
}
}
private boolean follow(int i, int j, int k) {
int j1 = i + 1;
int k1 = i - 1;
int l1 = j + 1;
int i2 = j - 1;
int j2 = i + j * width; //该点的像素值坐标
if (l1 >= height)
l1 = height - 1;//l1(y)的最大值
if (i2 < 0)
i2 = 0; //i2(y)的最小值
if (j1 >= width)
j1 = width - 1; //j1(x)的最大值
if (k1 < 0)
k1 = 0; //k1(x)的最小值
if (data[j2] == 0) { //像素值为黑
data[j2] = magnitude[j2]; //等级
boolean flag = false;
int l = k1;//l为x-1
do {
if (l > j1)//l大于x+1
break;
int i1 = i2;
do {
if (i1 > l1)
break;
int k2 = l + i1 * width;
if ((i1 != j || l != i)
&& magnitude[k2] >= k
&& follow(l, i1, k)) {
flag = true;
break;
}
i1++;
} while (true);
if (!flag)
break;
l++;
}
while (true);
return true;
} else {
return false;
}
}
}
实验效果:
参考博客来自:
http://blog.csdn.net/haohappy2004/article/details/476820