scikit - skimage python install




Detección de picos en una matriz 2D (14)

Solución

Archivo de datos: paw.txt . Código fuente:

from scipy import *
from operator import itemgetter

n = 5  # how many fingers are we looking for

d = loadtxt("paw.txt")
width, height = d.shape

# Create an array where every element is a sum of 2x2 squares.

fourSums = d[:-1,:-1] + d[1:,:-1] + d[1:,1:] + d[:-1,1:]

# Find positions of the fingers.

# Pair each sum with its position number (from 0 to width*height-1),

pairs = zip(arange(width*height), fourSums.flatten())

# Sort by descending sum value, filter overlapping squares

def drop_overlapping(pairs):
    no_overlaps = []
    def does_not_overlap(p1, p2):
        i1, i2 = p1[0], p2[0]
        r1, col1 = i1 / (width-1), i1 % (width-1)
        r2, col2 = i2 / (width-1), i2 % (width-1)
        return (max(abs(r1-r2),abs(col1-col2)) >= 2)
    for p in pairs:
        if all(map(lambda prev: does_not_overlap(p,prev), no_overlaps)):
            no_overlaps.append(p)
    return no_overlaps

pairs2 = drop_overlapping(sorted(pairs, key=itemgetter(1), reverse=True))

# Take the first n with the heighest values

positions = pairs2[:n]

# Print results

print d, "\n"

for i, val in positions:
    row = i / (width-1)
    column = i % (width-1)
    print "sum = %f @ %d,%d (%d)" % (val, row, column, i)
    print d[row:row+2,column:column+2], "\n"

Output sin cuadrados superpuestos. Parece que se seleccionan las mismas áreas que en tu ejemplo.

Algunos comentarios

La parte difícil es calcular sumas de todos los cuadrados 2x2. Asumí que los necesita todos, por lo que podría haber alguna superposición. Utilicé cortes para cortar las primeras / últimas columnas y filas de la matriz 2D original, y luego las superpongo todas juntas y calculando sumas.

Para entenderlo mejor, imaginando una matriz de 3x3:

>>> a = arange(9).reshape(3,3) ; a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

Luego puedes tomar sus rodajas:

>>> a[:-1,:-1]
array([[0, 1],
       [3, 4]])
>>> a[1:,:-1]
array([[3, 4],
       [6, 7]])
>>> a[:-1,1:]
array([[1, 2],
       [4, 5]])
>>> a[1:,1:]
array([[4, 5],
       [7, 8]])

Ahora imagina que los apilas uno encima del otro y sumas los elementos en las mismas posiciones. Estas sumas serán exactamente las mismas sumas en los cuadrados 2x2 con la esquina superior izquierda en la misma posición:

>>> sums = a[:-1,:-1] + a[1:,:-1] + a[:-1,1:] + a[1:,1:]; sums
array([[ 8, 12],
       [20, 24]])

Cuando tenga las sumas de más de 2x2 cuadrados, puede usar max para encontrar el máximo, u sort , u sorted para encontrar los picos.

Para recordar las posiciones de los picos, acoplo cada valor (la suma) con su posición ordinal en una matriz aplanada (ver zip ). Luego calculo la posición de la fila / columna nuevamente cuando imprimo los resultados.

Notas

Permití que los cuadrados de 2x2 se superpongan. La versión editada filtra algunos de ellos de modo que solo aparecen cuadrados no superpuestos en los resultados.

Elegir los dedos (una idea)

Otro problema es cómo elegir qué es probable que sean dedos de todos los picos. Tengo una idea que puede o no funcionar. No tengo tiempo para implementarlo ahora, así que solo pseudo-código.

Noté que si los dedos delanteros permanecen en casi un círculo perfecto, el dedo trasero debería estar dentro de ese círculo. Además, los dedos frontales están más o menos separados por igual. Podemos tratar de usar estas propiedades heurísticas para detectar los dedos.

Pseudo código:

