I\'ve got a task to implement Sobel filter which is, as you know, an image processing filter for edge detection. But unfortunately, I\'ve got no experience in image processi
Sobel Operator Wikipedia page is well descriptive about how to perform it. There other operators such as Roberts cross and Prewitt
Using convolution operation, you can switch the approach by changing the kernel matrix. Below, the implementation of Sobel and Convolution using Marvin Framework may help you.
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);
}
}
Convolution:
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;
}
}
I use Octave 4.4.1 for image processing and edge detection. Octave is an open source software which provides functionality of MatLab. I have used the following code from "https://in.mathworks.com/" Let us consider that the image is 'k1.jpg' To implement Sobel edge operator i=imread('k1.jpg');//To read the image pkg load image//Loading image processing Tool Box g=rgb2gray(i)//Conversion of image to grayscale S=edge(g,'Sobel');//Applying Sobel edge detector to g imshow(S);//To display the image Original image Segmented Image
All the above mentioned steps in a R markdown file. Hopefully this makes it more visual and easier to understand. I needed to implement a sobel filter and this page helped me understand the concepts still I had some trouble in getting it done. So putting it all in one place hopefully it helps.
http://rpubs.com/ghub_24/420754
Of course, you could use OpenCV for this:
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)
Input / Output:
The most simple explanation of the Sobel operator I've seen to this date is from Saush's blog, a tech enthusiast who once met Sobel himself:
The post describes in (not too many) details how to implement the filter, and shares Ruby source-code for demonstration purposes:
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')
Input/Output:
You can do this in R with the raster package (oriented towards geographic data)
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))