【问题标题】:Image Processing - Implementing Sobel Filter图像处理 - 实现 Sobel 滤波器
【发布时间】:2013-07-22 20:20:12
【问题描述】:

我的任务是实现 Sobel 过滤器,如您所知,它是一种用于边缘检测的图像处理过滤器。 但不幸的是,我没有图像处理领域的经验,以至于我什至不知道图像在计算机中是如何表示的。完全没有这方面的知识。

我已经阅读了一些论文和 PDF,但它们侧重于许多主题,我觉得我的任务可能不需要它们。

我很高兴知道您的建议,或者是否有任何特定的论文、PDF、教程或快速指南用于此目的。

谢谢

编辑:

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

【问题讨论】:

  • 投票结束作为资源记录

标签: image-processing edge-detection


【解决方案1】:

这很简单,您只需使用 Sobel 过滤器对图像进行卷积即可。 Sobel 滤波器有两个内核,x 方向内核和 y 方向内核。 x 方向内核检测水平边缘,y 方向内核检测垂直边缘。

x方向内核(大小为3x3)

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 *宽度])

在给定 magX 和 magY 的情况下计算像素 (x,y) 的大小:

ma​​g = sqrt(magX^2 + magY^2)

【讨论】:

  • 将水平和垂直核组合起来,将一个实部和一个虚部结合起来,然后你可以通过获取 abs(结果)来找到大小,是否有意义?跨度>
  • @azer89 我怀疑imagekernelx 的简单乘法是否可行,因为我们需要卷积,对吧?
  • 看这个博客:2d convolution
【解决方案2】:

迄今为止我看到的Sobel算子最简单的解释来自Saush's blog,一位曾经见过Sobel本人的技术爱好者:

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')

输入/输出

【讨论】:

  • 只是懒惰,您复制并粘贴了错误的上述代码(或者它在博客文章中是错误的,现在已修复?)。 sobel_x[0][4] 显然永远不会工作。应该是[0][1][1][1][2][1]等
【解决方案3】:

Sobel Operator 维基百科页面很好地描述了如何执行它。还有其他运算符,例如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;
    }

}

【讨论】:

  • 您好,我是新手,我创建了主类并收到此错误,您能告诉我如何为它编写主类吗?索贝尔 a = 新索贝尔(); MarvinImage imgIn = MarvinImageIO.loadImage("unnamed2.jpg"); MarvinImage imgOut = MarvinImageIO.loadImage("test.jpg"); a.进程(imgIn,imgOut); Sobel.process(Sobel.java:41) 处的线程“主”java.lang.NullPointerException 中的异常
【解决方案4】:

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

【讨论】:

  • 这应该是评论
【解决方案5】:

当然,您可以为此使用 OpenCV:

import cv2
import numpy as np

img = cv2.imread(INPUT_IMAGE)
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY).astype(float)

edge_x = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
edge_y = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)    
edge = np.sqrt(edge_x**2 + edge_y**2)    # image can be normalized to 
                                         # fit into 0..255 color space
cv2.imwrite(OUTPUT_IMAGE, edge)

输入/输出:

【讨论】:

    【解决方案6】:

    R markdown 文件中的所有上述步骤。希望这使它更直观,更容易理解。我需要实现一个 sobel 过滤器,这个页面帮助我理解了这些概念,但我在完成它时遇到了一些麻烦。所以把它们放在一个地方希望它会有所帮助。

    http://rpubs.com/ghub_24/420754

    【讨论】:

      【解决方案7】:

      我使用 Octave 4.4.1 进行图像处理和边缘检测。 Octave 是一个提供 MatLab 功能的开源软件。 我使用了来自“https://in.mathworks.com/”的以下代码 让我们考虑图像是'k1.jpg' 实现 Sobel 边缘算子 i=imread('k1.jpg');//读取图片 pkg load image//加载图像处理工具箱 g=rgb2gray(i)//图像转灰度 S=edge(g,'Sobel');//对g应用Sobel边缘检测器 imshow(S);//显示图像 Original image Segmented Image

      【讨论】:

        【解决方案8】:

        您可以在 R 中使用 raster 包(面向地理数据)执行此操作

        library(raster)
        sobel <- function(r) {
            fy <- matrix(c(1,0,-1,2,0,-2,1,0,-1)/4, nrow=3)
            fx <- matrix(c(-1,-2,-1,0,0,0,1,2,1)/4 , nrow=3)
            rx <- focal(r, fx)
            ry <- focal(r, fy)
            sqrt(rx^2 + ry^2)
        }
        
        b <- brick("https://i.stack.imgur.com/Bnxa6.jpg")
        plotRGB(b)
        s <- stack(lapply(1:3, function(i) sobel(b[[i]])))
        plotRGB(s)
        
        # or
        ss <- mean(s)
        plot(ss, col=gray(1:10/10))
        
        # or
        bb <- mean(b)
        sss <- sobel(bb)
        plot(sss, col=gray(1:10/10))
        

        【讨论】:

          猜你喜欢
          • 2017-06-20
          • 2016-02-24
          • 2015-07-31
          • 2017-01-12
          • 2013-09-27
          • 1970-01-01
          • 2013-11-19
          • 2012-03-22
          • 2021-06-25
          相关资源
          最近更新 更多