select the top N finger candidates (not too many, 10 or 12)
consider all possible combinations of 5 out of N (use itertools.combinations)
for each combination of 5 fingers:
    for each finger out of 5:
        fit the best circle to the remaining 4
        => position of the center, radius
        check if the selected finger is inside of the circle
        check if the remaining four are evenly spread
        (for example, consider angles from the center of the circle)
        assign some cost (penalty) to this selection of 4 peaks + a rear finger
        (consider, probably weighted:
             circle fitting error,
             if the rear finger is inside,
             variance in the spreading of the front fingers,
             total intensity of 5 peaks)
choose a combination of 4 peaks + a rear peak with the lowest penalty

Este es un enfoque de fuerza bruta. Si N es relativamente pequeño, entonces creo que es factible. Para N = 12, hay C_12 ^ 5 = 792 combinaciones, multiplicado por 5 formas de seleccionar un dedo trasero, por lo que hay 3960 casos que evaluar para cada pata.

Estoy ayudando a una clínica veterinaria midiendo la presión bajo la pata de un perro. Utilizo Python para mi análisis de datos y ahora estoy atascado tratando de dividir las patas en subregiones (anatómicas).

Hice una matriz 2D de cada pata, que consta de los valores máximos para cada sensor que la pata ha cargado a lo largo del tiempo. Aquí hay un ejemplo de una pata, donde utilicé Excel para dibujar las áreas que quiero "detectar". Estas son cajas de 2 por 2 alrededor del sensor con máximos locales, que en conjunto tienen la suma más grande.

Así que probé algunos experimentos y decidí buscar simplemente los máximos de cada columna y fila (no puedo mirar en una dirección debido a la forma de la pata). Esto parece "detectar" bastante bien la ubicación de los dedos separados, pero también marca los sensores vecinos.

Entonces, ¿cuál sería la mejor manera de decirle a Python cuáles de estos máximos son los que quiero?

Nota: ¡Los cuadrados 2x2 no pueden superponerse, ya que tienen que ser dedos separados!

También tomé 2x2 como una conveniencia, cualquier solución más avanzada es bienvenida, pero soy simplemente un científico del movimiento humano, así que no soy ni un verdadero programador ni un matemático, así que manténgalo "simple".

Aquí hay una versión que se puede cargar con np.loadtxt

Resultados

Así que probé la solución de @jextee (ver los resultados a continuación). Como puede ver, funciona muy bien en las patas delanteras, pero funciona menos bien para las patas traseras.

Más específicamente, no puede reconocer el pequeño pico que es el cuarto dedo del pie. Obviamente, esto es inherente al hecho de que el bucle se ve de arriba abajo hacia el valor más bajo, sin tener en cuenta dónde está.

¿Alguien sabría cómo modificar el algoritmo de @ jextee para que también pueda encontrar el 4to dedo?

Como todavía no he procesado ningún otro ensayo, no puedo suministrar ninguna otra muestra. Pero los datos que di antes eran los promedios de cada pata. Este archivo es una matriz con los datos máximos de 9 patas en el orden en que hicieron contacto con la placa.

Esta imagen muestra cómo se dispersaron espacialmente sobre la placa.

Actualizar:

He configurado un blog para cualquier persona interesada y he configurado un SkyDrive con todas las mediciones en bruto. Así que para cualquiera que solicite más datos: ¡más poder para usted!

Nueva actualización:

Así que después de la ayuda que recibí con mis preguntas sobre la detección de patas y la clasificación de las patas , ¡finalmente pude verificar la detección de cada dedo! Resulta que no funciona tan bien en nada que no sean patas del tamaño de mi ejemplo. Por supuesto, en retrospectiva, es mi culpa por haber elegido el 2x2 de manera tan arbitraria.

Este es un buen ejemplo de dónde sale mal: un clavo se reconoce como un dedo del pie y el "talón" es tan ancho que se reconoce dos veces.

La pata es demasiado grande, por lo que al tomar un tamaño de 2x2 sin superposición, algunos dedos se detectan dos veces. A la inversa, en los perros pequeños a menudo no encuentra un quinto dedo del pie, que sospecho que está siendo causado por el área 2x2 que es demasiado grande.

