web-dev-qa-db-fra.com

Traitement d'image - Implémentation du filtre Sobel

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 .

30
Ahmad Siavosh

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)

28
azer89

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:

enter image description here

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 :

19
karlphillip

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.

3
Marina Tolkachov

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:

3
Andriy Makukha

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.

http://rpubs.com/ghub_24/420754

0
ghub24