2013-07-23 136 views
23

我有一个任务来实现Sobel滤波器,就像你所知的那样,它是一个用于边缘检测的图像处理滤波器。 但不幸的是,我没有经验的图像处理领域,甚至我甚至不知道如何在计算机中表示图像。完全没有这方面的知识。图像处理 - 实现Sobel滤波器

我已经阅读了一些论文和PDF文件,但他们专注于很多主题,我觉得我可能不需要它们来完成我的任务。

我很乐意知道您的建议,或者是否有任何特定的纸张,PDF,教程或快速指南来达到此目的。

谢谢

编辑:

谢谢大家:) 我们工作的结果可以从here下载。

+0

投票结束为资源rec。 –

回答

23

这很容易,你只需要用索贝尔过滤器来卷积图像。 Sobel滤波器有两个内核,即x方向内核和y方向内核。 x方向内核检测水平线,y方向内核检测垂直线。

x方向内核(尺寸为3×3)

float kernelx[3][3] = {{-1, 0, 1}, 
         {-2, 0, 2}, 
         {-1, 0, 1}}; 

y方向内核

float kernely[3][3] = {{-1, -2, -1}, 
         {0, 0, 0}, 
         {1, 2, 1}}; 

为了计算在像素的卷积(X,Y),定义一个窗口,其大小为等于内核大小(计算x的量级的源代码和y的量级是相同的):

double magX = 0.0; // this is your magnitude 

for(int a = 0; a < 3; a++) 
{ 
    for(int b = 0; b < 3; b++) 
    {    
     int xn = x + a - 1; 
     int yn = y + b - 1; 

     int index = xn + yn * width; 
     magX += image[index] * kernelx[a][b]; 
    } 
} 

请注意,输入是一个灰度图像,它可以表示为double的一维数组(这只是一个技巧,因为坐标(x,y)中的像素值可以用index = [x + y * width]来访问)

为了计算在像素(x,y)的给定的幅度MAGX和MAGY:

MAG = SQRT(MAGX^2 + MAGY^2)

+1

将水平和垂直内核合并为一个实部和一个虚部是否有意义,然后通过获得abs(结果)来找到大小? – endolith

+0

@ azer89我怀疑'image'和'kernelx'的简单乘法是否可行,因为我们需要卷积,对吗? – Shailesh

+0