Después de probar la solución actual en todas mis medidas , llegué a la asombrosa conclusión de que para casi todos mis perros pequeños no encontraba un quinto dedo y que en más del 50% de los impactos para los perros grandes, ¡encontraría más!

Claramente necesito cambiarlo. Mi propia suposición era cambiar el tamaño del neighborhood a algo más pequeño para perros pequeños y más grande para perros grandes. Pero generate_binary_structure no me permitiría cambiar el tamaño de la matriz.

Por lo tanto, espero que alguien más tenga una mejor sugerencia para ubicar los dedos de los pies, ¿quizás tenga la escala del área del dedo del pie con el tamaño de la pata?


Al usar homología persistente para analizar su conjunto de datos, obtengo el siguiente resultado (haga clic para ampliar):

Esta es la versión 2D del método de detección de picos descrito en esta respuesta SO . La figura anterior simplemente muestra clases de homología persistente en 0 dimensiones ordenadas por persistencia.

Hice un aumento de escala del conjunto de datos original por un factor de 2 usando scipy.misc.imresize (). Sin embargo, tenga en cuenta que consideré las cuatro patas como un conjunto de datos; dividirlo en cuatro facilitaría el problema.

Metodología. La idea detrás de esto es bastante simple: considere la función gráfica de la función que asigna a cada píxel su nivel. Se parece a esto:

Ahora considere un nivel de agua en la altura 255 que desciende continuamente a niveles más bajos. En las islas locales máximas emergente (nacimiento). En los puntos de silla se unen dos islas; consideramos que la isla inferior se fusiona con la isla superior (muerte). El llamado diagrama de persistencia (de las clases de homología tridimensional, nuestras islas) muestra la muerte sobre los valores de nacimiento de todas las islas:

La persistencia de una isla es, entonces, la diferencia entre el nivel de nacimiento y el nivel de muerte; La distancia vertical de un punto a la diagonal principal gris. La figura etiqueta las islas al disminuir la persistencia.

La primera imagen muestra la ubicación de los nacimientos de las islas. Este método no solo da los máximos locales sino que también cuantifica su "significado" por la persistencia mencionada anteriormente. Uno entonces filtraría todas las islas con una persistencia demasiado baja. Sin embargo, en su ejemplo, cada isla (es decir, cada máximo local) es un pico que busca.

El código de Python se puede encontrar here .


Aquí hay una idea: se calcula el laplaciano (discreto) de la imagen. Espero que sea (negativo y) grande en los máximos, de una manera más dramática que en las imágenes originales. Por lo tanto, los máximos podrían ser más fáciles de encontrar.

Aquí hay otra idea: si conoce el tamaño típico de los puntos de alta presión, primero puede suavizar su imagen por convolutivo con un gaussiano del mismo tamaño. Esto le puede dar imágenes más simples para procesar.


Bueno, aquí hay un código simple y no muy eficiente, pero para este tamaño de conjunto de datos está bien.

import numpy as np
grid = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
              [0,0,0,0,0,0,0,0,0.4,0.4,0.4,0,0,0],
              [0,0,0,0,0.4,1.4,1.4,1.8,0.7,0,0,0,0,0],
              [0,0,0,0,0.4,1.4,4,5.4,2.2,0.4,0,0,0,0],
              [0,0,0.7,1.1,0.4,1.1,3.2,3.6,1.1,0,0,0,0,0],
              [0,0.4,2.9,3.6,1.1,0.4,0.7,0.7,0.4,0.4,0,0,0,0],
              [0,0.4,2.5,3.2,1.8,0.7,0.4,0.4,0.4,1.4,0.7,0,0,0],
              [0,0,0.7,3.6,5.8,2.9,1.4,2.2,1.4,1.8,1.1,0,0,0],
              [0,0,1.1,5,6.8,3.2,4,6.1,1.8,0.4,0.4,0,0,0],
              [0,0,0.4,1.1,1.8,1.8,4.3,3.2,0.7,0,0,0,0,0],
              [0,0,0,0,0,0.4,0.7,0.4,0,0,0,0,0,0]])

