Алгоритм Кэнни: Неправильная функция гистерезиса

Я пишу алгоритм Кэнни, и, похоже, у меня проблема с гистерезисом. Кажется, что пороговые значения обрабатываются, однако мой гистерезис, похоже, вообще не работает. Как и метод удаления слабых по какой-то странной причине. Пожалуйста помоги!

Low @ 10Low @ 10  High @ 75 High @ 75  After Hysteresis После гистерезиса, с проблемой A, края не были усилены методом performHysteresis; B слабые не-ребра не удаляются методом removeWeak.

Исходный код метода следующий:

import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;

class CannyMethod {

private static final float[] sobelX = { 1.0f, 0.0f, -1.0f,
                                        2.0f, 0.0f, -2.0f,
                                        1.0f, 0.0f, -1.0f};
private static final float[] sobelY = { 1.0f, 2.0f, 1.0f,
                                        0.0f, 0.0f, 0.0f,
                                       -1.0f,-2.0f,-1.0f};
private static int low, high;


public CannyMethod() {}

private ConvolveOp getSobel(boolean xy) {
    Kernel kernel;
    if (xy) kernel = new Kernel(3, 3, sobelX);
    else kernel = new Kernel(3, 3, sobelY);

    return new ConvolveOp(kernel, ConvolveOp.EDGE_ZERO_FILL, null);
}

public BufferedImage getCannyFilter(BufferedImage img) {
    return getCannyFilter(img, low, high);
}

public BufferedImage getCannyFilter(BufferedImage img, int l, int h) {
    int width = img.getWidth();
    int height = img.getHeight();
    low = l;
    high = h;

    int size = width * height;
    int[] x = new int[size];
    int[] y = new int[size];
    int[] pixelM = new int[size];
    double[] pixelD = new double[size];
    int[] pixelNew = new int[size];

    BufferedImage sobelXImg = getSobel(true).filter(img, null);
    BufferedImage sobelYImg = getSobel(false).filter(img, null);


    // returns arrays for x and y direction after convultion with Sobel Operator
    sobelXImg.getRaster().getPixels(0, 0, width, height, x);
    sobelYImg.getRaster().getPixels(0, 0, width, height, y);

// Calculates Gradient and Magnitude
    for(int i = 0; i < size; i++) {
        pixelM[i] = (int) Math.hypot(x[i], y[i]);
        pixelD[i] = Math.atan2((double) y[i], (double) x[i]);
    }

//Operations for Canny Algorithm takes magnitude and gradient and input into new array fo WritableRaster
    normalizeDirection(pixelD);
    nonMaximaSupression(pixelM, pixelD, pixelNew, width, height);
    performHysteresis(pixelNew, width);
    removeWeak(pixelNew);

    BufferedImage result = 
        new BufferedImage(width, height,
                          BufferedImage.TYPE_BYTE_GRAY);
    result.getRaster().setPixels(0, 0, width, height, pixelNew);

    return result;
}

private void normalizeDirection(double[] dArray) {
//Round degrees

    double pi = Math.PI;
    for(double i : dArray) {
        if (i < pi/8d && i >= -pi/8d) i = 0;
        else if (i < 3d*pi/8d && i >= pi/8d) i = 45;
        else if (i < -3d*pi/8d || i >= 3d*pi/8d) i = 90;
        else if (i < -pi/8d && i >= -3d*pi/8d) i = 135;
    }
}

private void nonMaximaSupression(int[] pixelM, double[] pixelD, 
    int[] pixelNew, int width, int height) {
//non-Maxima Supression
//Since array is not in 2-D, positions are calulated with width - functions properly

    for(int i = 0; i < pixelNew.length; i++) {
        if (i % width == 0 || (i + 1) % width == 0 ||
            i <= width || i >= width * height - 1) pixelNew[i] = 0;
        else {
            switch ((int) pixelD[i]) {
                case 0:  if (pixelM[i] > pixelM[i+1] 
                            && pixelM[i] > pixelM[i-1])
                            setPixel(i, pixelM[i], pixelNew);
                         else pixelNew[i] = 0;
                         break;
                case 45: if (pixelM[i] > pixelM[i+(width-1)] 
                            && pixelM[i] > pixelM[i-(width-1)])
                            setPixel(i, pixelM[i], pixelNew);
                         else pixelNew[i] = 0;
                         break;
                case 90: if (pixelM[i] > pixelM[i+width] 
                            && pixelM[i] > pixelM[i-width])
                            setPixel(i, pixelM[i], pixelNew);
                         else pixelNew[i] = 0;
                         break;
                case 135:if (pixelM[i] > pixelM[i+width] 
                            && pixelM[i] > pixelM[i-width])
                            setPixel(i, pixelM[i], pixelNew);
                         else pixelNew[i] = 0;
                         break;
                default: pixelNew[i] = 0;
            }
        }
    }
}

private void performHysteresis(int[] array, int width) {
//performs hysteresis

    int[] temp;
    for(int i = width; i < array.length - width; i++) {
        if (i % width == 0 || (i + 1) % width == 0) {}
        else {
            if (array[i] == 255) {
    //found strong one, track surrounding weak ones
    //temp is the positions of surrounding pixels
                temp = new int[] 
                    {i - (width + 1), i - width, i - (width - 1),
                     i - 1,                      i + 1,
                     i + (width - 1), i + width, i + (width + 1)};
                trackWeak(array, temp, width);
            }
        }
    }
}

private void trackWeak(int[] array, int[] pos, int width) {
    int[] temp;
    for (int i : pos) {
        if (array[i] > 0 && array[i] < 255) {
            array[i] = 255;
    //set weak one to strong one

            if (i % width == 0 || (i + 1) % width == 0) {}
            else {
    //temp is the positions of surrounding pixels
                temp = new int[]
                    {i - (width + 1), i - width, i - (width - 1),
                     i - 1,                      i + 1,
                     i + (width - 1), i + width, i + (width + 1)};
                trackWeak(array, temp, width);
            }
        }
    }
}

private void removeWeak(int[] array) {
//remove remaining weak ones from lew Threshold

    for(int i : array) {
        if (i < 255) {i = 0;}
    }
}

private void setPixel(int pos, int value, int[] pixelNew) {
    if (value > high) pixelNew[pos] = 255;
    else if (value > low) pixelNew[pos] = 128;
    else pixelNew[pos] = 0;
}

public void setThreshold(int l, int h) {
    low = l;
    high = h;
}
}

