private static void follow(int[] edgeImage, int x, int y,
int[] gradeMagnitude, int lowThreshold)
{
// 对8邻域象素进行查询
int[][] dir =
{
{ -1, -1 },
{ -1, 0 },
{ -1, 1 },
{ 0, -1 },
{ 0, 1 },
{ 1, -1 },
{ 1, 0 },
{ 1, 1 } };
for (int k = 0; k < 8; k++)
{
int ii = x + dir[k][0];  //这里不理解,dir的值不是二维的吗?怎么可以加。
int jj = y + dir[k][1];
// 如果该象素为可能的边界点,又没有处理过
// 并且梯度大于阈值
if (edgeImage[ii + width * jj] == 128
&& gradeMagnitude[ii + width * jj] >= lowThreshold)
                      //if的条件我看不懂
{
// 把该点设置成为边界点
edgeImage[ii + width * jj] = 255;
// 以该点为中心进行跟踪
follow(edgeImage, ii, jj, gradeMagnitude, lowThreshold);
}
}
}

解决方案 »

  1.   

       int ii = x + dir[k][0];  // dir 是二维的,但  dir[k][0]是 int 的..   if (edgeImage[ii + width * jj] == 128
                        && gradeMagnitude[ii + width * jj] >= lowThreshold)
                          //if的条件我看不懂
    我也不懂,因为不清楚你这个程序要达到什么目的
      

  2.   

    是dir二维数组,
    但dir[0][0]你说取到是哪个值?
    dir[k][0]就是k行的第一个数啊。如果k = 0, 在dir[k][0]=-1. k=3, dir[k][0]=0
    这个不难理解吧。
      

  3.   

    int ii=x+dir[k][0]
    我不知道LZ为什么不明白,这里的dir[k][0]不是指明了是K行第0列吗,很明显的可以拿到K行0列的值然后进行相加很明显的啊
      

  4.   

    int ii = x + dir[k][0];  //这里不理解,dir的值不是二维的吗?怎么可以加。
    这很好理解吧。  dir是二维,但是dir[][]的值是一个int
     if (edgeImage[ii + width * jj] == 128
                        && gradeMagnitude[ii + width * jj] >= lowThreshold)
                          //if的条件我看不懂
                {
                    // 把该点设置成为边界点
                    edgeImage[ii + width * jj] = 255;
                    // 以该点为中心进行跟踪
                    follow(edgeImage, ii, jj, gradeMagnitude, lowThreshold);
                }
    这个我也看不懂, 都没有说清楚要完成什么功能,  对这个函数的参数也没有说明白。   。。
      

  5.   

    我想知道 edgeImage、gradeMagnitude 和 lowThreshold 初始都是些什么值啊?这个算法到底是干什么?
      

  6.   

     dir 是二维的int数组,dir[k][0]是 int 的
      

  7.   

    所有源码在这里,看大家是否能理解。再说说心得看。
    /*
     * CannyEdgeDetector.java
     *
     * Created on 2007年12月10日, 下午8:42
     *
     */import java.awt.*;
    import java.awt.image.*;
    import java.awt.color.ColorSpace;/**
     * 边缘检测
     * <p>
     * 实现了Canny边缘检测算法,提供静态函数 canny
     * 
     * @author 余乐伟
     */
    public class CannyEdgeDetector
    {
    /**
     * Canny边缘检测
     * <p>
     * 函数 Canny 采用 CANNY 算法发现输入图像的边缘而且在输出图像中标识这些边缘。 threshold1和threshold2
     * 当中的小阈值用来控制边缘连接,大的阈值用来控制强边缘的初始分割。
     * <p>
     * Canny边缘检测算法步骤:<br>
     * step1:用高斯滤波器平滑图象;<br>
     * step2:计算梯度的幅值和方向; <br>
     * step3:对梯度幅值进行非极大值抑制; <br>
     * step4:用双阈值算法检测和连接边缘 <br>
     * 
     * @param sourceImage
     *            输入图像
     * @param lowThreshold
     *            第一个阈值(低)
     * @param highThreshold
     *            第二个阈值(高)
     * @return 用 Canny 边缘检测算法得到的边缘图
     */
    public static BufferedImage canny(BufferedImage sourceImage,
    int lowThreshold, int highThreshold)
    {
    height = sourceImage.getHeight();
    width = sourceImage.getWidth();
    int picsize = width * height; // 先把图片转换为灰度图
    ColorSpace grayCS = ColorSpace.getInstance(ColorSpace.CS_GRAY);
    ColorConvertOp colorConvertOp = new ColorConvertOp(grayCS, null);
    sourceImage = colorConvertOp.filter(sourceImage, null); // sourceImage = ColorConvert.grayImage(sourceImage); // 对原图高斯滤波
    sourceImage = gaussianSmooth(sourceImage); // 梯度幅值表
    int[] gradeMagnitude = new int[picsize];
    // 梯度方向表
    int[] gradeOrientation = new int[picsize]; // 计算方向导数和梯度的幅度
    grade(sourceImage, gradeMagnitude, gradeOrientation); // 应用非最大抑制,细化
    int[] edgeImage = NonmMaxSuppress(gradeMagnitude, gradeOrientation); // 边界提取与轮廓跟踪
    return thresholdingTracker(edgeImage, gradeMagnitude, lowThreshold,
    highThreshold);
    } /**
     * 用高斯滤波器平滑原图像
     * 
     * @param sourceImage
     *            输入图像
     * @return 高斯滤波后的图像
     */
    private static BufferedImage gaussianSmooth(BufferedImage sourceImage)
    {
    // 高斯模板
    float[] elements =
    { 1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f, 2.0f / 16.0f, 4.0f / 16.0f,
    2.0f / 16.0f, 1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f }; BufferedImage bi = new BufferedImage(sourceImage.getWidth(),
    sourceImage.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics2D big = bi.createGraphics();
    big.drawImage(sourceImage, 0, 0, null);
    // 创建一个Kernel
    Kernel kernel = new Kernel(3, 3, elements);
    ConvolveOp blur = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
    sourceImage = blur.filter(bi, null); return sourceImage;
    } /**
     * 计算方向导数和梯度的幅度
     * 
     * @param grayImage
     *            要计算的图象
     * @param gradeMagnitude
     *            要在其中存储结果的梯度数组
     * @param gradeOrientation
     *            要在其中存储结果的方向导数组
     */
    private static void grade(BufferedImage grayImage, int[] gradeMagnitude,
    int[] gradeOrientation)
    {
    int height = grayImage.getHeight();
    int width = grayImage.getWidth();
    int[] srcGray = new int[width * height];
    for (int i = 0; i < width; i++)
    for (int j = 0; j < height; j++)
    srcGray[i + j * width] = 0xff & grayImage.getRGB(i, j); for (int i = 1; i < width - 1; i++)
    {
    for (int j = 1; j < height - 1; j++)
    {
    int x = srcGray[(i + 1) + j * width]
    - srcGray[(i - 1) + j * width];// X方向导数
    int y = srcGray[i + (j + 1) * width]
    - srcGray[i + (j - 1) * width];// Y方向导数 gradeMagnitude[i + j * width] = (int) Math.sqrt(x * x + y * y);
    // 方向导数在非最大抑制时使用,使用时,只需知道 X 方向导数和 Y 方向导数的同号或异号情况
    gradeOrientation[i + j * width] = x * y;
    }
    } } /**
     * 非最大抑制
     * 
     * @param gradeMagnitude
     *            梯度数组
     * @param gradeOrientation
     *            方向数组
     * @return 非最大抑制后的边缘数组
     */
    private static int[] NonmMaxSuppress(int[] gradeMagnitude,
    int[] gradeOrientation)
    {
    int[] edgeImage = new int[width * height]; for (int i = 1; i < width - 1; i++)
    {
    for (int j = 1; j < height - 1; j++)
    {
    if (gradeMagnitude[i + width * j] == 0)
    {
    edgeImage[i + width * j] = 0;
    continue;
    }
    int n1 = 0, n2 = 0; // 判断 X 方向导数和 Y 方向导数的同号或异号情况
    if (gradeOrientation[i + width * j] > 0)
    {
    n1 = gradeMagnitude[i - 1 + width * (j - 1)];
    n2 = gradeMagnitude[i + 1 + width * (j + 1)];
    } else
    {
    n1 = gradeMagnitude[i + 1 + width * (j - 1)];
    n2 = gradeMagnitude[i - 1 + width * (j + 1)];
    }
    // 当前象素的梯度是局部的最大值
    // 该点可能是个边界点
    if (gradeMagnitude[i + width * j] >= n1
    && gradeMagnitude[i + width * j] >= n2)
    {
    edgeImage[i + width * j] = 128;
    }
    // 不可能是边界点
    else
    {
    edgeImage[i + width * j] = 0;
    }
    }
    }
    return edgeImage;
    } /**
     * 边界提取与轮廓跟踪,利用函数寻找边界起点
     * 
     * @param edgeImage
     *            边缘数组
     * @param gradeMagnitude
     *            梯度数组
     * @param lowThreshold
     *            第一个阈值(低)
     * @param highThreshold
     *            第二个阈值(高)
     * @return 用 Canny 边缘检测算法得到的边缘图
     */
    private static BufferedImage thresholdingTracker(int[] edgeImage,
    int[] gradeMagnitude, int lowThreshold, int highThreshold)
    {
    for (int i = 0; i < width; i++)
    {
    for (int j = 0; j < height; j++)
    {
    // 如果该象素是可能的边界点,并且梯度大于高阈值,该象素作为
    // 一个边界的起点
    if (edgeImage[i + width * j] == 128
    && gradeMagnitude[i + width * j] >= highThreshold)
    {
    // 把该点设置成为边界点
    edgeImage[i + width * j] = 255;
    // 以该点为中心进行跟踪
    follow(edgeImage, i, j, gradeMagnitude, lowThreshold);
    }
    }
    } BufferedImage destImage = new BufferedImage(width, height,
    BufferedImage.TYPE_INT_RGB);
    for (int i = 0; i < width; i++)
    {
    for (int j = 0; j < height; j++)
    if (edgeImage[i + width * j] == 255)
    destImage.setRGB(i, j, 0xff000000);
    else
    destImage.setRGB(i, j, -1);
    } return destImage;
    } /**
     * 在8邻近区域里搜索
     * 
     * @param edgeImage
     *            边缘数组
     * @param x
     *            图像元素的x坐标位置
     * @param y
     *            图像元素的y坐标位置
     * @param gradeMagnitude
     *            梯度数组
     * @param lowThreshold
     *            第一个阈值(低)
     */
    private static void follow(int[] edgeImage, int x, int y,
    int[] gradeMagnitude, int lowThreshold)
    {
    // 对8邻域象素进行查询
    int[][] dir =
    {
    { -1, -1 },
    { -1, 0 },
    { -1, 1 },
    { 0, -1 },
    { 0, 1 },
    { 1, -1 },
    { 1, 0 },
    { 1, 1 } };
    for (int k = 0; k < 8; k++)
    {
    int ii = x + dir[k][0];
    int jj = y + dir[k][1];
    // 如果该象素为可能的边界点,又没有处理过
    // 并且梯度大于阈值
    if (edgeImage[ii + width * jj] == 128
    && gradeMagnitude[ii + width * jj] >= lowThreshold)
    {
    // 把该点设置成为边界点
    edgeImage[ii + width * jj] = 255;
    // 以该点为中心进行跟踪
    follow(edgeImage, ii, jj, gradeMagnitude, lowThreshold);
    }
    }
    } /**
     * 图片高度
     */
    private static int height; /**
     * 图片宽度
     */
    private static int width; public static void main(String args[])
    {
    BufferedImage srcImage ,distImage;
    srcImage= ImageAPI.getBufferedImageFromFile("test.jpg");
    distImage= CannyEdgeDetector.canny(srcImage, 0, 212);
    ImageAPI.saveBufferedImagetoFile(distImage, "./distTest.jpg");
                    System.out.println("aa");

    }
    }
      

  8.   

    hehe!!!
    很好的,就是根据灰度值的变化的幅度来确定边缘