arr = []
for i in xrange(grid.shape[0] - 1):
    for j in xrange(grid.shape[1] - 1):
        tot = grid[i][j] + grid[i+1][j] + grid[i][j+1] + grid[i+1][j+1]
        arr.append([(i,j),tot])

best = []

arr.sort(key = lambda x: x[1])

for i in xrange(5):
    best.append(arr.pop())
    badpos = set([(best[-1][0][0]+x,best[-1][0][1]+y)
                  for x in [-1,0,1] for y in [-1,0,1] if x != 0 or y != 0])
    for j in xrange(len(arr)-1,-1,-1):
        if arr[j][0] in badpos:
            arr.pop(j)


for item in best:
    print grid[item[0][0]:item[0][0]+2,item[0][1]:item[0][1]+2]

Básicamente, solo hago una matriz con la posición de la esquina superior izquierda y la suma de cada cuadrado 2x2 y la ordeno por la suma. Luego tomo el cuadrado 2x2 con la suma más alta fuera de la disputa, lo puse en la bestmatriz y elimino todos los demás cuadrados 2x2 que usaron cualquier parte de este cuadrado eliminado de 2x2.

Parece que funciona bien, excepto con la última pata (la que tiene la suma más pequeña en el extremo derecho de la primera imagen), resulta que hay otros dos cuadrados de 2x2 elegibles con una suma más grande (y tienen una suma igual a El uno al otro). Uno de ellos sigue seleccionando un cuadrado de tu cuadrado 2x2, pero el otro está a la izquierda. Afortunadamente, por suerte, vemos que elegimos más de la que usted desearía, pero esto puede requerir que se usen algunas otras ideas para obtener lo que realmente desea todo el tiempo.


Este es un problema de registro de imagen . La estrategia general es:

  • Tenga un ejemplo conocido, o algún tipo de previo en los datos.
  • Ajuste sus datos al ejemplo, o ajuste el ejemplo a sus datos.
  • Ayuda si sus datos están alineados aproximadamente en primer lugar.

Aquí hay un acercamiento rudo y listo , "la cosa más tonta que podría funcionar":

  • Comience con cinco coordenadas de punta en aproximadamente el lugar que espera.
  • Con cada una de ellas, suba iterativamente a la cima de la colina. es decir, dada la posición actual, mover al píxel vecino máximo, si su valor es mayor que el píxel actual. Detente cuando las coordenadas de tu pie hayan dejado de moverse.

Para contrarrestar el problema de orientación, podría tener 8 o más ajustes iniciales para las direcciones básicas (Norte, Noreste, etc.). Ejecuta cada uno individualmente y tira cualquier resultado donde dos o más dedos terminen en el mismo píxel. Pensaré en esto un poco más, pero este tipo de cosas todavía se está investigando en el procesamiento de imágenes. ¡No hay respuestas correctas!

Idea un poco más compleja: (ponderada) K-significa agrupación. No está tan mal.

  • Comience con cinco coordenadas de punta, pero ahora estos son "centros de clúster".

Luego iterar hasta la convergencia:

  • Asigne cada píxel al clúster más cercano (solo haga una lista para cada clúster).
  • Calcula el centro de masa de cada grupo. Para cada grupo, esto es: Suma (coordenada * valor de intensidad) / Suma (coordenada)
  • Mueva cada grupo al nuevo centro de masa.

Es casi seguro que este método dará resultados mucho mejores, y obtendrá la masa de cada grupo, lo que puede ayudar a identificar los dedos de los pies.

(Una vez más, ha especificado la cantidad de agrupaciones por adelantado. Con la agrupación debe especificar la densidad de una forma u otra: elija la cantidad de agrupaciones, apropiada en este caso, o elija un radio de agrupación y vea cuántas finaliza con. Un ejemplo de este último es mean-shift .)