person DVCode    schedule 17.12.2014    source источник
comment
не извиняйтесь за отсутствие комментариев - добавляйте комментарии. И для того, чтобы помочь нам понять ваш код, и для того, чтобы вы разобрались в своем собственном коде на следующей неделе. Также не связывайтесь с кодом, который, по вашему мнению, может потребоваться от нас для его редактирования перед компиляцией: отправьте код, который, как вы знаете, компилируется. Помните, мы просто люди, очень похожие на вас. Чем больше времени нам нужно потратить на понимание или даже запуск вашего кода, тем больше мы просто перейдем к следующему вопросу.   -  person Mike 'Pomax' Kamermans    schedule 17.12.2014
comment
Спасибо за предложение, по вашему предложению я сделал комментарии для рассматриваемого класса и убедился, что класс компилируется без ошибок. Я выяснил одну проблему с моим кодом, однако в моей работе и публикации гистерезиса все еще есть проблема, я был бы очень признателен за вашу помощь, если вы можете что-то предложить.   -  person DVCode    schedule 17.12.2014


Ответы (1)


Я понял. Гистерезис работал, это было сложно сказать по качеству изображения.

Что касается слабого удаления, я использовал расширенный цикл for, и я начинаю видеть, что получается и изменяется только копия элемента, а не сам элемент в самом массиве. Как только я изменил это на обычный цикл for, все заработало!

person DVCode    schedule 18.12.2014