image processing - prewitt - Procesamiento de imágenes-Implementación del filtro Sobel
operador prewitt (5)
Tengo una tarea para implementar el filtro Sobel, que es, como saben, un filtro de procesamiento de imágenes para detección de bordes. Pero desafortunadamente, no tengo experiencia en el campo del procesamiento de imágenes, en la medida en que ni siquiera sé cómo se representan las imágenes en la computadora. Totalmente no hay conocimiento en este campo.
He leído algunos documentos y PDF, pero se centran en muchos temas que siento que no los necesito para mi tarea.
Me complacería conocer sus sugerencias o si hay algún documento en particular, PDF, tutorial o guía rápida para este propósito.
Gracias
EDITAR:
Gracias a todos :) El resultado de nuestro trabajo se puede descargar desde here .
Es bastante fácil, solo necesitas unir tu imagen con un filtro Sobel. Un filtro Sobel tiene dos kernels, kernel x-direction y kernel y-direction. El kernel de dirección x detecta los bordes horizontales, y los núcleos de dirección y detectan los bordes verticales.
kernel de dirección x (el tamaño es 3x3)
float kernelx[3][3] = {{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1}};
núcleo de dirección y
float kernely[3][3] = {{-1, -2, -1},
{0, 0, 0},
{1, 2, 1}};
Para calcular la convolución en píxeles (x, y), defina una ventana de tamaño igual al tamaño del núcleo (el código fuente para calcular la magnitud en xy la magnitud en y son idénticos):
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];
}
}
Tenga en cuenta que la entrada es una imagen en escala de grises y puede representarse como 1D matriz de doble (Esto es solo un truco, ya que se puede acceder a un valor de píxel en la coordenada (x, y) con índice = [x + y * ancho])
Para calcular la magnitud en píxeles (x, y) dados magX y magY:
mag = sqrt (magX ^ 2 + magY ^ 2)
Gx está estimando el gradiente en la dirección x (columnas) y Gy está estimando el gradiente en la dirección y (filas). Entonces Gy detecta líneas horizontales, y Gx detecta líneas verticales.
La explicación más simple del operador de Sobel que he visto hasta la fecha es del blog de Saush , un entusiasta de la tecnología que una vez conoció al propio Sobel:
La publicación describe (no demasiados) detalles sobre cómo implementar el filtro y comparte el código fuente de Ruby para fines de demostración:
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'')
Entrada / Salida :
Por supuesto, podrías usar OpenCV para esto:
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)
De entrada y salida:
La página de Sobel Operator Wikipedia es muy descriptiva sobre cómo realizarla. Hay otros operadores como Roberts cross y Prewitt
Usando la operación de convolución, puede cambiar el enfoque cambiando la matriz del kernel. A continuación, la implementación de Sobel y Convolution usando Marvin Framework puede ayudarlo.
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);
}
}
Circunvolución:
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;
}
}