Lo siento por la falta de detalles de implementación u otros detalles. Yo codificaría esto pero tengo una fecha límite. Si nada más ha funcionado la próxima semana, avíseme y le daré una oportunidad.


Este problema ha sido estudiado con cierta profundidad por los físicos. Hay una buena implementación en ROOT . Mire las clases de TSpectrum (especialmente TSpectrum2 para su caso) y la documentación para ellas.

Referencias:

  1. M.Morhac et al .: Métodos de eliminación de fondo para espectros de rayos gamma de coincidencia multidimensional. Instrumentos y métodos nucleares en la investigación de física A 401 (1997) 113-132.
  2. M.Morhac et al .: eficiente deconvolución de oro en una y dos dimensiones y su aplicación a la descomposición de espectros de rayos gamma. Instrumentos y métodos nucleares en la investigación de física A 401 (1997) 385-408.
  3. M.Morhac et al .: Identificación de picos en espectros de rayos gamma de coincidencia multidimensional. Instrumentos y métodos nucleares en la investigación física A 443 (2000), 108-125.

... y para aquellos que no tienen acceso a una suscripción a NIM:


Gracias por los datos en bruto. Estoy en el tren y esto es lo que he llegado (mi parada se acerca). Le di masajes a su archivo txt con expresiones regulares y lo coloqué en una página html con algún javascript para visualización. Lo estoy compartiendo aquí porque algunos, como yo, pueden encontrarlo más fácilmente hackeable que python.

Creo que un buen enfoque será invariante de escala y rotación, y mi próximo paso será investigar las mezclas de gaussianos. (cada almohadilla de la pata es el centro de un gaussiano).

    <html>
