2016-01-06 3 views
0

Я пытаюсь выполнить обнаружение краев с помощью Sobel Operator, и я получаю странное трехкратное изображение.Обнаружение кромок в Java на PPM с использованием оператора Sobel

Изображение начинает жизнь как ЦБК, который я храню как многомерного массива основных цветов: Original image

Я преобразовать его в оттенки серого, который, кажется, работает просто отлично: Grayscale converted image

но когда я пытаюсь найти края, все идет ... странно: Edges found?

Учитывая, что код написан на Java, он довольно многословный, поэтому я включил только функцию преобразования. Если это будет полезно, чтобы опубликовать все это, я сделаю это.

private Color[][] sobelConvert(Color[][] image) { 
    Color[][] newPPM = new Color[maxX][maxY]; 

    for (int y = 0; y < maxY; y++) { 
     for (int x = 0; x < maxX; x++) { 
      int a = testForColor(x-1, y-1, image); 
      int b = testForColor(x-1, y, image); 
      int c = testForColor(x-1, y+1, image); 

      int d = testForColor(x, y-1, image); 
      int e = testForColor(x, y+1, image); 

      int f = testForColor(x+1, y-1, image); 
      int g = testForColor(x+1, y, image); 
      int h = testForColor(x+1, y+1, image); 

      int eH = (c + 2*e + h) - (a + 2*d + f); 
      int eV = (f + 2*g + h) - (a + 2*b + c); 

      int edgyness = (int) Math.sqrt((eH * eH) + (eV * eV)); 
      if (edgyness > 255) { 
       edgyness = 255; 
      } 
      if (edgyness < 0) { 
       edgyness = 0; 
      } 
      newPPM[x][y] = new Color(edgyness, edgyness, edgyness); 
     } 
    } 
    return newPPM; 
} 

testForColor() делает некоторую проверку диапазона, и возвращает одно из значений RGB в объекте цвета - так что я думаю, что я могу понять, яркость.

private int testForColor(int x, int y, Color[][] ppm) { 
    if (x < 0 || x >= maxX) { 
     return 0; 
    } 

    if (y < 0 || y >= maxY) { 
     return 0; 
    } 

    return ppm[x][y].getGreen(); 
} 

Edit: Добавление кода для чтения & написать PPM:

public Edgeness(String fileName) throws Exception { 
    this.fileName = fileName; 
    boolean foundDims = false; 
    Color c = null; 
    int r, g, b; 

    String line; 

    try { 
     BufferedReader br = new BufferedReader(new FileReader(fileName)); 
     while ((line = br.readLine()) != null) { 
      //System.out.println(line); 

      // Test if the line has any lenght (ignore empty lines) 
      // First line. We will ignore it. 
      // First character is a #. Ignore it. (this is bad - should check the whole line. TODO.) 
      if (line.length() > 0 && !line.equals("P3") && !(line.charAt(0) == '#')) { 
       // Check for image dimensions. Only do this once. I assume regex's take longer 
       // than testing a boolean. 
       if (!foundDims) { 
        Pattern pImDim = Pattern.compile("(\\d+) (\\d+)"); 
        Matcher mImDim = pImDim.matcher(line); 
        if (mImDim.find()) { 
         maxX = Integer.parseInt(mImDim.group(1)); 
         maxY = Integer.parseInt(mImDim.group(2)); 
         ppm = new Color[maxX][maxY]; 
        } 
        foundDims = true; 
       } 

       // Hmm. Last capture is kept, the rest are overwritten. so.. we split instead. 
       // https://stackoverflow.com/questions/3537878/how-to-capture-an-arbitrary-number-of-groups-in-javascript-regexp 
       String[] rgbVals = line.split(" "); 
       if (rgbVals.length % 3 == 0) { 
        for (int i = 0; i < rgbVals.length; i += 3) { 
         r = Integer.parseInt(rgbVals[i]); 
         g = Integer.parseInt(rgbVals[i+1]); 
         b = Integer.parseInt(rgbVals[i+2]); 
         c = new Color(r, g, b); 
         addNextColor(c); 
        } 
       } 
      } 
     } 
     br.close(); 
    } finally { 
    } 
} 
private void addNextColor(Color c) { 
    ppm[currentX][currentY] = c; 
    currentY++; 
    if (currentY >= maxY) { 
     currentX++; 
     currentY = 0; 
    } 
} 

И функцию, чтобы сохранить PPM в файл. Если я загружу PPM, то сразу вызовите render(), созданное изображение будет точной копией. Аналогично, если я сохраню изображение в градациях серого, я получаю изображение, указанное выше.

private void render(Color[][] image, String fileName) throws IOException { 
    ArrayList<String> output = new ArrayList<String>(); 
    output.add("P3"); 
    output.add(maxX + " " + maxY); 
    output.add("255"); 

    for (int x = 0; x < maxX; x++) { 
     StringBuilder sb = new StringBuilder(); 
     for (int y = 0; y < maxY; y++) { 
      if (image[x][y] != null) { 
       sb.append(image[x][y].getRed() + " " + image[x][y].getGreen() + " " + image[x][y].getBlue() + " "); 
      } else { 
       sb.append("0 0 0 "); 
      } 
     } 
     output.add(sb.toString()); 
    } 

    BufferedWriter bw = new BufferedWriter(new FileWriter(fileName)); 
    for (String s : output) { 
     bw.write(s); 
     bw.newLine(); 
    } 
    bw.close(); 
} 

Я конвертирую выход PPM в PNG с помощью программы преобразования ImageMagik.

Я нашел реализацию, написанную на Ruby в http://blog.saush.com/2011/04/20/edge-detection-with-the-sobel-operator-in-ruby/, которая при адаптации к Java дала тот же результат.

FWIW, это от Ежедневного программирования Reddit.

+0

Отправьте код, используемый для чтения/записи изображений PPM в/из 'Color [] []'. –

ответ

0

Проблема находится в другом месте - метод работает нормально - на дисплее может быть

Попробуйте проверить каждую стадию путем сохранения изображения, получаемого с

BufferedImage bim=new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 
int[] pix=new int[w*h]; 
for(i=0; i<pix.length; i++) pix[i]=(p[i%w][i/w].getBlue()<<16)|(p[i%w][i/w].getBlue()<<8)|p[i%w][i/w].getBlue()|0xff000000; 
bim.setRGB(0, 0, w, h, pix, o, w); 

try { 
ImageIO.write(bim, "png", new File(path+".png")); 
} catch (IOException ex) { ex.printStackTrace(); } 

где р ваш ппм массив

+0

Я не знаю, если отметить это правильно - но это помогло разоблачить проблему. Коренной проблемой было то, что я неправильно читал PPM. Это было исправлено с помощью плохой функции Render(). Спасибо за подсказку здесь - это была огромная помощь! –

0

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

У меня есть пример дома, который делает полное обнаружение края Canny (одним из шагов которого является обнаружение края привязанности), выставляя пошаговые промежуточные изображения. Если у вас все еще возникают проблемы, когда я вернусь с работы, я могу с уверенностью дать вам несколько советов.