Estoy usando un filtro de sobel de tamaño 3×3 para calcular la imagen de derivados. Revisando algunos artículos en internet, parece que los núcleos de filtro de sobel para el tamaño de 5×5 y 7×7 también son comunes, pero no soy capaz de encontrar su núcleo de valores.

Podría alguien por favor hágamelo saber el núcleo de los valores para el filtro de sobel de tamaño 5×5 y 7×7? También, si alguien pudiera compartir un método para generar el kernel de valores, que será mucho más útil.

Gracias de antemano.

InformationsquelleAutor Aarkan | 2012-03-05

9 Comentarios

  1. 15

    ACTUALIZACIÓN 23-Abr-2018: parece que los granos se define en el enlace de más abajo no son verdaderos Sobel núcleos (de 5×5 y por encima de) – se puede hacer un trabajo razonable de detección de bordes, pero no deben ser llamados Sobel núcleos. Ver Daniel respuesta para una más exacta y completa de resumen. (Voy a dejar esta respuesta aquí como (a) que está vinculado desde diversos lugares y (b) aceptado respuestas no pueden ser fácilmente eliminados).

    Google parece que subir un montón de resultados, por ejemplo,
    http://rsbweb.nih.gov/nih-image/download/user-macros/slowsobel.macro sugiere los siguientes núcleos de 3×3, 5×5, 7×7 y 9×9:

    3×3:

    1   0   -1
    2   0   -2
    1   0   -1
    

    5×5:

    2   1   0   -1  -2
    3   2   0   -2  -3
    4   3   0   -3  -4
    3   2   0   -2  -3
    2   1   0   -1  -2
    

    7×7:

    3   2   1   0   -1  -2  -3
    4   3   2   0   -2  -3  -4
    5   4   3   0   -3  -4  -5
    6   5   4   0   -4  -5  -6
    5   4   3   0   -3  -4  -5
    4   3   2   0   -2  -3  -4
    3   2   1   0   -1  -2  -3
    

    9×9:

    4   3   2   1   0   -1  -2  -3  -4
    5   4   3   2   0   -2  -3  -4  -5
    6   5   4   3   0   -3  -4  -5  -6
    7   6   5   4   0   -4  -5  -6  -7
    8   7   6   5   0   -5  -6  -7  -8
    7   6   5   4   0   -4  -5  -6  -7
    6   5   4   3   0   -3  -4  -5  -6
    5   4   3   2   0   -2  -3  -4  -5
    4   3   2   1   0   -1  -2  -3  -4
    

    • Gracias, cualquier enlace a su función de generador?
    • No creo que estas es una de ellas. Sobel es realmente sólo se define para 3×3 y los grandes núcleos parecen ser determinado en un ad hoc base. Ellos son sólo los elementos diferenciadores, por lo que debería ser relativamente fácil generar los coeficientes para cualquier tamaño de núcleo.
    • Lo siento, pero estos no son Sobel núcleos.
    • te importa que ampliar ese ?
    • Compruebe mi respuesta, se tomó un tiempo para escribir 🙂
    • Hay no son ni siquiera cerca.
    • por favor, acepte Daniel respuesta en lugar de esta.

  2. 36

    Otras fuentes parecen dar diferentes definiciones de los grandes núcleos. El Intel IPP biblioteca, por ejemplo, da la 5×5 kernel como

    1  2 0  -2 -1
    4  8 0  -8 -4
    6 12 0 -12 -6
    4  8 0  -8 -4
    1  2 0  -2 -1
    

    Intuitivamente, esto tiene más sentido para mí, porque estás prestando más atención a los elementos más cerca del centro. También tiene una definición natural en términos de 3×3 núcleo, que es fácil de extender a generar grandes núcleos. Dicho esto, en mi breve búsqueda he encontrado 3 diferentes definiciones de la 5×5 de núcleo por lo que sospecho que (como dice Pablo) el más grande de los kernels son ad hoc, por lo que esta no es la respuesta definitiva.

    El 3×3 kernel es el exterior producto de un suavizado kernel y un gradiente de kernel, en Matlab esto es algo así como

    sob3x3 = [ 1 2 1 ]' * [1 0 -1]
    

    los grandes núcleos pueden ser definidos por convolving el 3×3 kernel con otro suavizado kernel

    sob5x5 = conv2( [ 1 2 1 ]' * [1 2 1], sob3x3 )
    

    puede repetir el proceso para conseguir progresivamente mayor los núcleos

    sob7x7 = conv2( [ 1 2 1 ]' * [1 2 1], sob5x5 )
    sob9x9 = conv2( [ 1 2 1 ]' * [1 2 1], sob7x7 )
    ...
    

    hay un montón de otras maneras de escribir esto, pero creo que esto explica exactamente lo que está pasando mejor. Básicamente, usted comienza con un suavizado kernel en una dirección y un número finito de diferencias de la estimación de la derivada en los otros y, a continuación, sólo hay que aplicar el suavizado hasta que obtenga el tamaño del kernel que quieras.

    Porque es solo una serie de circunvoluciones, todos los lindos propiedades de retención, (conmutatividad, asociatividad y así sucesivamente) que podrían ser útiles para su aplicación. Por ejemplo, usted puede trivialmente separar el 5×5 núcleo en su suavizado y derivados componentes:

    sob5x5 = conv([1 2 1],[1 2 1])' * conv([1 2 1],[-1 0 1])
    

    Cuenta que para ser un «buen» derivado del estimador, el 3×3 Sobel debe ser escalado por un factor de 1/8:

    sob3x3 = 1/8 * [ 1 2 1 ]' * [1 0 -1]
    

    y cada núcleo más grande necesita ser modificada por un factor adicional de 1/16 (porque el suavizado de los núcleos no están normalizadas):

    sob5x5 = 1/16 * conv2( [ 1 2 1 ]' * [1 2 1], sob3x3 )
    sob7x7 = 1/16 * conv2( [ 1 2 1 ]' * [1 2 1], sob5x5 )
    ...
    
    • Pero, ¿por qué es el factor de escala 1/8o de una de 3×3 kernel y 1/16 de 5×5?
    • La 1D diferencias finitas kernel es 1/2 * [1 0 -1] y la 1D de suavizado kernel es 1/4 * [ 1 2 1 ]. Para el 3×3 necesidades de una escala de 1/2 * 1/4 = 1/8, y los grandes núcleos necesidad 1/4 * 1/4 = 1/16 al pasar de 1 a 2 dimensiones.
    • Si usted todavía está interesado en el tema, agradecería comentarios sobre mi solución para Sobel núcleos de tamaño arbitrario y rotación.
  3. 26

    Solución completa para arbitrario Sobel núcleo tamaños y ángulos

    tl;dr: salte a la sección ‘Ejemplos’

    Para agregar otra solución, ampliando este documento (no es particularmente alta calidad, pero muestra cierto nivel de gráficos y matrices de partida en la parte inferior de la página 2).

    Objetivo

    Lo que estamos tratando de hacer es estimar el local gradiente de la imagen en la posición (x,y). El gradiente es un vector formado por componentes en x y y de la dirección, gx y gy.

    Ahora, imagina que queremos aproximar el gradiente basado en nuestra pixel (x,y) y sus vecinos como un núcleo de operación (3×3, 5×5, o a cualquier tamaño).

    Solución idea

    Podemos aproximar el gradiente sumando más de las proyecciones de todos los vecinos del centro de pares en la dirección del degradado. (Sobel núcleo es apenas un particular método de ponderación de las diferentes contribuciones, y así es Prewitt, básicamente).

    Explícita pasos intermedios para 3×3

    Esta es la imagen local, central de píxel (x,y), marcada como ‘o’ (centro)

    a b c
    d o f
    g h i
    

    Digamos que queremos que el gradiente en la dirección x positiva. El vector unitario en x positivo-la dirección es (1,0) [voy a usar más tarde en el convenio, el eje y positivo está orientado hacia ABAJO, es decir, (0,1), y que (0,0) es la esquina superior izquierda de la imagen).]

    El vector de o a f (‘de’ para abreviar) es (1,0). El gradiente en la dirección ‘de’ es (f – o) /1 (valor de la imagen en píxeles aquí se denota f menos el valor en el centro o, dividido por la distancia entre los píxeles). Si proyectamos el vector unitario de cada vecino gradiente en la dirección del degradado (1,0) a través de un punto del producto obtenemos 1. Aquí hay una pequeña tabla con las aportaciones de todos los vecinos, comenzando con el más sencillo de los casos. Tenga en cuenta que para las diagonales, su distancia es de sqrt2, y los vectores unitarios en las direcciones diagonales son 1/sqrt2 * (+/-1, +/-1)

    f:   (f-o)/1     * 1
    d:   (d-o)/1     * -1       because (-1, 0) dot (1, 0) = -1
    b:   (b-o)/1     * 0        because (0, -1) dot (1, 0) = 0
    h:   (h-o)/1     * 0        (as per b)
    a:   (a-o)/sqrt2 * -1/sqrt2 distance is sqrt2, and 1/sqrt2*(-1,-1) dot (1,0) = -1/sqrt2
    c:   (c-o)/sqrt2 * +1/sqrt2   ...
    g:   (g-o)/sqrt2 * -1/sqrt2   ...
    i:   (i-o)/sqrt2 * +1/sqrt2   ...
    

    editar una aclaración:
    Hay dos factores de 1/sqrt(2) por la siguiente razón:

    1. Estamos interesados en la contribución a la gradiente de en una dirección específica (aquí x), así que necesitamos para el proyecto direccional gradiente que va desde el centro del píxel a píxel vecino en la dirección que nos interesa. Esto se logra tomando el producto escalar de los vectores unitarios en las direcciones, que introduce el primer factor 1/L (aquí 1/sqrt(2) para las diagonales).

    2. El gradiente mide el cambio infinitesimal en un punto, que nos aproximado por diferencias finitas. En términos de una ecuación lineal, m = (y2-y1)/(x2-x1). Por esta razón, la diferencia de valor del píxel del centro a los píxeles vecinos (y2-y1) tiene que ser distribuido más de su distancia (corresponde a x2-x1) con el fin de conseguir el ascenso unidades por unidad de distancia. Esto produce un segundo factor de 1/L (aquí 1/sqrt(2) para las diagonales)

    Ok, ahora vamos a conocer las aportaciones. Vamos a simplificar esta expresión mediante la combinación de los pares de opuestos de píxel contribuciones. Voy a empezar con d y f:

    {(f-o)/1 * 1} + {(d-o)/1 * -1}
    = f - o - (d - o)
    = f - d
    

    Ahora la primera diagonal:

    {(c-o)/sqrt2 * 1/sqrt2} + {(g-o)/sqrt2 * -1/sqrt2}
    = (c - o)/2 - (g - o)/2
    = (c - g)/2
    

    La segunda diagonal contribuye (i – a)/2. La dirección perpendicular contribuye a cero. Tenga en cuenta que todas las contribuciones de la central de píxel » o » desaparecen.

    Hemos calculado las contribuciones de todos los vecinos más cercanos a los de un gradiente positivo de la dirección x en el píxel (x,y), por lo que el total de nuestras aproximación del gradiente en la dirección x es simplemente la suma de los mismos:

    gx(x,y) = f - d + (c - g)/2 + (i - a)/2
    

    Podemos obtener el mismo resultado mediante el uso de un núcleo de circunvolución donde los coeficientes son escritas en el lugar de la correspondiente píxeles vecinos:

    -1/2  0  1/2
     -1   0   1
    -1/2  0  1/2
    

    Si usted no quiere tratar con fracciones, se multiplica esto por 2 y se obtiene el conocido Sobel 3×3 kernel.

          -1 0 1
    G_x = -2 0 2
          -1 0 1
    

    La multiplicación por dos sólo sirve para obtener conveniente enteros. La escala de la imagen de salida es básicamente arbitraria, la mayoría de las veces normalizar a tu imagen de rango, de todos modos (para obtener claramente visible resultados).

    Por el mismo razonamiento anterior, se obtiene el núcleo para el gradiente vertical gy proyectando el vecino contribuciones en el vector unitario en la positiva dirección y (0,1)

          -1 -2 -1
    G_y =  0  0  0
           1  2  1
    

    Fórmula para núcleos de tamaño arbitrario

    Si quieres 5×5 o más núcleos, sólo es necesario prestar atención a las distancias, por ejemplo,

    A B 2 B A
    B C 1 C B
    2 1 - 1 2
    B C 1 C B
    A B 2 B A
    

    donde

    A = 2 * sqrt2
    B = sqrt5
    C = sqrt2.
    

    Si la longitud del vector de conectar cualquiera de los dos píxeles es L, el vector unitario en esa dirección tiene un prefactor de 1/L. Por esta razón, las contribuciones de cualquier píxel ‘k’ a (digamos) el x-gradiente (1,0) puede ser simplificada a «(valor de la diferencia sobre el cuadrado de la distancia) veces (DotProduct de no normalizados vector de dirección de » ok » con el vector gradiente, por ejemplo, (1,0) )»

    gx_k = (k - o)/(pixel distance^2) ['ok' dot (1,0)].
    

    Debido a que el producto escalar de la conexión de vector con el eje x de la unidad de vectores, se selecciona el correspondiente vector de entrada, la correspondiente G_x kernel de entrada en la posición k es simplemente

    i /(i*i + j*j)
    

    donde i y j son el número de pasos desde el centro del píxel a píxel k de x y de y dirección. En el anterior 3×3 de cálculo, el píxel de la ‘a’ se tiene i = -1 (1 a la izquierda), j = -1 (1 para la parte superior) y, por tanto, la ‘a’ entrada de kernel es -1 /(1 + 1) = -1/2.

    Las entradas para el G_y núcleo son

    j/(i*i + j*j). 
    

    Si quiero valores enteros de mi kernel, yo siga estos pasos:

    • de verificación de la gama disponible de la imagen de salida
    • calcular más alto posible resultado de la aplicación de punto flotante kernel (es decir, asumir la máxima de entrada valor por debajo de todos positiva del núcleo entradas, por lo que el valor de salida es (suma de todos los positivos núcleo de valores) * (máximo posible de la imagen de entrada de valor). Si usted ha firmado entrada, es necesario considerar los valores negativos también. Peor de los casos es entonces la suma de todos los valores positivos + suma de todos abs valores de anotaciones negativas (si max de entrada bajo positivos-max de entrada bajo negativos). edit: la suma de todos los abs valores también ha sido denominada acertadamente peso del núcleo
    • calcular el máximo permitido ampliar el kernel (sin desbordar el rango de salida de la imagen)
    • para todos los múltiplos enteros (de 2 a por encima del máximo) de punto flotante de kernel: compruebe que tiene la menor suma absoluta de los errores de redondeo y el uso de este kernel

    Así que en resumen:

    Gx_ij = i /(i*i + j*j)
    Gy_ij = j /(i*i + j*j)
    

    donde i,j es la posición en el núcleo contados a partir del centro. La escala del núcleo entradas según sea necesario para obtener los números enteros (o al menos cerca de aproximaciones).

    Estas fórmulas tienen validez para todos los tamaños de kernels.

    Ejemplos

              -2/8 -1/5  0  1/5  2/8           -5  -4  0   4   5
              -2/5 -1/2  0  1/2  2/5           -8 -10  0  10   8
    G_x (5x5) -2/4 -1/1  0  1/1  2/4  (*20) = -10 -20  0  20  10
              -2/5 -1/2  0  1/2  2/5           -8 -10  0  10   8
              -2/8 -1/5  0  1/5  2/8           -5  -4  0   4   5
    

    Tenga en cuenta que la central de 3×3 píxeles de la 5×5 núcleo de flotador de notación son sólo el 3×3 del núcleo, es decir, más grande núcleos representan una continua aproximación adicional pero inferior ponderado de los datos. Esto continúa a mayor tamaño de kernel:

               -3/18 -2/13 -1/10 0  1/10 2/13 3/18
               -3/13 -2/8  -1/5  0  1/5  2/8  3/13
               -3/10 -2/5  -1/2  0  1/2  2/5  3/10
    G_x (7x7)  -3/9  -2/4  -1/1  0  1/1  2/4  3/9 
               -3/10 -2/5  -1/2  0  1/2  2/5  3/10
               -3/13 -2/8  -1/5  0  1/5  2/8  3/13
               -3/18 -2/13 -1/10 0  1/10 2/13 3/18
    

    Exacta entero representaciones serán práctico en este punto.

    Como lo que puedo decir (no tener acceso al documento original), el «Sobel» parte de esto es ponderaciones de las contribuciones. El Prewitt solución puede ser obtenida por dejar fuera de la distancia de la ponderación y la que acaba de entrar i y j en el núcleo de la manera adecuada.

    Bono: Sobel Kernels para las direcciones arbitrarias

    Por lo que podemos aproximar las componentes x y y de la gradiente de la imagen (que en realidad es un vector, como se indica en el principio). El gradiente en cualquier dirección arbitraria alfa (mide matemáticamente positivo, en este caso de las agujas del reloj desde el eje y positivo es hacia abajo) puede ser obtenida por medio de la proyección del vector gradiente en el alfa-el gradiente de la unidad de vectores.

    El alfa-vector unitario es (cos alfa, el pecado alfa). Para alfa = 0°, se puede obtener el resultado para el gx, para alfa = 90°, se obtiene gy.

    g_alpha = (alpha-unit vector) dot (gx, gy)
            = (cos a, sin a) dot (gx, gy)
            = cos a * gx + sin a * gy
    

    Si te molesta que escriba gx y gy como sumas de vecino contribuciones, te das cuenta de que puede agrupar el resultado a largo expresión por los términos que se aplican a la misma píxeles vecinos, y luego reescribir esto como un único núcleo de circunvolución con entradas

    G_alpha_ij = (i * cos a + j * sin a)/(i*i + j*j)
    

    Si quieres el entero más cercano de aproximación, siga los pasos descritos anteriormente.

    • Gracias por la integral de escribir-up – esta es, obviamente, mucho más rigurosas que las aproximaciones de los NIH documento que he basado mi respuesta en.
    • Puedo obtener una respuesta diferente para este. Siguiente de Sobel descripción, estoy seguro de cómo todas las raíces se caen, y por qué tienen diferentes ponderaciones para G(1,2)=-4 y G(2,1)=-8. Ambos están a la misma distancia desde el centro donde la derivada es la que se mide, y deberían tener el mismo peso, no? Aquí es lo que me dieron cuando me trató de derivar NxN 2D operador de Sobel, tal vez me fue mal en algún sitio: reddit.com/r/computervision/comments/8e234p
    • Hola! El -4 y -8 no son debido a la diferente distancia de pesos, pero debido a lo que he llamado i y j, la distancia en la dirección del degradado desde el centro del elemento. Si las entradas son iguales, medir la diagonal de gradientes (en ese caso, una horizontal y vertical de la frontera obtendrían la misma respuesta de fuerza en el núcleo). La segunda raíz factor debe de venir de la ponderación de píxeles contribuciones a la inversa de la distancia, de la primera venida de normalización de la longitud de la «gradiente de contribución vector».
    • Oh, Oh. » la distancia en la dirección del degradado…» ver lo que se está diciendo. Y por lo tanto, por el centro de la fila/col es de ceros (quiero la proyección sobre la dirección del degradado). Yo era capaz parcialmente con éxito rederive el 3×3 caso haciendo todas las matemáticas con la mano, pero en lugar de 1 y 2, he sqrt(2)’s y 2. Es que sólo por aproximación o me estoy perdiendo de un paso? Cuando traté de dividirlos, todo lo cancela y me encuentro con Prewitt lugar. Totalmente de gracias. Yo estaba tratando de hacer pequeños cambios en ella para algo más, y esto realmente ayudó.
    • Voy a ampliar la exposición de la sección para el 3×3 del núcleo, los detalles son demasiado largas para un comentario
    • Este es un concepto interesante, ya que sigue Sobel original de derivación, pero no estoy seguro de que el filtro resultante tiene buenas propiedades. Usted puede hacer que el núcleo de tamaño muy grande, y de ver que no es fluida, mucho más que un pequeño núcleo (como entradas más aproximado a cero). También, no es separable, como el original Sobel kernel.
    • Una cosa a tener en cuenta, sin embargo: Si usted tiene una pendiente uniforme en una imagen, el menor factor de distancia se acaba de equilibrar el hecho de que la diferencia de valor es proporcionalmente más lejos de ir en la dirección del degradado. En ese caso especial, todos los píxeles en la dirección del degradado contribuir con la misma cantidad. En el caso más común de ruido o no-bastante uniformes gradientes, grandes núcleos de mejorar la realidad de suavizado. Para mis propósitos, 5×5 hasta ahora han sido en general bastante bien.
    • Hola @Daniel – ¿te importaría votar en la synonymization petición aquí? Estoy tratando de conseguir [borde] sinónimos con [edge detection], ya que se trata de la misma cosa, y que los usuarios sigan haciendo preguntas acerca de microsoft-borde utilizando el [borde] tag…

  4. 3

    Sobel filtro de degradado generador

    (Esta respuesta se refiere a la análisis dada por @Daniel, arriba).

    Gx[i,j] = i /(i*i + j*j)
    
    Gy[i,j] = j /(i*i + j*j)
    

    Este es un resultado importante, y una mejor explicación que se puede encontrar en la original en papel. Debe ser escrito en Wikipedia, o en otro lugar, porque también parece superior a cualquier otra discusión de la cuestión disponibles en internet.

    Sin embargo, no es realmente cierto que el valor entero representaciones no son prácticos para los filtros de tamaño mayor de 5*5, como se reivindica. El uso de números enteros de 64 bits, Sobel filtro con un tamaño de hasta 15*15 puede ser exactamente expresó.

    Aquí están los cuatro primeros; el resultado debe ser dividido por el «peso», por lo que el gradiente de una región de la imagen como la siguiente, es normalizado a un valor de 1.

    1 2 3 4 5
    1 2 3 4 5
    1 2 3 4 5
    1 2 3 4 5
    1 2 3 4 5
    

    Gx(3) :

    -1/2  0/1  1/2           -1  0  1
    -1/1    0  1/1   * 2 =   -2  0  2
    -1/2  0/1  1/2           -1  0  1
    
    weight = 4               weight = 8
    

    Gx(5) :

    -2/8 -1/5  0/4  1/5  2/8             -5  -4   0   4   5
    -2/5 -1/2  0/1  1/2  2/5             -8 -10   0  10   8
    -2/4 -1/1    0  1/1  2/4   * 20 =   -10 -20   0  20  10
    -2/5 -1/2  0/1  1/2  2/5             -8 -10   0  10   8
    -2/8 -1/5  0/4  1/5  2/8             -5  -4   0   4   5
    
    weight = 12                          weight = 240
    

    Gx(7) :

    -3/18 -2/13 -1/10   0/9  1/10  2/13  3/18             -130 -120  -78    0   78  120  130
    -3/13  -2/8  -1/5   0/4   1/5   2/8  3/13             -180 -195 -156    0  156  195  180
    -3/10  -2/5  -1/2   0/1   1/2   2/5  3/10             -234 -312 -390    0  390  312  234
     -3/9  -2/4  -1/1     0   1/1   2/4   3/9   * 780 =   -260 -390 -780    0  780  390  260
    -3/10  -2/5  -1/2   0/1   1/2   2/5  3/10             -234 -312 -390    0  390  312  234
    -3/13  -2/8  -1/5   0/4   1/5   2/8  3/13             -180 -195 -156    0  156  195  180
    -3/18 -2/13 -1/10   0/9  1/10  2/13  3/18             -130 -120  -78    0   78  120  130
    
    weight = 24                                           weight = 18720
    

    Gx(9) :

    -4/32 -3/25 -2/20 -1/17  0/16  1/17  2/20  3/25  4/32                -16575  -15912  -13260   -7800       0    7800   13260   15912   16575
    -4/25 -3/18 -2/13 -1/10   0/9  1/10  2/13  3/18  4/25                -21216  -22100  -20400  -13260       0   13260   20400   22100   21216
    -4/20 -3/13  -2/8  -1/5   0/4   1/5   2/8  3/13  4/20                -26520  -30600  -33150  -26520       0   26520   33150   30600   26520
    -4/17 -3/10  -2/5  -1/2   0/1   1/2   2/5  3/10  4/17                -31200  -39780  -53040  -66300       0   66300   53040   39780   31200
    -4/16  -3/9  -2/4  -1/1     0   1/1   2/4   3/9  4/16   * 132600 =   -33150  -44200  -66300 -132600       0  132600   66300   44200   33150
    -4/17 -3/10  -2/5  -1/2   0/1   1/2   2/5  3/10  4/17                -31200  -39780  -53040  -66300       0   66300   53040   39780   31200
    -4/20 -3/13  -2/8  -1/5   0/4   1/5   2/8  3/13  4/20                -26520  -30600  -33150  -26520       0   26520   33150   30600   26520
    -4/25 -3/18 -2/13 -1/10   0/9  1/10  2/13  3/18  4/25                -21216  -22100  -20400  -13260       0   13260   20400   22100   21216
    -4/32 -3/25 -2/20 -1/17  0/16  1/17  2/20  3/25  4/32                -16575  -15912  -13260   -7800       0    7800   13260   15912   16575
    
    weight = 40                                                          weight = 5304000
    

    El Rubí programa que se anexa a continuación, se calculan los filtros de Sobel y pesos correspondientes de cualquier tamaño, aunque el valor entero de los filtros no son susceptibles de ser útil para los tamaños de más de 15*15.

    #!/usr/bin/ruby
    # Sobel image gradient filter generator
    # by <[email protected]> -- Sept 2017
    # reference:
    # https://stackoverflow.com/questions/9567882/sobel-filter-kernel-of-large-size
    if (s = ARGV[0].to_i) < 3 || (s % 2) == 0
    $stderr.puts "invalid size"
    exit false
    end
    s /= 2
    n = 1
    # find least-common-multiple of all fractional denominators
    (0..s).each { |j|
    (1..s).each { |i|
    d = i*i + j*j
    n = n.lcm(d / d.gcd(i))
    }
    }
    fw1 = format("%d/%d", s, 2*s*s).size + 2
    fw2 = format("%d", n).size + 2
    weight = 0
    s1 = ""
    s2 = ""
    (-s..s).each { |y|
    (-s..s).each { |x|
    i, j = x, y   # "i, j = y, x" for transpose
    d = i*i + j*j
    if (i != 0)
    if (n * i % d) != 0   # this should never happen
    $stderr.puts "inexact division: #{n} * #{i} /((#{i})^2 + (#{j})^2)"
    exit false
    end
    w = n * i / d
    weight += i * w
    else
    w = 0
    end
    s1 += "%*s" % [fw1, d > 0 ? "%d/%d" % [i, d] : "0"]
    s2 += "%*d" % [fw2, w]
    }
    s1 += "\n" ; s2 += "\n"
    }
    f = n.gcd(weight)
    puts s1
    puts "\nweight = %d%s" % [weight/f, f < n ? "/%d" % (n/f) : ""]
    puts "\n* #{n} =\n\n"
    puts s2
    puts "\nweight = #{weight}"
  5. 2

    Rápidamente me hackeado un algoritmo para generar una Sobel núcleo de cualquier extraño tamaño > 1, basado en los ejemplos dados por @Pablo R:

        public static void CreateSobelKernel(int n, ref float[][] Kx, ref float[][] Ky)
    {
    int side = n * 2 + 3;
    int halfSide = side / 2;
    for (int i = 0; i < side; i++)
    {
    int k = (i <= halfSide) ? (halfSide + i) : (side + halfSide - i - 1);
    for (int j = 0; j < side; j++)
    {
    if (j < halfSide)
    Kx[i][j] = Ky[j][i] = j - k;
    else if (j > halfSide)
    Kx[i][j] = Ky[j][i] = k - (side - j - 1);
    else
    Kx[i][j] = Ky[j][i] = 0;
    }
    }
    }

    Espero que ayude.

  6. 2

    Aquí es una solución sencilla hecha con python 3 uso de numpy y @Daniel respuesta.

    def custom_sobel(shape, axis):
    """
    shape must be odd: eg. (5,5)
    axis is the direction, with 0 to positive x and 1 to positive y
    """
    k = np.zeros(shape)
    p = [(j,i) for j in range(shape[0]) 
    for i in range(shape[1]) 
    if not (i == (shape[1] -1)/2. and j == (shape[0] -1)/2.)]
    for j, i in p:
    j_ = int(j - (shape[0] -1)/2.)
    i_ = int(i - (shape[1] -1)/2.)
    k[j,i] = (i_ if axis==0 else j_)/float(i_*i_ + j_*j_)
    return k
    

    Devuelve el kernel (5,5) como este:

    Sobel x:
    [[-0.25 -0.2   0.    0.2   0.25]
    [-0.4  -0.5   0.    0.5   0.4 ]
    [-0.5  -1.    0.    1.    0.5 ]
    [-0.4  -0.5   0.    0.5   0.4 ]
    [-0.25 -0.2   0.    0.2   0.25]]
    Sobel y:
    [[-0.25 -0.4  -0.5  -0.4  -0.25]
    [-0.2  -0.5  -1.   -0.5  -0.2 ]
    [ 0.    0.    0.    0.    0.  ]
    [ 0.2   0.5   1.    0.5   0.2 ]
    [ 0.25  0.4   0.5   0.4   0.25]]
    

    Si alguien sabe una mejor manera de hacer eso en python, por favor hágamelo saber. Soy un novato todavía 😉

  7. 1

    Como Adam Bowen explicó en su respuesta, el Sobel kernel es una combinación de un suavizado a lo largo de un eje, y una central de diferencia derivado a lo largo del otro eje:

    sob3x3 = [1 2 1]' * [1 0 -1]
    

    El suavizado añade regularización (reduce la sensibilidad al ruido).

    (Estoy dejando fuera todos los factores 1/8 en este post, como hizo Sobel mismo, lo que significa que el operador determina la derivada hasta el escalado. También, * siempre significa convolución en este post.)

    Vamos a generalizar este:

    deriv_kernel = smoothing_kernel * d/dx
    

    Una de las propiedades de la convolución es que

    d/dx f = d/dx * f
    

    Que es, convolving una imagen con el elemental operador de la derivada de los rendimientos de la derivada de la imagen. Tomando nota también de que la convolución es conmutativa,

    deriv_kernel = d/dx * smoothing_kernel = d/dx smoothing_kernel
    

    Que es, la derivada de kernel es la derivada de una suavizado kernel.

    Nota de que la aplicación de dicho núcleo, a una imagen de convolución:

    image * deriv_kernel = image * smoothing_kernel * d/dx = d/dx (image * smoothing_kernel)
    

    Que es, con esta generalizada, idealizado derivados del núcleo podemos calcular el verdadero derivados de suavizado de la imagen. Esto por supuesto no es el caso con la Sobel kernel, ya que utiliza una central de diferencia en la aproximación a la derivada.
    Pero la elección de un mejor smoothing_kernel, esto puede lograrse. El núcleo Gaussiano es la opción ideal aquí, ya que ofrece el mejor compromiso entre la compacidad en el dominio espacial (pequeño núcleo de la huella) con la compacidad en el dominio de la frecuencia (bueno suavizado). Además, el Gauss es perfectamente isotrópica y separables. El uso de una Gaussiana derivado del núcleo de los rendimientos de la mejor manera posible regularización de operador de la derivada.

    Por lo tanto, si usted está buscando para una mayor operador de Sobel, porque se necesita más de regularización, el uso de una Gaussiana operador de la derivada de lugar.


    Vamos a analizar la Sobel kernel un poco más.

    El suavizado kernel es triangular, con muestras de [1 2 1]. Esta es una función triangular, la cual, muestra, conduce a que esos tres valores:

          2 + x ,   if -2 < x < 0
    h = { 2     ,   if x = 0
    2 - x ,   if 0 < x < 2
    

    Su derivada es:

                1 ,   if -2 < x < 0
    d/dx h = {  0 ,   if x = 0        (not really, but it's the sensible solution)
    -1 ,   if 0 < x < 2
    

    Así, podemos ver que la diferencia central derivado de la aproximación puede ser visto como una muestra de los analíticos derivados de la misma triangular de la función que se utiliza para alisar. Así tenemos:

    sob3x3 = [1 2 1]' * d/dx [1 2 1] = d/dx ( [1 2 1]' * [1 2 1] )
    

    Por lo tanto, si usted quiere hacer este núcleo más grande, simplemente agrandar el suavizado kernel:

    sob5x5 = d/dx ( [1 2 3 2 1]' * [1 2 3 2 1] ) = [1 2 3 2 1]' * [1 1 0 -1 -1]
    sob7x7 = d/dx ( [1 2 3 4 3 2 1]' * [1 2 3 4 3 2 1] ) = [1 2 3 4 3 2 1]' * [1 1 1 0 -1 -1 -1]
    

    Esto es muy diferente de la consejo dado por Adam Bowen, que sugiere convolving el kernel con el 3-ficha triangular del núcleo a lo largo de cada dimensión: [1 2 1] * [1 2 1] = [1 4 6 4 1], y [1 2 1] * [1 0 -1] = [1 2 0 -2 -1]. Tenga en cuenta que, debido al teorema del límite central, convolving este kernel triangular con sí misma conduce a un filtro que se aproxima a la de Gauss un poco más. El más grande es el kernel que crear por repetidas circunvoluciones con sí mismo, más se aproxima a este Gaussiano. Así, en lugar de utilizar este método, usted puede ser que también muestra directamente la función de Gauss.

    Daniel tiene un largo post en el que se sugiere la ampliación de la Sobel kernel en otro sentido. La forma de la suavizado kernel aquí difiere de la aproximación Gaussiana, no he probado el estudio de sus propiedades.

    Tenga en cuenta que ninguno de estos tres posibles extensiones de la Sobel núcleo son en realidad Sobel núcleos, ya que el Sobel kernel es explícitamente un 3×3 kernel (véase la nota histórica por Sobel acerca de su operador, el cual nunca llegó a publicarse).

    Nota también de que yo no estoy abogando por la extendida Sobel núcleo derivados de aquí. El uso de Gauss derivados!

  8. 0

    Gracias por todo, voy a tratar de segunda variante por @Adam Bowen, tomar el código de C# para Sobel5x5, 7×7, 9×9… matriz generaion para esta variante (tal vez con errores, si te encuentras a error o puede optimizar el código de escritura que hay):

        static void Main(string[] args)
    {
    float[,] Sobel3x3 = new float[,] {
    { -1, 0, 1},
    { -2, 0, 2},
    { -1, 0, 1}};
    float[,] Sobel5x5 = Conv2DforSobelOperator(Sobel3x3);
    float[,] Sobel7x7 = Conv2DforSobelOperator(Sobel5x5);
    Console.ReadKey();
    }
    public static float[,] Conv2DforSobelOperator(float[,] Kernel)
    {
    if (Kernel == null)
    throw new Exception("Kernel = null");
    if (Kernel.GetLength(0) != Kernel.GetLength(1))
    throw new Exception("Kernel matrix must be Square matrix!");
    float[,] BaseMatrix = new float[,] {
    {1, 2, 1},
    {2, 4, 2},
    {1, 2, 1}};
    int KernelSize = Kernel.GetLength(0);
    int HalfKernelSize = KernelSize /2;
    int OutSize = KernelSize + 2;
    if ((KernelSize & 1) == 0) //Kernel_Size must be: 3, 5, 7, 9 ...
    throw new Exception("Kernel size must be odd (3x3, 5x5, 7x7...)");
    float[,] Out = new float[OutSize, OutSize];
    float[,] InMatrix = new float[OutSize, OutSize];
    for (int x = 0; x < BaseMatrix.GetLength(0); x++)
    for (int y = 0; y < BaseMatrix.GetLength(1); y++)
    InMatrix[HalfKernelSize + x, HalfKernelSize + y] = BaseMatrix[x, y];
    for (int x = 0; x < OutSize; x++)
    for (int y = 0; y < OutSize; y++)
    for (int Kx = 0; Kx < KernelSize; Kx++)
    for (int Ky = 0; Ky < KernelSize; Ky++)
    {
    int X = x + Kx - HalfKernelSize;
    int Y = y + Ky - HalfKernelSize;
    if (X >= 0 && Y >= 0 && X < OutSize && Y < OutSize)
    Out[x, y] += InMatrix[X, Y] * Kernel[KernelSize - 1 - Kx, KernelSize - 1 - Ky];
    }
    return Out;
    }
    

    Resultados (Mapeado Normal) o se copia allí, donde esta metod – №2, @Pablo R metod – №1. Ahora estoy usando el último, porque dan más resultado sin problemas y es fácil de generar núcleos con este código.

  9. 0

    Implementación en Matlab de Daniel respuesta:

    kernel_width = 9;
    halfway = floor(kernel_width/2);
    step = -halfway : halfway;
    i_matrix = repmat(step,[kernel_width 1]);
    j_matrix = i_matrix';
    gx = i_matrix ./( i_matrix.*i_matrix + j_matrix.*j_matrix );
    gx(halfway+1,halfway+1) = 0; % deals with NaN in middle
    gy = gx';
    

Dejar respuesta

Please enter your comment!
Please enter your name here