我的任务是实现 Sobel 过滤器,如您所知,它是用于边缘检测的图像处理过滤器。但不幸的是,我没有图像处理领域的经验,以至于我什至不知道图像在计算机中是如何表示的。完全没有这方面的知识。
我已经阅读了一些论文和 PDF,但它们专注于许多我觉得我可能不需要它们来完成我的任务的主题。
我很高兴知道您的建议,或者是否有任何特定的论文、PDF、教程或快速指南用于此目的。
谢谢
编辑:
谢谢大家 :) 我们的工作成果可以从这里下载。
我的任务是实现 Sobel 过滤器,如您所知,它是用于边缘检测的图像处理过滤器。但不幸的是,我没有图像处理领域的经验,以至于我什至不知道图像在计算机中是如何表示的。完全没有这方面的知识。
我已经阅读了一些论文和 PDF,但它们专注于许多我觉得我可能不需要它们来完成我的任务的主题。
我很高兴知道您的建议,或者是否有任何特定的论文、PDF、教程或快速指南用于此目的。
谢谢
编辑:
谢谢大家 :) 我们的工作成果可以从这里下载。
这很简单,你只需要用 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];
}
}
请注意,输入是灰度图像,它可以表示为一维双精度数组(这只是一个技巧,因为坐标 (x,y) 中的像素值可以通过 index = [x + y * width] 访问)
在给定 magX 和 magY 的情况下计算像素 (x,y) 的大小:
mag = sqrt(magX^2 + magY^2)
迄今为止我看到的关于Sobel 算子的最简单的解释来自Saush 的博客,他是一位技术爱好者,曾与 Sobel 本人见过面:
这篇文章(不是太多)详细描述了如何实现过滤器,并分享了 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 Operator Wikipedia 页面很好地描述了如何执行它。还有其他运营商,例如Roberts cross和Prewitt
使用卷积运算,您可以通过改变核矩阵来切换方法。下面,使用Marvin 框架实现 Sobel 和卷积可能会对您有所帮助。
索贝尔:
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;
}
}
Gx 估计 x 方向(列)的梯度,Gy 估计 y 方向(行)的梯度。所以 Gy 检测水平线,而 Gx 检测垂直线。
当然,您可以为此使用 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)
输入输出:
您可以在 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))
我使用 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');//将Sobel边缘检测器应用到g imshow(S); //显示图像 原始图像 分割图像
R 降价文件中的所有上述步骤。希望这使它更直观,更容易理解。我需要实现一个 sobel 过滤器,这个页面帮助我理解了这些概念,但我在完成它时遇到了一些麻烦。所以把它放在一个地方希望它会有所帮助。