<head>
    <script type="text/javascript" src="http://vis.stanford.edu/protovis/protovis-r3.2.js"></script> 
    <script type="text/javascript">
    var heatmap = [[[0,0,0,0,0,0,0,4,4,0,0,0,0],
[0,0,0,0,0,7,14,22,18,7,0,0,0],
[0,0,0,0,11,40,65,43,18,7,0,0,0],
[0,0,0,0,14,61,72,32,7,4,11,14,4],
[0,7,14,11,7,22,25,11,4,14,65,72,14],
[4,29,79,54,14,7,4,11,18,29,79,83,18],
[0,18,54,32,18,43,36,29,61,76,25,18,4],
[0,4,7,7,25,90,79,36,79,90,22,0,0],
[0,0,0,0,11,47,40,14,29,36,7,0,0],
[0,0,0,0,4,7,7,4,4,4,0,0,0]
],[
[0,0,0,4,4,0,0,0,0,0,0,0,0],
[0,0,11,18,18,7,0,0,0,0,0,0,0],
[0,4,29,47,29,7,0,4,4,0,0,0,0],
[0,0,11,29,29,7,7,22,25,7,0,0,0],
[0,0,0,4,4,4,14,61,83,22,0,0,0],
[4,7,4,4,4,4,14,32,25,7,0,0,0],
[4,11,7,14,25,25,47,79,32,4,0,0,0],
[0,4,4,22,58,40,29,86,36,4,0,0,0],
[0,0,0,7,18,14,7,18,7,0,0,0,0],
[0,0,0,0,4,4,0,0,0,0,0,0,0],
],[
[0,0,0,4,11,11,7,4,0,0,0,0,0],
[0,0,0,4,22,36,32,22,11,4,0,0,0],
[4,11,7,4,11,29,54,50,22,4,0,0,0],
[11,58,43,11,4,11,25,22,11,11,18,7,0],
[11,50,43,18,11,4,4,7,18,61,86,29,4],
[0,11,18,54,58,25,32,50,32,47,54,14,0],
[0,0,14,72,76,40,86,101,32,11,7,4,0],
[0,0,4,22,22,18,47,65,18,0,0,0,0],
[0,0,0,0,4,4,7,11,4,0,0,0,0],
],[
[0,0,0,0,4,4,4,0,0,0,0,0,0],
[0,0,0,4,14,14,18,7,0,0,0,0,0],
[0,0,0,4,14,40,54,22,4,0,0,0,0],
[0,7,11,4,11,32,36,11,0,0,0,0,0],
[4,29,36,11,4,7,7,4,4,0,0,0,0],
[4,25,32,18,7,4,4,4,14,7,0,0,0],
[0,7,36,58,29,14,22,14,18,11,0,0,0],
[0,11,50,68,32,40,61,18,4,4,0,0,0],
[0,4,11,18,18,43,32,7,0,0,0,0,0],
[0,0,0,0,4,7,4,0,0,0,0,0,0],
],[
[0,0,0,0,0,0,4,7,4,0,0,0,0],
[0,0,0,0,4,18,25,32,25,7,0,0,0],
[0,0,0,4,18,65,68,29,11,0,0,0,0],
[0,4,4,4,18,65,54,18,4,7,14,11,0],
[4,22,36,14,4,14,11,7,7,29,79,47,7],
[7,54,76,36,18,14,11,36,40,32,72,36,4],
[4,11,18,18,61,79,36,54,97,40,14,7,0],
[0,0,0,11,58,101,40,47,108,50,7,0,0],
[0,0,0,4,11,25,7,11,22,11,0,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
],[
[0,0,4,7,4,0,0,0,0,0,0,0,0],
[0,0,11,22,14,4,0,4,0,0,0,0,0],
[0,0,7,18,14,4,4,14,18,4,0,0,0],
[0,4,0,4,4,0,4,32,54,18,0,0,0],
[4,11,7,4,7,7,18,29,22,4,0,0,0],
[7,18,7,22,40,25,50,76,25,4,0,0,0],
[0,4,4,22,61,32,25,54,18,0,0,0,0],
[0,0,0,4,11,7,4,11,4,0,0,0,0],
],[
[0,0,0,0,7,14,11,4,0,0,0,0,0],
[0,0,0,4,18,43,50,32,14,4,0,0,0],
[0,4,11,4,7,29,61,65,43,11,0,0,0],
[4,18,54,25,7,11,32,40,25,7,11,4,0],
[4,36,86,40,11,7,7,7,7,25,58,25,4],
[0,7,18,25,65,40,18,25,22,22,47,18,0],
[0,0,4,32,79,47,43,86,54,11,7,4,0],
[0,0,0,14,32,14,25,61,40,7,0,0,0],
[0,0,0,0,4,4,4,11,7,0,0,0,0],
],[
[0,0,0,0,4,7,11,4,0,0,0,0,0],
[0,4,4,0,4,11,18,11,0,0,0,0,0],
[4,11,11,4,0,4,4,4,0,0,0,0,0],
[4,18,14,7,4,0,0,4,7,7,0,0,0],
[0,7,18,29,14,11,11,7,18,18,4,0,0],
[0,11,43,50,29,43,40,11,4,4,0,0,0],
[0,4,18,25,22,54,40,7,0,0,0,0,0],
[0,0,4,4,4,11,7,0,0,0,0,0,0],
],[
[0,0,0,0,0,7,7,7,7,0,0,0,0],
[0,0,0,0,7,32,32,18,4,0,0,0,0],
[0,0,0,0,11,54,40,14,4,4,22,11,0],
[0,7,14,11,4,14,11,4,4,25,94,50,7],
[4,25,65,43,11,7,4,7,22,25,54,36,7],
[0,7,25,22,29,58,32,25,72,61,14,7,0],
[0,0,4,4,40,115,68,29,83,72,11,0,0],
[0,0,0,0,11,29,18,7,18,14,4,0,0],
[0,0,0,0,0,4,0,0,0,0,0,0,0],
]
];
</script>
</head>
<body>
    <script type="text/javascript+protovis">    
    for (var a=0; a < heatmap.length; a++) {
    var w = heatmap[a][0].length,
    h = heatmap[a].length;
var vis = new pv.Panel()
    .width(w * 6)
    .height(h * 6)
    .strokeStyle("#aaa")
    .lineWidth(4)
    .antialias(true);
vis.add(pv.Image)
    .imageWidth(w)
    .imageHeight(h)
    .image(pv.Scale.linear()
        .domain(0, 99, 100)
        .range("#000", "#fff", '#ff0a0a')
        .by(function(i, j) heatmap[a][j][i]));
vis.render();
}
</script>
  </body>
</html>


La solución del físico:
Defina 5 marcadores de pata identificados por sus posiciones X_i e inicie con posiciones aleatorias. Defina alguna función de energía combinando algún premio por la ubicación de marcadores en las posiciones de las patas con algún castigo por la superposición de marcadores; digamos:

E(X_i;S)=-Sum_i(S(X_i))+alfa*Sum_ij (|X_i-Xj|<=2*sqrt(2)?1:0)

( S(X_i) es la fuerza media en 2x2 al cuadrado alrededor de X_i , alfa es un parámetro que debe alcanzarse como máximo experimentalmente)

Ahora es el momento de hacer algo de magia Metropolis-Hastings:
1. Seleccione un marcador aleatorio y muévalo un píxel en dirección aleatoria.
2. Calcula dE, la diferencia de energía causada por este movimiento.
3. Obtenga un número aleatorio uniforme de 0-1 y llámelo r.
4. Si dE<0 o exp(-beta*dE)>r , acepte el movimiento y vaya a 1; Si no, deshaga el movimiento y vaya a 1.
Esto debe repetirse hasta que los marcadores converjan en patas. Beta controla el escaneo para optimizar la compensación, por lo que también debe optimizarse experimentalmente; También se puede aumentar constantemente con el tiempo de simulación (recocido simulado).



Solo un par de ideas de la cabeza:

  • tomar el gradiente (derivado) del escaneo, ver si eso elimina las llamadas falsas
  • Aprovecha al máximo los máximos locales.

También es posible que desee echar un vistazo a OpenCV , tiene una API de Python bastante decente y podría tener algunas funciones que le serían útiles.


No estoy seguro de que esto responda a la pregunta, pero parece que solo puede buscar los n picos más altos que no tienen vecinos.

Aquí está la esencia. Tenga en cuenta que está en Ruby, pero la idea debe ser clara.

require 'pp'

NUM_PEAKS = 5
NEIGHBOR_DISTANCE = 1

data = [[1,2,3,4,5],
        [2,6,4,4,6],
        [3,6,7,4,3],
       ]

def tuples(matrix)
  tuples = []
  matrix.each_with_index { |row, ri|
    row.each_with_index { |value, ci|
      tuples << [value, ri, ci]
    }
  }
  tuples
end

def neighbor?(t1, t2, distance = 1)
  [1,2].each { |axis|
    return false if (t1[axis] - t2[axis]).abs > distance
  }
  true
end

# convert the matrix into a sorted list of tuples (value, row, col), highest peaks first
sorted = tuples(data).sort_by { |tuple| tuple.first }.reverse

# the list of peaks that don't have neighbors
non_neighboring_peaks = []

sorted.each { |candidate|
  # always take the highest peak
  if non_neighboring_peaks.empty?
    non_neighboring_peaks << candidate
    puts "took the first peak: #{candidate}"
  else
    # check that this candidate doesn't have any accepted neighbors
    is_ok = true
    non_neighboring_peaks.each { |accepted|
      if neighbor?(candidate, accepted, NEIGHBOR_DISTANCE)
        is_ok = false
        break
      end
    }
    if is_ok
      non_neighboring_peaks << candidate
      puts "took #{candidate}"
    else
      puts "denied #{candidate}"
    end
  end
}

pp non_neighboring_peaks

Qué sucede si avanza paso a paso: primero localiza el máximo global, procesa, si es necesario, los puntos circundantes según su valor, luego establece la región encontrada en cero y repite para la siguiente.



Parece que puedes engañar un poco usando el algoritmo de Jetxee. Él está encontrando bien los primeros tres dedos, y deberías poder adivinar dónde se basa el cuarto.





image-processing