algorithm - recognition - microsoft vision pricing
MediciĆ³n del grosor medio de trazas en una imagen. (7)
Aquí hay una respuesta que funciona en cualquier lenguaje de computadora sin la necesidad de funciones especiales ...
Idea básica: intente colocar un círculo en las áreas negras de la imagen. Si puedes, prueba con un círculo más grande.
Algoritmo:
- establecer fondo de imagen = 0 y traza = 1
- inicializar el resultado de la matriz []
- establecer minimalExpectedWidth
- establece w = minimalExpectedWidth
- lazo
- configurar contador = 0
- Crea una matriz de ceros de tamaño wxw.
- Dentro de un círculo de diámetro w en esa matriz, pon unos
- calcular el área del círculo (= PI * w)
- Recorre todos los píxeles de la imagen.
- optimización: si el píxel actual es de color de fondo -> continuar bucle
- multiplique la matriz con la imagen en cada píxel (por ejemplo, filtrando la imagen con esa matriz) (puede hacer esto usando la posición actual de x e y un doble para bucle de 0 a w)
- Toma la suma del resultado de cada multiplicación.
- si la suma es igual al área del círculo calculado, incremente el contador en uno
- almacenar en resultado [w - minimalExpectedWidth]
- incrementa w por uno
- optimización: incluir algoritmo de más abajo aquí
- mientras que el contador es mayor cero
Ahora la matriz de resultados contiene el número de coincidencias para cada ancho probado.
Graficarlo para echarle un vistazo.
Para un ancho de uno, esto será igual al número de píxeles de color de traza. Para un valor de ancho mayor, menos áreas circulares encajarán en la traza. Por lo tanto, la matriz de resultados disminuirá constantemente hasta que se produzca una caída repentina . Esto se debe a que la matriz de filtro con el área circular de ese ancho ahora solo encaja en las intersecciones.
Justo antes de la caída es el ancho de su traza. Si el ancho no es constante, la caída no será tan repentina.
No tengo MATLAB aquí para probar y no estoy seguro de una función para detectar esta caída repentina, pero sí sabemos que la disminución es continua, así que tomaría el máximo de la segunda derivada de la (cero basado en) matriz de resultados como esta
Algoritmo:
- establecer máximo = 0
- establecer widthFound = 0
- establece minimalExpectedWidth como arriba
- establecer prevvalue = resultado [0]
- establecer índice = 1
- set prevFirstDerivative = resultado [1] - prevvalue
- bucle hasta que el índice es mayor longitud de resultado
- firstDerivative = result [index] - prevvalue
- establecer secondDerivative = firstDerivative - prevFirstDerivative
- si secondDerivative> maximum o secondDerivative <maximum * -1
- máximo = segundoDerivativo
- widthFound = index + minimalExpectedWidth
- prevFirstDerivative = firstDerivative
- prevvalue = resultado [índice]
- índice de incremento en uno
- ancho de retorno
Ahora widthFound es el ancho del trazado para el cual (en relación con el ancho + 1) se encontraron muchas más coincidencias.
Sé que esto está parcialmente cubierto en algunas de las otras respuestas, pero mi descripción es bastante sencilla y no es necesario que haya aprendido el procesamiento de imágenes para hacerlo.
Aquí está el problema: tengo una serie de imágenes binarias compuestas por trazas de diferentes grosores. A continuación hay dos imágenes para ilustrar el problema:
Primera imagen - tamaño: 711 x 643 px
Segunda imagen - tamaño: 930 x 951 px
Lo que necesito es medir el grosor promedio (en píxeles) de las trazas en las imágenes. De hecho, el grosor promedio de las trazas en una imagen es una medida algo subjetiva. Entonces, lo que necesito es una medida que tenga alguna correlación con el radio de la traza, como se indica en la siguiente figura:
Notas
Como la medida no necesita ser muy precisa, estoy dispuesto a cambiar la precisión por velocidad. En otras palabras, la velocidad es un factor importante para la solución de este problema.
Puede haber intersecciones en las trazas.
El grosor de la traza podría no ser constante, pero una medida promedio está bien (incluso el grosor máximo de la traza es aceptable).
La traza siempre será mucho más larga que ancha.
Desde Here Un método simple!
3.1 Estimando el ancho de la pluma
El grosor de la pluma se puede estimar fácilmente a partir del área A y la longitud del perímetro L del primer plano
T = A/(L/2)
En esencia, hemos transformado el primer plano en un rectángulo y medido la longitud del lado más largo. Un modelado más fuerte de la pluma, por ejemplo, como un disco que produce extremos circulares, podría permitir una mayor precisión, pero un error de rasterización podría comprometer la significación.
Si bien la precisión no es un problema importante, debemos considerar sesgos y singularidades.
Por lo tanto, debemos calcular el área A y la longitud del perímetro L utilizando funciones que tengan en cuenta la "redondez". En matlab
A = bwarea(.)
L = bwarea(bwperim(.; 8))
Como no tengo MATLAB a la mano, hice un pequeño programa en Mathematica:
m = Binarize[Import["http://imgur.com/3Zs7m.png"]] (* Get Image *)
k = Binarize[MorphologicalPerimeter[m]] (* Get Perimeter *)
p = N[2 Count[ImageData[m], Except[1], 2]/
Count[ImageData[k], Except[0], 2]] (* Calculate *)
La salida es de 36 Px ...
Imagen perimetral sigue
HTH!
Han pasado 3 años desde que se hizo la pregunta :) siguiendo el procedimiento de @nikie, aquí hay una implementación matlab del ancho de trazo.
clc;
clear;
close all;
I = imread(''3Zs7m.png'');
X = im2bw(I,0.8);
subplottight(2,2,1);
imshow(X);
Dist=bwdist(X);
subplottight(2,2,2);
imshow(Dist,[]);
RegionMax=imregionalmax(Dist);
[x, y] = find(RegionMax ~= 0);
subplottight(2,2,3);
imshow(RegionMax);
List(1:size(x))=0;
for i = 1:size(x)
List(i)=Dist(x(i),y(i));
end
fprintf(''Stroke Width = %u /n'',mean(List));
Me impresionó la respuesta de @Nikie y lo intenté ...
Simplifiqué el algoritmo para obtener solo el valor máximo, no la media, evadiendo así el máximo algoritmo de detección local. Creo que esto es suficiente si el trazo se comporta bien (aunque para las líneas que se intersectan a sí mismas puede no ser exacto).
El programa en Mathematica es:
m = Import["http://imgur.com/3Zs7m.png"] (* Get image from web*)
s = Abs[ImageData[m] - 1]; (* Invert colors to detect background *)
k = DistanceTransform[Image[s]] (* White Pxs converted to distance to black*)
k // ImageAdjust (* Show the image *)
Max[ImageData[k]] (* Get the max stroke width *)
El resultado generado es
El valor numérico (28.46 px x 2) se ajusta bastante bien a mi medida de 56 px (aunque su valor es 100px: *)
Editar - Implementado el algoritmo completo
Bueno ... más o menos ... en lugar de buscar los máximos locales, encontrar el punto fijo de la transformación de la distancia. Casi, pero no completamente diferente a la misma cosa :)
m = Import["http://imgur.com/3Zs7m.png"]; (*Get image from web*)
s = Abs[ImageData[m] - 1]; (*Invert colors to detect background*)
k = DistanceTransform[Image[s]]; (*White Pxs converted to distance to black*)
Print["Distance to Background*"]
k // ImageAdjust (*Show the image*)
Print["Local Maxima"]
weights =
Binarize[FixedPoint[ImageAdjust@DistanceTransform[Image[#], .4] &,s]]
Print["Stroke Width =",
2 Mean[Select[Flatten[ImageData[k]] Flatten[ImageData[weights]], # != 0 &]]]
Como puede ver, el resultado es muy similar al anterior, obtenido con el algoritmo simplificado.
Suponiendo que la traza tiene un espesor constante, es mucho más larga que ancha, no tiene una curva demasiado fuerte y no tiene intersecciones / cruces, sugiero un algoritmo de detección de bordes que también determina la dirección del borde, luego un detector de subida / caída con Algunos trigonometría y un algoritmo de minimización. Esto le da el espesor mínimo a través de una parte relativamente recta de la curva.
Supongo que el error es de hasta un 25%.
Primero use un detector de bordes que nos dé la información de dónde está un borde y qué dirección tiene (en pasos de 45 ° o PI / 4). Esto se hace filtrando con 4 matrices 3x3 diferentes ( Example ).
Por lo general, diría que es suficiente para escanear la imagen horizontalmente, aunque también se puede escanear verticalmente o diagonalmente.
Suponiendo que el escaneo línea por línea (horizontal), una vez que encontremos un borde, verifiquemos si se trata de un aumento (que va del fondo al color traza) o una caída (al fondo). Si la dirección del borde está en ángulo recto con respecto a la dirección de escaneo, omítalo.
Si encuentra una subida y una caída con las direcciones correctas y sin ninguna perturbación intermedia, mida la distancia desde la subida hasta la caída. Si la dirección es diagonal, multiplique por squareroot de 2. Almacene esta medida junto con los datos de coordenadas.
El algoritmo luego debe buscar a lo largo de un borde (no puede encontrar un recurso web en eso en este momento) para las mediciones vecinas (por sus coordenadas). Si hay un mínimo local con un relleno de aproximadamente 4 a 5 unidades de tamaño a cada lado (un valor para jugar con: más grande: menos información, más pequeño: más ruido), esta medida califica como candidata. Esto es para asegurar que los extremos del camino o una sección doblada demasiado no se tengan en cuenta.
Lo mínimo de eso sería la medida. Verificación de plausibilidad: si la traza no está demasiado enredada, debe haber muchos valores en esa área.
Por favor comenta si hay más preguntas. :-)
Tengo una solución interesante:
- Detección de bordes, para extracción de píxeles de borde.
- Haga simulación física: considere los píxeles del borde como partículas cargadas positivamente.
- Ahora coloque un número de partículas libres cargadas positivamente en el área del golpe.
- Calcule las ecuaciones de fuerza eléctrica para determinar el movimiento de estas partículas libres.
- Simule el movimiento de las partículas durante algún tiempo hasta que las partículas alcancen el equilibrio de posición. (Como se repelerán de ambos bordes de stoke después de algún tiempo, se mantendrán en la línea media de stoke)
- Ahora el grosor del trazo / 2 sería
average distance from edge particle to nearest free particle.
Yo sugeriría este algoritmo:
- Aplique una transformación de distancia a la imagen, de modo que todos los píxeles de fondo se establezcan en 0, todos los píxeles de primer plano se configuren a la distancia del fondo
- Encuentra los máximos locales en la imagen transformada a distancia. Estos son puntos en el medio de las líneas. Ponga sus valores de píxeles (es decir, distancias desde el fondo) de la imagen en una lista
- Calcula la mediana o el promedio de esa lista