看看这个博客:[2d卷积](http://www.songho.ca/dsp/convolution/convolution2d_example.html) – Shailesh

4

Sobel Operator Wikipedia页面是很好的描述有关如何执行它。还有其他运算符,如Roberts crossPrewitt

使用卷积运算,可以通过更改内核矩阵来切换方法。下面,使用Marvin Framework来实现Sobel和Convolution可能会对您有所帮助。

索贝尔:

public class Sobel extends MarvinAbstractImagePlugin{ 

    // Definitions 
    double[][] matrixSobelX = new double[][]{ 
      {1,  0, -1}, 
      {2,  0, -2}, 
      {1,  0, -1} 
    }; 
    double[][] matrixSobelY = new double[][]{ 
      {-1, -2,  -1}, 
      {0,  0,  0}, 
      {1,  2,  1} 
    }; 

    private MarvinImagePlugin convolution; 

    public void load(){ 
     convolution = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.convolution.jar"); 
    } 

    public MarvinAttributesPanel getAttributesPanel(){ 
     return null; 
    } 
    public void process 
    (
     MarvinImage imageIn, 
     MarvinImage imageOut, 
     MarvinAttributes attrOut, 
     MarvinImageMask mask, 
     boolean previewMode 
    ) 
    { 
     convolution.setAttribute("matrix", matrixSobelX); 
     convolution.process(imageIn, imageOut, null, mask, previewMode); 
     convolution.setAttribute("matrix", matrixSobelY); 
     convolution.process(imageIn, imageOut, null, mask, previewMode); 
    } 
} 

卷积:

public class Convolution extends MarvinAbstractImagePlugin{ 

    private MarvinAttributesPanel attributesPanel; 
    private MarvinAttributes  attributes; 

    public void process 
    (
     MarvinImage imageIn, 
     MarvinImage imageOut, 
     MarvinAttributes attributesOut, 
     MarvinImageMask mask, 
     boolean previewMode 
    ) 
    { 
     double[][] matrix = (double[][])attributes.get("matrix"); 

     if(matrix != null && matrix.length > 0){ 
      for(int y=0; y<imageIn.getHeight(); y++){ 
       for(int x=0; x<imageIn.getWidth(); x++){ 
        applyMatrix(x, y, matrix, imageIn, imageOut); 
       } 
      } 
     } 
    } 

    private void applyMatrix 
    (
     int x, 
     int y, 
     double[][] matrix, 
     MarvinImage imageIn, 
     MarvinImage imageOut 
    ){ 

     int nx,ny; 
     double resultRed=0; 
     double resultGreen=0; 
     double resultBlue=0; 

     int xC=matrix[0].length/2; 
     int yC=matrix.length/2; 

     for(int i=0; i<matrix.length; i++){ 
      for(int j=0; j<matrix[0].length; j++){ 
       if(matrix[i][j] != 0){  
        nx = x + (j-xC); 
        ny = y + (i-yC); 

        if(nx >= 0 && nx < imageOut.getWidth() && ny >= 0 && ny < imageOut.getHeight()){ 

         resultRed += (matrix[i][j]*(imageIn.getIntComponent0(nx, ny))); 
         resultGreen += (matrix[i][j]*(imageIn.getIntComponent1(nx, ny))); 
         resultBlue += (matrix[i][j]*(imageIn.getIntComponent2(nx, ny))); 
        } 


       } 



      } 
     } 

     resultRed = Math.abs(resultRed); 
     resultGreen = Math.abs(resultGreen); 
     resultBlue = Math.abs(resultBlue); 

     // allow the combination of multiple appications 
     resultRed += imageOut.getIntComponent0(x,y); 
     resultGreen += imageOut.getIntComponent1(x,y); 
     resultBlue += imageOut.getIntComponent2(x,y); 

     resultRed = Math.min(resultRed, 255); 
     resultGreen = Math.min(resultGreen, 255); 
     resultBlue = Math.min(resultBlue, 255); 

     resultRed = Math.max(resultRed, 0); 
     resultGreen = Math.max(resultGreen, 0); 
     resultBlue = Math.max(resultBlue, 0); 

     imageOut.setIntColor(x, y, imageIn.getAlphaComponent(x, y), (int)resultRed, (int)resultGreen, (int)resultBlue); 
    } 

    public void load(){ 
     attributes = getAttributes(); 
     attributes.set("matrix", null); 
    } 

    public MarvinAttributesPanel getAttributesPanel(){ 
     if(attributesPanel == null){ 
      attributesPanel = new MarvinAttributesPanel(); 
      attributesPanel.addMatrixPanel("matrixPanel", "matrix", attributes, 3, 3); 
     } 
     return attributesPanel; 
    } 

} 
+0

嗨,我是新来的,我已经创建了主要类,并得到这个错误,你能告诉我如何为它写主要类? Sobel a = new Sobel(); \t \t MarvinImage imgIn = MarvinImageIO.loadImage(“unnamed2.jpg”); \t \t MarvinImage imgOut = MarvinImageIO.loadImage(“test.jpg”); \t \t a.process(imgIn,imgOut);在线程“main”中的异常java.lang.NullPointerException \t at Sobel.process(Sobel.java:41) – Abdullah

14

我已经看到了这个日期的Sobel算最简单的解释是Saush's blog,科技爱好者谁曾经遇到过索贝尔本人:

enter image description here

The post描述(不要太多),详细介绍了如何实现滤波器,以及股Ruby源代码用于演示目的:

require 'chunky_png' 

class ChunkyPNG::Image 
    def at(x,y) 
    ChunkyPNG::Color.to_grayscale_bytes(self[x,y]).first 
    end 
end 

img = ChunkyPNG::Image.from_file('engine.png') 

sobel_x = [[-1,0,1], 
      [-2,0,2], 
      [-1,0,1]] 

sobel_y = [[-1,-2,-1], 
      [0,0,0], 
      [1,2,1]] 

edge = ChunkyPNG::Image.new(img.width, img.height, ChunkyPNG::Color::TRANSPARENT) 

for x in 1..img.width-2 
    for y in 1..img.height-2 
    pixel_x = (sobel_x[0][0] * img.at(x-1,y-1)) + (sobel_x[0][1] * img.at(x,y-1)) + (sobel_x[0][2] * img.at(x+1,y-1)) + 
       (sobel_x[1][0] * img.at(x-1,y)) + (sobel_x[1][1] * img.at(x,y)) + (sobel_x[1][2] * img.at(x+1,y)) + 
       (sobel_x[2][0] * img.at(x-1,y+1)) + (sobel_x[2][1] * img.at(x,y+1)) + (sobel_x[2][2] * img.at(x+1,y+1)) 

    pixel_y = (sobel_y[0][0] * img.at(x-1,y-1)) + (sobel_y[0][1] * img.at(x,y-1)) + (sobel_y[0][2] * img.at(x+1,y-1)) + 
       (sobel_y[1][0] * img.at(x-1,y)) + (sobel_y[1][1] * img.at(x,y)) + (sobel_y[1][2] * img.at(x+1,y)) + 
       (sobel_y[2][0] * img.at(x-1,y+1)) + (sobel_y[2][1] * img.at(x,y+1)) + (sobel_y[2][2] * img.at(x+1,y+1)) 

    val = Math.sqrt((pixel_x * pixel_x) + (pixel_y * pixel_y)).ceil 
    edge[x,y] = ChunkyPNG::Color.grayscale(val) 
    end 
end 

edge.save('engine_edge.png') 

输入/输出

+2

只是空洞的,你已经复制并粘贴了错误的代码(或者它在博文中是错误的,现在是固定?)。 sobel_x [0] [4]显然永远不会起作用。它应该是[0] [1] [1] [1] [2] [1]等。 – Doug

+0

嗨,你能支持我们的图像处理社区http://area51.stackexchange.com/proposals/86832。我们需要人们用不到10张选票来提问。谢谢。 – Royi

2

Gx估计x方向上的梯度(c和Gy)估计y方向(行)的梯度。 所以Gy检测水平线,Gx检测垂直线。

+1

这应该是评论 – ketan