J'ai la tâche d'implémenter le filtre Sobel qui est, comme vous le savez, un filtre de traitement d'image pour la détection des contours. Mais malheureusement, je n'ai aucune expérience dans le domaine du traitement d'image, dans la mesure où je ne sais même pas comment les images sont représentées sur ordinateur. Aucune connaissance dans ce domaine.
J'ai lu des articles et des PDF, mais ils se concentrent sur de nombreux sujets dont je pense que je n'en ai peut-être pas besoin pour ma tâche.
Je serais heureux de connaître vos suggestions ou s'il existe un document, un PDF, un tutoriel ou un guide rapide à cet effet.
Merci
MODIFIER:
Merci à tous :) Le résultat de notre travail peut être téléchargé à partir de ici .
C'est assez simple, il vous suffit de convoluer votre image avec un filtre Sobel. Un filtre Sobel a deux noyaux, un noyau direction x et un noyau direction y. Le noyau de direction x détecte les bords horizontaux et les noyaux de direction y détectent les bords verticaux.
noyau direction x (la taille est 3x3)
float kernelx[3][3] = {{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1}};
noyau direction y
float kernely[3][3] = {{-1, -2, -1},
{0, 0, 0},
{1, 2, 1}};
Pour calculer la convolution au pixel (x, y), définissez une fenêtre de taille égale à la taille du noyau (le code source pour calculer la magnitude en x et la magnitude en y sont identiques):
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];
}
}
Notez que l'entrée est une image en niveaux de gris et elle peut être représentée comme un tableau 1D de double (c'est juste une astuce, car une valeur de pixel en coordonnées (x, y) est accessible avec index = [x + y * largeur])
Pour calculer la magnitude en pixels (x, y) compte tenu de magX et magY:
mag = sqrt (magX ^ 2 + magY ^ 2)
L'explication la plus simple de l'opérateur Sobel que j'ai vue à cette date est de le blog de Saush , un passionné de technologie qui a rencontré Sobel lui-même:
La publication décrit en (pas trop) de détails comment implémenter le filtre et partage Ruby code source à des fins de démonstration:
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')
Entrée/sortie :
Opérateur Sobel La page Wikipedia est bien descriptive sur la façon de l'exécuter. Il y a d'autres opérateurs tels que Roberts cross et Prewitt
En utilisant l'opération de convolution, vous pouvez changer d'approche en changeant la matrice du noyau. Ci-dessous, l'implémentation de Sobel et Convolution en utilisant Marvin Framework peut vous aider.
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;
}
}
Gx estime le gradient dans la direction x (colonnes) et Gy estime le gradient dans la direction y (lignes). Gy détecte donc les lignes horizontales et Gx détecte les lignes verticales.
Bien sûr, vous pouvez utiliser OpenCV pour cela:
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)
Entrée sortie:
Toutes les étapes mentionnées ci-dessus dans un fichier R markdown . Espérons que cela le rende plus visuel et plus facile à comprendre. J'avais besoin d'implémenter un filtre sobel et cette page m'a aidé à comprendre les concepts, mais j'ai eu du mal à le faire. Donc, tout cela en un seul endroit, j'espère que cela aide.