Foro de elhacker.net

Programación => Java => Mensaje iniciado por: footer en 16 Agosto 2017, 03:10 am



Título: Comparar Imagenes y encontrar similitudes.
Publicado por: footer en 16 Agosto 2017, 03:10 am
Hola buenas noches a todos. Un amigo me desafio a ver si podia resolver algo, el desafio consistia en hacer que la computadora reconozca dos imagenes de entre 5, esas dos imagenes son la misma imagen pero con algunas modificaciones. Mejor les dejo algunas imagenes para que se entienda mejor la imagen del desafio es esta:

(https://image.ibb.co/gPg7Kv/a.jpg)

Lo primero que hice fue pintar el fondo de negro y filtrar la imagen a escala de grises y obtuve esto:

(https://image.ibb.co/f1jGCF/Salida_Principal.png)


Luego lo que hice fue separar las subimagenes y obtener su borde y obtuve estas:

(https://image.ibb.co/ewcKXF/prueba0.png)
(https://image.ibb.co/jBCWev/prueba1.png)
(https://image.ibb.co/figPzv/prueba2.png)
(https://image.ibb.co/hJsa6a/prueba3.png)
(https://image.ibb.co/eMAjzv/prueba4.png)

Ahora no se como continuar, queria saber como hago para detectar similitudes entre las imagenes, no puedo hacerlo por medio del color de los pixeles ya que las imagenes varian sus colores, aqui dio casualidad que justo el amarillo esta en ambas imagenes iguales pero la forma es lo que vale ya que a veces tocan colores muy distintos.

Queria saber si alguien tiene conocimiento sobre detectar patrones en las imagenes que me permitan saber que figura tengo alli, o algun libro o pdf que hable del tema.

Aqui les dejo el codigo con que he estado intentando, esta incluida la imagen del desafio, esta hecho en java y se me hizo un poquito espaguetti jaja pero esta todo comentado. Suerte.

Link: https://drive.google.com/open?id=0B1i-JNEuRD1zV3FQTmJ6X2pBN3M





Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 16 Agosto 2017, 06:45 am
...primero debes detectar los bordes salientes...

Esto es:
- Recorre la imagen horizontalmente bajando hasta tocar el primer píxel, luego ídem pero desde abajo hacia arriba.
- Recorre la imagen verticalmente avanzando a la derecha hasta que toques el primer píxel, luego ídem pero desde la derecha y avanzando hacia la izquierda...

La forma más exacta, es resaltar los vértices salientes... Imagina que con un lápiz trazas líneas para encerrar cada figura en un polígono, pero siempre con ángulos convexos ('reentrantes', nunca cóncavos hacia afuera) y siempre tocando la figura, por supuesto.

Mediante la comparación luego de:
A - La superficie interna del polígono. buen candidato para determinar rápidamente los similares (pero no óptimo si varían en tamaño)
B - La cantidad de lados del polígono resultante. Buen candidato para a primera vista determinar similitud incluso entre diferentes tamaños.
C - Los ángulos que forman cada par de lados del polígono. Es la tarea final, las previas son aproximaciones rápidas.

Y con esto  es relativamente asequible determinar su similitud con un porcentaje.
Éste algoritmo sería el adecuado, si además las formas tienen diferente tamaño (dos figuras iguales o muy parecidas pero de diferente tamaño), ya que los ángulos se mantienen así como el número de lados del polígono.




Basicamente  en pseudocódigo son estos pasos:
Esta sería la función principal (tras los pasos que llevas)
Código:
Buleano = Funcion Buscarsimilitudes(Lista de Imagenes Figuras )
    Lista Poligonos  // lista de poligono
    Lista Poligono // lista de líneas

    Por cada figura en Figuras
         Poligono = CrearPoligono(figura)
         Poligonos.Add (Poligono)
    Siguiente

    Bucle para j desde 0 Poligonos.Length -2  //el último se debe comparar
        Poligono = Poligonos.Item(j)
        Bucle para k desde j a Poligonos.Length -1
            Si EsSimilar(Poligono, Poligonos.Item(k))  luego
                // Mostrar coincidencia en la forma que tengas previsto.  
                Similares = TRUE
            Fin si
        Siguiente
    Siguiente
  
    Devolver Similares //si al menos hubo 2 similares entre sí, devolverá TRUE.
Fin Funcion

Aquí el pseudocódigo para crear un polígono de cada imagen (a grandes rasgos).
Tu primer paso será entonces un "localizador de puntos salientes" de la figura...
El segundo, será un "trazador de líneas"... primero empezamos con los 4 puntos (uno de cada orientación, se trata de intentar lanzar una línea de uno de ellos al del lado contiguo, si corta en algún punto la figura, se debe buscar otro punto saliente entre medias y repetir).
Es mejor usar una lista que un array porque no se sabe cuanto se va a almacenar.
Código:
Lista = Funcion CrearPoligono(imagen Figura)
    Lista Puntos  //donde señaden los puntos.
    Lista Poligono //donde se añaden las líneas
    entero j, k
    punto centro

    centro = PuntoCentral(Figura) // se trata de hallar aprox, el punto central de la imagen, un eje de cordenadas en el centro.
    Puntos = BuscarLos4PuntosMásSalientes // (de las 4 orientaciones), da igual si prefieres buscarlos en diagonal, pero es más complejo recorrer así la imagen.    
    j=0
    k=(j+1)
    Hacer
        Linea = TrazarLinea(puntos.Item(j), Puntos.Item(k) )
        Si Linea CortaFigura(Linea, Figura) luego //Si la línea corta la figura...
            Punto = Buscar nuevo punto saliente entre ambos, y añadir delante del destino
            Puntos.Add(punto, k)            
        Sino
            //OJO: No trato el caso de que k sea el último y el 3º punto debiera ser el primero el 0º
            // queda a tu esfuerzo modificarlo como convenga...
            Si AnguloEsConcavo(puntos.Item(j), Puntos.Item(k),  Puntos.Item(k+1), centro ) = FALSE luego
              
                Poligono.Add(Linea)
                j = k
                Si (k < Puntos.Count) luego                  
                    k +=1
                Sino
                    Si (k=0) luego
                       Conectado = TRUE
                    Sino
                        k = 0
                    Fin si
                Fin si
            Sino
                El punto intermedio entre los dos se elimina // hace concavidad, la búsqueda (la programación) del más saliente no fue 'adecuada', pero bueno esto nos permite avanzar aunque sea más lentamente.
                // j y k no cambian, así al retorno se traza la línea entre esos dos (que antes tenían uno en medio).
            Fin si
        Fin si
    Repetir Mientras (Conectado= FALSE)
    Devolver Poligono
Fin funcion

También puedes buscar similitud por perímetro cuando el número de lados es desigual. Si la superficie y el perímetro son similares hay probabilidades.
Código:
Buleano = EsSimilar(Lista p1, Lista p2)  // p1 y p2 son sendos polígonos
    Area1 = HallarArea(p1)
    Area2 = HallarArea(p2)
  
    Si SimilitudPorTolerancia(Area1, Area2, ToleranciaArea) = TRUE luego  //tolerancia debe expresarse en forma de porcentaje aceptable, p.e.: '90' por ciento.
         // son de tamaño similar, no hay zoom, o es escaso.
        Si SimilitudAngulos(p1, p2, ToleranciaAngulos) = TRUE luego
            Devolver TRUE
        Fin si
    Sino  // son distintos, puede que uno esté con zoom... comprobamos lados y angulos
        // comprobamos la similitud en el número de lados.
        Si SimilitudPorTolerancia(p1.Length, p2.Length, ToleranciaLados) = TRUE luego
            Si SimilitudAngulos(p1, p2, ToleranciaAngulos) = TRUE luego
                Devolver TRUE
            Fin si
        Si no
            // El número de lados si no cincide ver si hay o falta un lado de tamaño muy corto, pero no se expone aquí...
            // Si cambia el númeor de lados, vamos a exigir más exactitud, con los ángulos
            Si SimilitudAngulos(p1, p2, ToleranciaAngulos+ToleranciaExigente) = TRUE luego
                Devolver TRUE
            Fin si
        Fin si
    Fin si
Fin Funcion

Tolerancia debe ser un valor en el rango 1-100, pero si se pone 100 exige exactitud total, y si se pone 1, una casa será igual que un coche, un valor adecuado podría ser 90% es decir uno es similar a otro si es un 90% del área (esto es solo varía un 10%, no confundir ambos valores, pués puede hacerse  al derecho o al revés).
Código:
Buleano = Funcion SimilitudPorTolerancia(entero v1, entero v2, byte Tolerancia)
    Si (v1 >= v2) luego  //
        Si (((v1/100) * Tolerancia) >= v2) luego Devolver TRUE
    Sino
        Si (((v2/100) * Tolerancia) >= v1) luego Devolver TRUE
    Fin si
Fin Funcion

Se traza una línea ente los puntos extremos, y considerando el centro, se ve si p2, a que lado queda
respecto de la línea, según el centro debe quedar en un sitio u otro para saber si es cóncavo o convexo.
Código:
Buleano = Funcion  AnguloEsConcavo(Punto p1, Punto p2, Punto p3, Punto centro)
   Linea  
    
    Linea = TrazarLínea(p1,p3) //Trazar una línea desde p1 a p3

    //Ver donde queda p2 respecto de la linea y según p1 y p3 estén orientados respecto del centro
    Si p1.X < centro.x
        // Sin terminar... queda a tu esfuerzo
    Sino
        // Sin terminar... queda a tu esfuerzo
    Fin si
Fin Funcion

Código:
Buleano = Funcion SimilitudAngulos(Poligono pol1, Poligono pol2)
    Lista Angs1, Angs2
    Decimal ang1, ang2  //valor en  coma flotante
    Buleano Similares

    Angs1 = AngulosPoligono(pol1)
    Angs2 = AngulosPoligono(pol2)

    // Quizás una figura esté rotada respecto de otra, luego exige encontrar ekl punto de coincidencia.
    // pero puede pasar que haya más de un ángulo en una figura que tenga el mismo que otro en la otra figura...
    Bucle para i desde 0 a Angs1.Length
        ang1 = Angs1.Item(i)
        Bucle para cada j desde 0 a Angs2.length
            ang2 = Angs1.Item(j)
            // se convierten a enteros, tal como exige la función...
            Si SimilitudPorTolerancia(ConvertirAEntero(ang1), ConvertirAEntero(ang2), ToleranciaAngulo) = TRUE luego
                Similares = TRUE
                Bucle para k desde j+1 a Angs1.Length
                    ang2 = Angs1.Item(k)
                    Si SimilitudPorTolerancia(ConvertirAEntero(ang1), ConvertirAEntero(ang2), ToleranciaAngulo) = False luego
                        Similares = FALSE
                        Salir del bucle
                    Fin si
                Fin Bucle
                Si (Similares = TRUE) luego Devolver TRUE
            Fin si
        Fin bucle    
    Fin Bucle
Fin Funcion
Crea una lista con los ángulos del polígono.
Código:
Lista = Funcion AngulosPoligono(Poligono Pol)
    Lista Angulos
    Punto p1, p2, p3
    
    p1 = pol1.Item(0)
    p2 = pol1.Item(1)
    p3 = pol1.Item(2)
    Angulo = AnguloFormado3Pt(p1, p2, p3)
    Angulos.Add(angulo)
    Bucle para j desde 3 a p1.Length - 1 // si es un triángulo, no entrará en el bucle        
        p1=p2
        p2=p3
        p3= pol1.Item(j)
        Angulo = AnguloFormado3Pt(p1, p2, p3)
        Angulos.Add(angulo)
    Fin bucle
    // Faltan 2 ángulos, los formados por el final y el comienzo
    p1=p2
    p2=p3
    p3= pol1.Item(0)    
    Angulo = AnguloFormado3Pt(p1, p2, p3)
    Angulos.Add(angulo)

    p1=p2
    p2=p3
    p3= pol1.Item(1)    
    Angulo = AnguloFormado3Pt(p1, p2, p3)
    Angulos.Add(angulo)
    
    Devolver Angulos
Fin Funcion

Código:
Decimal = AnguloFormado3Pt(Punto p1, Punto p2, Punto p3)
   // queda a tu esfuerzo, son simples matemáticas...
Fin funcion

Aumento una de las figuras y realizo un pequeño dibujo a mano alzada. Nota el número de lados del polígono que encierra la figura, sus ángulos, etc... así te formas una idea y con esto debiera valerte... aunque tienes trabajo por delante...

(http://i.imgur.com/Fsu1wBz.png)


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 16 Agosto 2017, 18:19 pm
Olvidaba decirte, que hay otra más sencilla y rápida, pero es aplicable solo cuando tengas la seguridad de que las imágenes tienenn todas la misma orientación y si no es así, deben antes ser rotadas, considerando los 4 puntos más sobresalientes de uno consderado centro.

Esto es, si hay que rotarlas, primero trazas un punto que inscriba por completo la figura, pero tocando en al menos 3 puntos el exterior del perímetro de la figura.
Luego buscas 3-4 puntos más alejados del centro.

Esos puntos te sirven para saber cuanto puede estar rotada una figura respecto d ela otra y si es preciso se rotan. También para saber si una está desplazada respecto de otra.

Recuerda que debemos tener imágenes donde el fondo es blanco y la figura (no solo el trazo que la encierra) es negro (o viceversa), pero si es transparente hay que considerar la transparencia del color opuesto a la tinta d ela figura (blanco o negro).

Finalmente solo cuando estés seguro que 'encajan' en el mismo centro.

Entonces se hace una operación xor entre los píxeles de ambas imágenes. El resultado será el siguiente:
255 xor 255 = 0
0 xor 0 = 0
255 xor 0 = 255
0 xor 255 = 255
Es decir, donde una imagen coincida (dentro y fuera de la figura) con la otra, dará un píxel negro en la imagen resultado, y blanco cuando sean distintas. Contando el número de blancos sabremos cuanto difiere (o contando los blancos sabremos cuanto es igual). Usa la tolerancia con diferentes valores, para ver qué resultados te da.

Esta solución, es la adecuada cuando no hay que ser muy extrictos y las formas son más o menos claras, del mismo tamaño, pequeñas y la velocidad es muy importante.

P.d.: Aquí no se ha considerado si la imagen están espejadas (que veo que tienes dos iguales pero espejadas entre sí). cuando cabe la posibilidad de que estén espejadas, hay que hacer 4 comparaciones (4 bucles idénticos), el primero tal cual (como si las dos estuvieren corrctas, en otra donde la segunda imagen esté invertida horizontalemente, la 3ª donde se considere invertida a la segunda figura verticalemtne y la 4º donde se consdiere invertida a la segunda figura tanto vertical como horizontalmente.
Con los reconocimientos en el mensaje anterior es fácil detectar si están invertidas, porque las  áreas, perímetros vendrán a coincidir y medidas y ángulos  conncidirán en orden inverso...


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: footer en 17 Agosto 2017, 04:32 am
Hola NEBIRE gracias por tus respuesta y tiempo, estuve viendo tu pseudocodigo y me parece bastante buena idea, si no me equivoco lo que me dices que haga es que formar poligonos donde cada lado del poligono estara definido por puntos salientes de la figura que se encuentren al lado, luego comparar los  poligonos y ver sus similitudes por medio de sus angulos, la verdad que tiene mucho sentido. Asi que me puse a ver si podia al menor comenzar con eso. Asi que al codigo que subi antes le agregue la clase "comparador" donde escribi algunos metodos entre ellos estan: un metodo que encuentra los primeros cuatro puntos saliente (superior, inferior, derecho, izquierdo), luego con esos puntos salientes se calcula en punto central de cada imagen, ademas tambien pinta las imagenes por dentro, las imagenes devueltas por java son estas:

(no se alcanzan a ver, pero si hacen zoom con el navegador podran notar 5 puntos, uno central y los demas son los primeros 4 puntos salientes)


(https://image.ibb.co/jcjzjv/Punto_Central0.png) (https://image.ibb.co/iSTQPv/Punto_Central1.png) (https://image.ibb.co/mSFTcF/Punto_Central2.png) (https://image.ibb.co/hbaTcF/Punto_Central3.png) (https://image.ibb.co/cE11xF/Punto_Central4.png)

El siguiente paso si no me equivoco es hacer una linea entre 2 puntos salientes que esten al lado y verificar si toca a la figura, en ese caso comprobara un nuevo punto saliente entre medio de esos 2 puntos y hara una linea nueva. Apenas puedo intentare eso y estare actualizando el post. Aqui dejo el codigo. Suerte.

String link = "https://drive.google.com/open?id=0B1i-JNEuRD1zWVFvVG4xcFpCN2s";
 


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 17 Agosto 2017, 16:49 pm
Exacto...

Una vez con los 4 puntos y uno considerado como el 'centro geométrico', desde los 4 hay que buscar los puntos salientes que tocando a la figura logran encerrar por completo la figura.

La parte que puede parecer un poco confusa (espero que no), es la de considerar el ángulo convexo o cóncavo, ya que eso depende del cuadrante (en realidad ángulo de ambos puntos alrededor del eje).

Por último, aunque no se ha mencionado explicítamente si no que se ha dejado un poco al aire, es que consideramos similitud... porque puede tener diferentes interpretaciones según lo que busquemos:
Similitud en la forma, similitud en tamaño (área), etc...
Se ha asumido de forma genérica, pero los detalles dados permiten avanzar en la dirección que uno pretenda.

p.d.: No he mirado tu código aún... cuando avances algo más le hecho un vistazo.
Ten en cuenta que es fácil perderse, o desalientarse porque hay muchos pequeños detalles que mimar y ponder en orden. Pero bueno, cada función en pseudocódidigo está en grandes pasos (y escrito al vuelo), se puede pulir y detallar más llegado el caso.


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: footer en 20 Agosto 2017, 04:58 am
como elimino este mensaje? lo publique solo sin querer.


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: footer en 20 Agosto 2017, 06:23 am
Hola todos, hago una actualizacion de esto, he hecho un "parentesis" por que me puse a ver como podria detectar un punto saliente que este entre 2 puntos salientes, siguiendo con la idea que me dio NEBIRE he trazado lineas entre los 2 puntos y ¿como iba a hacer para que el programa detecte el punto saliente del medio?.
Se me ocurrieron 2 formas. La primer manera:
En cualquiera de la dos ideas se tiene un recorrido/ruta que no es mas que los pixeles de una linea, ese recorrido sera lo que indique la direccion del "scanner" que tampoco es mas que una linea donde entre sus puntos en algun momento estara el pixel saliente del medio, en la idea uno el recorrido se marca con una linea amarilla y el escaner con una linea roja, los puntos salientes con azul y con verde el centroide que es el centro de la figura por ultimo de color negro dibujo la linea que une un punto con el otro:


(https://image.ibb.co/c2KMHQ/img2.png)

Donde la linea amarilla es el recorrido del scanner, que es la linea roja y este scanner se va moviendo hacia uno de los puntos de la linea.
Para hacer esto superficialmente lo que se hace es:

Calcular angulo de la linea que va desde el punto de salida hasta el punto de llegada, en este caso (foto) el punto de salida es el de abajo, entonces metemos ese punto en un eje cartesiano y calculamos el angulo con el otro punto, esto se hace con trigonometria
Para eso hay que detectar el cuadrante del vector y sumar los angulos del cuadrante anterior: En la imagen al angulo de color celeste se le suman 0 grados, al de marron se le suman 90 grados,  y asi con los demas angulos...
(https://image.ibb.co/dfJbj5/img3.png)

Una vez con ese angulo se hace la linea que une esos dos puntos tambien con trigonometria. Despues de esto tenemos una line hecho desde un punto hasta otro punto. (los dos mas salientes),

Lo siguiente es calcular el angulo entre el punto centroide y el punto de salida de la linea, esto se hace de la misma forma:

(https://image.ibb.co/gVTnrk/img4.png)

Con este angulo se puede trazar la lines de recorrido:  (linea amarilla) de ahi sale la linea amarilla de la imagen de arriba.

(https://image.ibb.co/nhavcQ/img5.png)

Una vez hecho eso solamente queda comprobar, para comprobar hay que meter en un array cada punto de la linea amarilla (solo la linea amarilla), e ir recorriendo cada punto uno a uno desde el ultimo hasta el primero (se recorre al revez por que se quiere detectar desde afuera hacia adentro) y por cada punto de esos hara una nueva linea, la linea scanner, para hacer la linea usara el angulo de la linea negra:

(https://image.ibb.co/nouXP5/img6.png)



Forma 2:

Es lo mismo que antes pero cambia en que en ves de calcular la linea de recorrido con un angulo igual al angulo entre centroide y punto de salida lo que hace es calcularla a noventa grados del angulo de la linea, se obtendria esto:

(https://image.ibb.co/iWX8xQ/imgOtra.png)

para obtener la linea que es perpendicular se puede sumar o restar 90 grados al angulo de la linea el problema es que a veces habra que sumar y otras veces habra que restar
entonces para saber eso tengo que tener en cuenta que para trazar una una ruta de trayecto/recorrido para el scanner tengo que alejarme del punto centroide y para poder alejarme se tiene primero que: calcular angulo entre punto saliente y centroide, luego sumar 90 grados al angulo (que ya existe calculado antes, arriba) de la linea que se habia llamado "alpha" y obtengo una de las 2 rectas de noventa grados para tener la otra tengo que restar 90 grados al mismo angulo que antes le habia sumado, ¿cual recta elijo?. Para responder esa pregunta hace falta saber la diferencia entre los 3 angulos que se tienen que son marron,violeta,verde:

(https://image.ibb.co/gNN8xQ/img7.png)

negro = es el angulo de la linea
marron = es el angulo de la linea + 90 grados.
violeta = es el angulo de la linea -90 grados.
verde = es el angulo entre el punto saliente y el centroide

y ahora hacemos las diferencias:

marron - verde = diferencia entre el angulos+90 y el angulo con centroide
violeta - verde = diferencia entre el angulo-90 y el angulo con centroide

de los dos angulos que me importan (angulo+90 y angulo-90) voy a tomar el que me de mayor diferencia con el angulo centroide por que eso quiere decir que en ese angulo me voy alejar del punto centroide la diferencia seria esta:

(https://image.ibb.co/h7C0u5/img8.png)

la diferencia es bastante en este caso, lo que sigue es igual, se traza la linea amarilla a 90 grados, se recorre esa linea desde fuera hacia dentro y en cada pixel de la linea amarilla trazara nuevas lineas (linea roja, scanner) con el angulo de la linea negra.

Aqui dejo un codigo que ilustra esto:
El codigo es una animacion que muestra los dos tipos de deteccion, si se fijan en la clase Principal hay varias opciones de configuracion, si ponen el valor de la propiedad "tipoDeDeteccion" = 1 veran la forma 1 que explique antes y si ponen "tipoDeDeteccion" = 2 veran la segunda forma, ademas hay una imagen de salida que se guarda en "D:/salidaDiagonales.png" por si quieren ver, la linea de recorrido del scanner se traza en verde, no en amarillo, por ultimo pueden cambiar el punto por defecto por uno que ustedes quieran, y esto me lleva a mencionar algunos errores que pueden pasar...

si ponen tipo de deteccion = 1 y ponen 2 puntos que esten a 45 grados ej: (10,10);(20,20) veran como la deteccion no hace su trabajo como debe ser.
Si ponen tipo de deteccion = 2 hay angulos entre puntos que hara que el programa no sepa que elegir, por ejemplo el punto (10,10);(10,10) al poner ese punto en el momento de elegir el recorrido del scanner hara la diferencia y ambas diferencias son iguales entonces el programa no sabe que elegir...
 Espero no haberme olvidado de algo, ya estare viendo si puedo icluir esto en la deteccion de las imagenes de arriba. Saludos.

Subido a googleDrive
Link: https://drive.google.com/open?id=0B1i-JNEuRD1zOEdoX0Z0NHFpNlU











Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 21 Agosto 2017, 06:06 am
Bien, vas avanzando... pero te daré algunas ideas...

1 - Es preferible no considerar el punto central como el punto de cruce entre las líneas que unen los puntos verticales y horizontales, sino, como muestor en el siguiente dibujo, el punto medio entre la distancia que separa los puntos horizontales, e ídem de los puntos verticales, de modo, que con ese centro es equidistante a ambos lados, pudiéndose trazar (si fuera el caso), un círculo o elipse que pase por ellos.
No es del todo obligatorio, pero reduce la cantidad de píxeles a visitar...
Se expone en la siguiente imagen (he desplazado los puntos para que no vengan a coincidir enfrente uno de otro y quede más claro la idea...
(http://i.imgur.com/BflmpaQ.png)

2 - Con los 4 puntos, se elige uno como inicio y una dirección (pongamos el de arriba y girando en sentido de las agujas del reloj, ahora nos centramso solo ne ese cuadrante. (son 4 bucles uno de trás de otro, que corresponden a cada cuadrante). Se lanza una línea entre los dos que limitan ese cuadrante... ¿por qué?. ahora vemos con una imagen porqué.
En la imagen se ven 6 variacones de la misma figura. Mira la última, si no corta la figura, implica que esa es la línea que encierra la figura, luego esa sería la solución para ese cuadrante.
Pero miremos a la figura 1, si recorremos los píxeles de la línea, podemos contar cuantas veces corta la figura (recordemos que la figura la tenemos en negro y el exterior en blanco, yo para que se vean con claridad los detalles, he conservado solo el contorno. en la imagen 1, la línea de contorno es interceptada 4 veces, una siempre sale otra que entra, luego podemos deducir que como mínimo hay 2 'picos' salientes. Bien si ahora te fijas en a imagen marcada como 3, verás que el controno se intercepta 10 veces, es decir hay al menos 5 'picos' salientes, se puedne contar bien, he puesto un trazado amarillo en cada saliente.
Pueden ser más pícos que el número dividido entre 2 (la marcada como 4 tiene el propósito de demostrar eso), pero nunca menos.
La 1 la 2, son la misma, en la 1 simplemente he trazado las 4 líneas que unen los 4 puntos, como idea general...
La imagen 5 redunda en lo mismo, ver que aunque el contorno sea retorcido siempre una intercepción entra en la figura y la siguiente sale.
Esos puntos de intercepción del contorno son útiles... nos sirven para saber cuantos picos cabe encontrar como mínimo.

(http://i.imgur.com/Hq4lDPB.png)

En la siguiente imagen, vamos a analizar más en profundidad la importancia de los puntos de interceción de  contornos. Si miras con detenimiento la siguiente imagen, podrás ver que cada vez que la línea azul, corta el contorno, las veces impares, entra dentro de la figura y las veces pares sale de la figura , esto sucede siempre, da igual lo enrevesado que sea la imagen. De hecho esta característica es la base de rellenar figuras encerradas (o lo opuesto rellenar el exterior) con un color o un patrón, solo recorriendo línea a línea...
(http://i.imgur.com/nlZFEnZ.png)

Ahora vamos al siguiente paso importante... se muestra en las siguientes imágenes...
Hemos empezado a detectar los picos, para ello se generan dos bucles, uno de recorrido vertical y otro horizontal ... por supuesto son dos bucles anidados, uno de recorrer líneas y el interno para recorrer los píxeles de cada línea.
En el horizontal vamos detectando el borde saliente, cada vez que una línea encuentre lo más a la derecha un contorno, y, en la siguientes líneas (el bucle interno anidado) empezamos (como mínimo) en esa posición, no volvemos cada vez al origen (centro de cordenadas). Esto se muestra en el trazo azul. Si recorriéramos todo, empezaríamos el bucle horizontal siempre desde la línea roja, sin embargo eso solo sucede en la primera línea. Cuando llega al pico 1(ver la marca rosada), ya empieza las siguientes líneas en ese punto. Esto acelera la búsqueda...
(http://i.imgur.com/vBoptiH.png)

Se puede ver también que he trazado unas líneas rojas.... Una vez detectados los puntos salientes, desde el punto final del cuadrante (o desde el punto origen), se trazan líneas a cada uno de esos puntos recién obtenidos.
De entre todas esas líneas, aquella que arroja el ángulo más grande respecto de la línea que trazamos entre ambos puntos originales, es el punto más saliente.
De nuevo desde ese punto, trazamos líneas (la primera al punto de origen del cuadrante) y al resto de puntos obtenidos (más arriba en el eje 'Y', que la posición 'y' que ocupa éste punto), y de nuevo aquella línea que marca el ángulo mayor con respecto a la línea trazada hacia el punto del cuadrante, determina el punto más saliente....
Siguiendo el procedimiento, se obtiene todos esos puntos salientes que encierran la figura en ese cuadrante.
Es trivial, dibujar las líneas de los siguientes (saturaría la vista tantas líneas), se observa fácilmente que desde el punto final del cuadrante, marcado como 0, la línea irá al 1, luego al 3, luego al 5 y finalmente al de origen marcado como 6.
(http://i.imgur.com/OBpfbKT.png)

En esta otra imagen, más de  lo mismo. Tiene trabajo, pero es un modo seguro. Zonas redondeadas, pueden dar, líneas muy cortas y próximas entre sí, que pueden 'falsear' luego los ángulos. Pueden 'resumirse'...
Un detalle (en la esquina superior izquierda de la imagen) es ver como en el bucle de recorrido horizontal, se empieza siempre desde la línea del eje, (en este cuadrante desde ahí hacia la derecha).
En azul claro, el trazado necesario para detectar los picos con sus puntos. Hay que notar que el procedimiento descrito solo se 'visitan' desde los bucles (el bucle interno) los píxeles de la zona marcado en ese color cyan, no todos los del cuadrante, ya que el iniio del bucle interno, va fijandose con un valor mayor cada vez que en una línea se detecta uno más saliente.
(http://i.imgur.com/5YvnTHn.png)

El resto de cuadrantes es aplicar el mismo sistema, con los cambios que proceden o recurrir a senos y cosenos...

Si te queda alguna duda o las explicaciones no te parecen suficientemente claras, avisa... se puede hacer un pseudocodigo...

Cuando avances más te comento algo sobre los atractores gravitatorios... que resultan muy útiles para detectar similitud de formas con flexibilidad en contornos y en la propia forma.


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: footer en 24 Agosto 2017, 02:08 am
hola NEBIRE que tal, comento esto para preguntarte sobre la parte de las lineas azules, si mal no entendi la idea seria esta:
1) calcular el centro: diviendo la distancia horizontal /2 idem para la distancia vertical

2)Luego detectar la cantidad de picos minimos, esto se haria trazando una linea y detectar cuantas veces la linea corta con la imagen, siendo impar -> entrada a img, par -> salida a la img cada vez que entre o salga de la figura sumara un contador++, luego divido /2 y obtengo los posibles picos minimos a detectar.

3) y aqui viene mi principal duda, si no entendi mal lo que debo hacer es definir el cuadrante, cada cuadrante estara limitado por los 4 puntos que me daran 4 cuadrantes, elijo el primer cuadrante en sentido a las agujas del reloj, si la linea toca la figura en ese cuadrante entonces yo debo tener la cantidad minima de picos y debo buscarlos en este cuadrante para luego pasar al siguiente.
Para buscar esos picos de hacer:
Con un "scanner"  horizontal, que valla aumentando filas de a 1 y en cada fila evaluara los pixeles uno por uno de izquierda a derecha, las filas hiran de arriba hacia abajo y haria un "scanner" vertical que hira sumando columnas de a 1 y en cada columna evaluara cada pixel de abajo hacia arriba, las columnas hiran de derecha a izquierda (teniendo en cuenta la img 1)
Cada pico tendra dos puntos salientes a detectar, el superior (que lo detectara el scanner horizontal, y el punto saliente que esta mas a la derecha, que lo detectara el scanner vertical).
Y la duda es: ¿como los detecto? lei lo que escribiste pero no pude encontrar por mas de que quise asimilarlo la forma de detectar los 2 puntos salientes de cada pico (superior y el de la derecha). Esta parte me genera dudas

"cada vez que una línea encuentre lo más a la derecha un contorno, en la siguientes líneas (el bucle interno anidado) empezamos en esa posición,"

entiendo la idea pero no entiendo el funcionamiento de los bucles, el externo mueve en lineas y el interno mueve en pixeles de cada linea y cuando se detecta un borde saliente superior (no se como lo detectaria) el bucle interno de pixeles va a arrancar en la siguiente linea en la posicion que detecto en la anterior no arrancara desde el comienzo.
idem para scanner vertical.

4) Una vez detectado los puntos de cada pico se trazan linea desde el punto final (o el punto de origen) hacia cada punto detectado y la linea que tenga mayor angulo sera el punto mas saliente.

Espero no molestar mucho... Saludos.

PD: alguien no tendra el link de un post que hable sobre como hacer lineas en java? no me refiero al elemento graphics sino a calcular los puntos de la linea que pasa por dos puntos, lo logre hacer con trigonometria, y con funciones lineales, pero al comparar mis lineas con las del elemento graphics no son iguales tienes unas pequeñas diferencias, estare subiendo el codigo de las lineas mas tarde.


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 25 Agosto 2017, 18:59 pm
Te contesto a la noche (más bien de madrugada). Esta mañana te estaba contestando, pero creí necesario apoyarlo con imágenes y se me fue el tiempo sin terminarlo antes de irme al trabajo...


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 26 Agosto 2017, 05:44 am
hola NEBIRE que tal, comento esto para preguntarte sobre la parte de las lineas azules, si mal no entendi la idea seria esta:
1) calcular el centro: diviendo la distancia horizontal /2 idem para la distancia vertical
Si, pero OJO. Esto para pasos posteriores.... para ahora mismo que vamos a detectar los picos, los cuadrantes quedan divididos, por las líneas que se cruzan delimitando el cuadrante para ese par de puntos.
Este cuadrante (su tamaño) varía para cada par, pero tranquilo, no examinamos todo (el área del cuadrante)...

Al crear la línea entre ambos puntos, al mismo tiempo se guardan en un array, porque esos puntos son el inicio del bucle 'x' para cada ciclo del bucle 'y' (para recorrer las filas y columnas).
El algoritmo de Bresenham, te vale muy bien, para trazar la línea, además opera con valores enteros, no con decimales... esos puntos deben guardarse, el punto x más a la derecha por cada 'y'. Es decir el tamaño del array es la altura (si hacmeos el recorrido de forma horizontal, es más cómodo así que hacerlo de forma vertical, elige el que más te convenga).


2)Luego detectar la cantidad de picos minimos, esto se haria trazando una linea y detectar cuantas veces la linea corta con la imagen, siendo impar -> entrada a img, par -> salida a la img cada vez que entre o salga de la figura sumara un contador++, luego divido /2 y obtengo los posibles picos minimos a detectar.
Exacto, te da los picos mínimos, podría haber más, pero nunca menos.


3) y aqui viene mi principal duda, si no entendi mal lo que debo hacer es definir el cuadrante, cada cuadrante estara limitado por los 4 puntos que me daran 4 cuadrantes, elijo el primer cuadrante en sentido a las agujas del reloj,
Si, pero cada cuadrante queda definido por las líneas que cruzan sus líneas imaginarias (ordenada y abscisa), es decir las líneas trazadas de cada 2 puntos, ofrece un cuadrante (los 4 cuadrantes posiblemente se cortan entre ellos, no nos importa).
Te adjunto una imagen de como se particiona...
(http://i.imgur.com/MhoGcPR.png)


si la linea toca la figura en ese cuadrante entonces yo debo tener la cantidad minima de picos y debo buscarlos en este cuadrante para luego pasar al siguiente.
Para buscar esos picos de hacer:
Si, y si no toca la figura, esa línea basta para rodear la figura en ese cuadrante.
Pero antes de buscar en el siguiente cuadrante, resolvemos todo el asunto de ESTE cuadrante.

Con un "scanner"  horizontal, que valla aumentando filas de a 1 y en cada fila evaluara los pixeles uno por uno de izquierda a derecha, las filas hiran de arriba hacia abajo y haria un "scanner" vertical que hira sumando columnas de a 1 y en cada columna evaluara cada pixel de abajo hacia arriba, las columnas hiran de derecha a izquierda (teniendo en cuenta la img 1)
Cada pico tendra dos puntos salientes a detectar, el superior (que lo detectara el scanner horizontal, y el punto saliente que esta mas a la derecha, que lo detectara el scanner vertical).

Y la duda es: ¿como los detecto? lei lo que escribiste pero no pude encontrar por mas de que quise asimilarlo la forma de detectar los 2 puntos salientes de cada pico (superior y el de la derecha). Esta parte me genera dudas

"cada vez que una línea encuentre lo más a la derecha un contorno, en la siguientes líneas (el bucle interno anidado) empezamos en esa posición,"

entiendo la idea pero no entiendo el funcionamiento de los bucles, el externo mueve en lineas y el interno mueve en pixeles de cada linea y cuando se detecta un borde saliente superior (no se como lo detectaria) el bucle interno de pixeles va a arrancar en la siguiente linea en la posicion que detecto en la anterior no arrancara desde el comienzo.
idem para scanner vertical.
Te lo explico una vez más (pero debes tener en cuenta que lo dicho se aplica a este cuadrante, a los siguientes hay que 'desplazar' la idea... es decir es reflexivo, aplicar los cambios necesarios).

Veamos, tenemos dos puntos (miremos la figura 1 de esta nueva imagen que suba, la pongo un poco más arriba). Esos dos puntos trazando sus paralelas, se cortan en un punto... que definen el cuadrante 'NorEste'. Explico siempre sobre este cuadrante...

Un poco  de pseudocódigo que ayude a plantear como resolverlo...
Consta de dos bucles anidados:

p.d: He retirado el pseudocódigo, he puesto más abajo otro equivalente más optimizado... aunque era un detalle que esperaba que vieras, lo cierto es que supone bastante embrollo, así que... vas a trabajar igualmente bastante...

En realidad cada encuentro, no es pico, a menudo es solo una promesa.... si es una leve curva habrá muchos 'picos seguidos'
Mirando esta imagen te puedes hacer una idea clara, de lo que va haciendo el pseudocódigo (el recorrido del bucle interno).
Cada puntito marcado verde (el anterior que está a su izquierda), es el que se añade a "Picos".
(http://i.imgur.com/7mLwiCn.png)


En esta imagen (tras este párrafo) la línea azul, sería representaría los valores de dx, el recorrido del bucle horizontal que va tomando al iniciar cada línea (como está a mano alzada, no salen rectas muy rectas, pero se ve claramente el recorrido, y como cuando hay un saliente avanza del saliente y cuando la diagonal supera al saliente, tira de la diagonal... esas líneas eran:
Código:
Si (dX < LineaDiagonal(Y) ) luego dX = LineaDiagonal(Y) 
Nota que este bucle horizontal empieza en el puntoA (el de arriba y avanza hacia la derecha, buscando cambios entre negro y blanco, hasta final de línea, luego avanza a la siguiente línea empezando en el punto más adelantado hallado en la línea previa, o bien tomando como inicio el de la diagonal.
(http://i.imgur.com/rfDT68X.png)


Si el bucle se recorre verticalmente desde el puntoB hacia el puntoA y de izquerda a derecha... es resultado será casi idéntico y no arroja interés apreciable (salvo que con la reflexibidad lógica por los otros cuadrantes, se puedan acometer en el mismo código dos cuadrantes diferentes). En fin elige recorrerlo en horizontal o en vertical, según te acomode mejor al código, pero no hay apenas diferencias en el resultado, más abajo te pongo una imagen con el recorrido hecho de ambas maneras y verás que no hay diferencia. Las puede haber si la figura entra y sale sobre sí misma, pero lo que no falla esel resultado final de hallar los picos.)

Con la declaración de los bucles, el código y las imágenes debería quedarte claro, los pasos...

Quizás haría falta una imagen para ver como procede la criba... luego me edito, antes termino el mensaje...
Ok, Aquí la imagen que va buscando los picos salientes, esta sería la función que 'criba' los picos, y que opera justo con los puntos obtenidos...
Nota como cuando un pico es seleccionado (por su mayor ángulo), son descartados los que están más 'arriba' que él (o abajo según se mire), en la lista.
Si dos o más puntos tuvieran casualmente el mismo ángulo, se toma por bueno el que quede mas lejos (sino éste luego apuntaría al siguiente y seríans líneas rectas pasando por varios puntos que se resumen en los puntos de los extremos).
En cuatro pasos, pues solo encontró 3 puntos salientes, la imagen final traza las líneas para ver el resultado con claridad.
(http://i.imgur.com/c9xxy4N.png)


Código:
Array Angulos(0 a Picos.count-1) //el tamaño es el de picos
entero n = Picos.Count-1 //K-1 al inicio, pero como podemos saltarnos algunos, lo dejamos en una variable.


Salientes.Add(Picos.count-1)) //el PuntoB
Bucle para k desde Picos.Count-1 a 2 retrocediendo
    // bucle para calcular el ángulo desde el punto actual al resto anteriores.
    Bucle para j desde n hasta 1 retrocediendo
        Angulo = CalcularAngulo(Picos(0), Picos(k), Picos(j))
        Angulos (j)= Angulo  //ambas lineas pueden ser solo una, se deja en dos para que quede claro que
           // la función devuelve el ángulo que forman los 3 puntos en ese orden (con Picos(k) en medio).
    Fin bucle
    //Tomar el ángulo mayor de todos.
    Bucle para j desde n-1 hasta 1 retrocediendo
        Si Angulos(j) > Angulos(n) luego n = j
    Fin Bucle
    Salientes.Add(punto picos(n))  //
Fin bucle
Salientes.Add(Picos(0)) // El PuntoA

//Ahora puede trazarse una línea desde un punto de 'salientes' al siguiente y veremos si el trazado es correcto.
Y con esto hemos resuelto este cuadrante.


4) Una vez detectado los puntos de cada pico se trazan linea desde el punto final (o el punto de origen) hacia cada punto detectado y la linea que tenga mayor angulo sera el punto mas saliente.
Si, pero el ángulo formado entre el punto final y la línea que va de PuntoA al PuntoB (final), luego se repite desde el punto recién hallado con ángulo más saliente, el angulo será partiendo desde este al PuntoA (y a los respectivos puntos más 'hacia donde avanzamos' que quedan en la dirección opuesta de donde partimos. en este cuadrante empezamos a recorrer los picos desde el PuntoB (horariamente la aguja de las '3') y en dirección antihoraria (hasta la aguja que marca las '12'). Realmente no importa el orden en que se recorran. Si quieres reutilizar la lista previa (en vez de asignar a una nueva los válidos), empieza desde 0 hacia arriba, y eliminas los que no se quedan..
Pongo otra imagen mejor, para que se vea esto... Ya está es la última imagen subida puesto más arriba.

Nota que en realidad se toma como pico (promesa) el píxel hallado blanco tras un previo hallado negro. si esto ocurre más de una vez en la misma línea (con el recorrido horizontal que hacemos), el que quede al final (el más a la derecha hallado), es el que se añade, por eso se añade al terminar el bucle... en la misma línea se va actualizando...
Esto implica que una curva, va a ofrecer muchos 'picos promesa'.... podríamos sacar una línea tangente a la curva y tomar el punto de tangencia como válido, pero no conviene que te compliques tanto, una pequeña inexactitud, no merma el resultado ni se va a notar demasiado retraso por añadir 20 puntos más que los 3 o 4 previstos inicialmente). El tiempo dependerá del tamaño de la imagen, básicamente...

Te pongo una imagen final, que muestra algunas cosas que te decía...
1 - Que no importa si eliges un recorrido horizontal a derecgha y bajando, que si eliges un recorrido vertical subiendo y a izquierda
(linea azul es bucle 'Y' y luego bucle 'X' a derecha , línea verde es bucle 'X' y dentro bucle 'Y' ascendiendo).
2 - En cyan he encerrado una zona con curva, pero luego en un dibujo más pequeño, he realizado otro apuntado por una letra 'P' en amarillo.
3 - La forma en que avanza el bucle interno. Si toca la diganonal, el bucle x comienza en ese valor, si hubo un pico antes más adelante que la diagonal, el bucle X (es decir dX) comienza ahí....
(http://i.imgur.com/fmkKBSy.png)


-----------
Para finalizar... podemos optimizar el bucle interno, verás:
En realidad si recorriéramos el bucle interno de derech a izquierda, nos pararíamos al encontrar el primer pixel negro, ese punto sería el que se añade y saltamos al final de la siguiente línea y retrocediendo de derecha a izquierda. A lo sumo hasta el pixel hallado en la línea anterior (dX) o el que marque la diagonal, esto no cambia. No requiere comprobar posteriores apariciones, todavez que el que está más a la derecha es el que nos interesa.
El código resultante requerirá menos comprobaciones...
(http://i.imgur.com/hljpDxc.png)



Modifico el pseudocódigo, para reflejarlo, ahora verás que es bastante sencillo y despejado.
Código:
Array LineaDiagonal() <----- previamente calculada con el algoritmo de Bresenham (por ejemplo).
Entero dX= 0 // al comienzo será: PuntoSuperior.X, pero dejemos qu actúe el bucle.

Picos.Add(punto (PuntoA.Y, PuntoA.X)) //añadimos el punto inicial al comienzo (ojo, no añadirlo dos veces, si es así, empezar el bucle Y uno más adelante

// El bucle y, recorre en este cuadrante las líneas verticalmente hacia abajo
Bucle para Y desde puntoSuperior.Y hasta Punto.Derecha.Y    
    Si (dX < LineaDiagonal(Y) ) luego // LineaDiagonal(Y) tiene el valor de X en esa línea.
        dX = LineaDiagonal(Y)
    Fin si

    // El bucle x es quien hace todo el trabajo de detección
    Bucle para X desde PuntoDerecha.X hasta dX retrocediendo        
        Si (pixel(Y, X) = ColorNegro) luego //Si hay un pixel negro, es el más saliente en esta línea  
                // La figura era toda negra y el resto blanco, no?, o era al revés?                          
                dX = X      //en la siguiente línea el bucle terminará en dx (como máximo), y en lo que resta de alto, nunca menos de este valor..  
                Picos.Add(Punto (Y, dX))  // se encontró un pico se añade
                salir del bucle //no hace falta seguir mirando en esta línea.            
        Fin si
    Fin Bucle
Fin bucle
Picos.Add(Punto (PuntoB.Y,PuntoB.X)) //añadimos el punto final (ojo, no añadirlo dos veces, si es así, llegar a uno menos en el bucle Y)


PD: alguien no tendra el link de un post que hable sobre como hacer lineas en java? no me refiero al elemento graphics sino a calcular los puntos de la linea que pasa por dos puntos, lo logre hacer con trigonometria, y con funciones lineales, pero al comparar mis lineas con las del elemento graphics no son iguales tienes unas pequeñas diferencias, estare subiendo el codigo de las lineas mas tarde.
Ya te comentaba más arriba (al comienzo), el algoritmo de Bresenham, que además es muy fácil de entender y opera con enteros. Además también difiere segun el cuadrante (la dirección), lo que viene en sincronía con lo que vamos haciendo... podemos implementar 4 diferentes más simplificados uno para cada cuadrante.


Esta detección (de áreas) es costosa de codificar, pero es muy precisa. Si se requiere menos precisión, puedes recurrir a otros sencillos métodos...
Si te parece bien, en otro momento te comento por encima otro método más sencillo, donde no importa tanto la exactitud de las formas, se considera similar, es adecuado por ejemplo para detectar caras, de lo que no es, coches de lo que no es, etc... es decir no se requiere una exactitud en la forma, si no una clara 'compatibilidad' de la forma. Dos rostros humanos, son similares (aunque dos personas sean muy distintas), comparados con por ejemplo una lechuga, un avión, una nube, una montaña, etc...


-------------------
p.d2.: He puesto por ahí alguna incongruencia (posibemente algo esté inexacto o tal aunque procuro asegurarme alguno se escapa, si tienes dudas por ello avisa) ... en alguna parte a los puntos de los cuadrantes los he llamado PuntoA y PuntoB y en otra PuntoSuperior y PuntoDerecha... es cosa de escribir parte ayer de madrugada y parte hoy... en vez de todo del tirón, pero sin más importancia.


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: footer en 28 Agosto 2017, 04:57 am
Hola NEBIRE traigo aqui algunas dudas y un poco de codigo para ver si voy bien encaminado, cualquier punto de vista y/o observaciones constructivas seran tenidas en cuentas.

Con respecto al centro de cada cuadrante ya me quedo bien claro como debe ser.
Al crear las lineas del punto central tomare la distancia x que hay entre ambos puntos salientes, eso me indicara que distancia recorrera como maximo el bucle interno del scanner horizontal, esto se cumple solo en la primera fila ya que la linea esta inclinada.


Con respecto al "scanner horizontal" lo hare desde fuera hacia dentro. Cuando encuentre un pixel negro entonces la siguiente linea llegara como maximo hasta esa posicion y agregara el pixel a un array.

teniendo en cuenta la siguiente imagen:

(https://image.ibb.co/d2kue5/img2.png)

Esto seria el scanner horizontal en el cuadrante cuatro (anti reloj)

Se puede decir que el "scanner" horizontal no me detectara el punto mas saliente de cada pico, sino que me detectara un conjunto de posibles puntos salientes, en ese conjunto de puntos esta incluido el punto saliente que estoy buscando
Por ejemplo en la imagen cada cuadrado amarillo es un punto detectado por el scanner entonces cada punto amarillo sera agregado al arraylist "posiblesPuntosSalientes" luego queda ver cual de todos esos puntos son los que busco (en la imagen son solo 2 puntos los que busco ya que son dos picos pero en el array de posibles puntos tendre: 14 puntos, para saber cual es el que busco entonces calculo el angulo en esos catorce puntos tomando el ultimo punto del cuadrante como punto central y el posible punto saliente que mas angulo me dé será el más saliente de todos, eso me lleva a decir tambien que los angulos que luego usare para comparar no se calcularan con cada punto saliente sino que se calculara con cada posible punto saliente, es correcto esto?...


Con respecto a calcular el angulo he visto en el pseudocodigo que para calcular el angulo envias tres parametros, Picos(0), Picos(k), Picos(j), por que no se envian solo dos parametros? punto central y punto del que se quiere saber el angulo?

" Si dos o más puntos tuvieran casualmente el mismo ángulo, se toma por bueno el que quede mas lejos "
Supongo que sera mas lejos del punto que se toma como central para calcular los angulos en este caso el punto B.

Estas serian las primeras dudas, ya que por esto voy a arrancar:

Sobre el pseodocodigo:
si, la figura es toda negra y el fondo es blanco.
si aplico este pseudocodigo pasara lo de la imagen de arriba, cada vez que detecte pixel negro se agregara al array, pero esto no garantiza que el pixel que se agrega sea el punto saliente sino que sera un posible punto saliente y entre esas posibilidades esta el que se busca (el mas saliente de ese pico) que se detectara con su angulo mayor al de los demas (para ese pico).



Sobre el algoritmo de Bresenham, lo busque y lo estuve viendo, algunas cosas las entiendo otras no... igual para mi suerte puede implementarlo y usarlo para hacer lineas rectas, eso queda pendiente saber como funciona al 100% ese algoritmo, una de las dudas era:
 p = 2*dy - dx; Eso se puede leer como: 2 veces la distancia en el eje 'y' menos 1 vez la distancia en el eje 'x' pero no se que es eso visto del punto de vista de la matematica, que representa, que nombre tiene, que significa... etc.

He escrito algo de codigo, el codigo resuelve el primer cuadrante de cada imagen, los cuadrantes se cuentan en sentido contrario a las agujas del reloj, lo hice asi por que asi habia comenzado a hacerlo con la idea anterior (la del scanner con lineas diagonales) y para no perder tiempo modificando algo que ya estaba hecho lo hice de esta manera

El codigo tiene algunos comentarios, se hace partiendo desde la deteccion de poligono ya que lo anterior es para convertir la img en escala de grises y sacar los bordes, pintar la img etc. Tambien se incluye la imagen (que trae 5 imagenes dentro 5 en 1) esta img se llama "a.png". Al ejecutar el programa guarda en el disco "D:/" varias imagenes, que son los pasos del programa, las que tienen mas importancia son las imagenes llamadas "PPS0.png", "PPS1.png"... en esas imagenes se ven los resultados del scanner horizontal donde cada posible punto saliente es marcado en verde, los puntos rojos son los puntos mas salientes de cada lado. Luego las imagenes que se llaman "TrazarLineaX.png"... son las imagenes que muestran los puntos mas salientes y los posibles puntos salientes pero ademas de eso tambien muestra los puntos salientes que resuelven ese cuadrante (puntos de color azul), en la imagen 4 hay un error que es por la forma en que se calculan los angulos entre dos puntos, toma una recta en el eje de absisas positivo como perteneciente al cuadrante 4 entonces eso hace que tenga angulo de 360 cuando tiene 0.

subido a google drive.
link del codigo = https://drive.google.com/open?id=0B1i-JNEuRD1zU3JPOWlVbzhOLUU

PD: en entos dias subire una imagen que refleje una duda que tengo sobre esta forma de detectar los puntos salientes.

Saludos.






Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 28 Agosto 2017, 16:41 pm
Oh, a la noche te releo con detenimiento y contesto tus dudas, también revisaré el código, ya lo he descargado.


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 30 Agosto 2017, 05:58 am
Te voy respondiendo con cita,s al ser un mensaje algo largo y por ello difícil de retener en memoria cada cuestión planteada...

Con respecto al centro de cada cuadrante ya me quedo bien claro como debe ser.
Al crear las lineas del punto central tomare la distancia x que hay entre ambos puntos salientes, eso me indicara que distancia recorrera como maximo el bucle interno del scanner horizontal, esto se cumple solo en la primera fila ya que la linea esta inclinada.
Exacto. de ahí la importancia de tener en un array los valores de x (más a la derecha), para dicha diagonal (la línea entre tales 2 puntos).
Fíjate además que ese array determina al mismo tiempo el máximo número de pícos salientes hallados. Esto es como máximo 1 por cada píxel en x. en definitiva... ya sabes el número menor de picos al contar cuantas veces se corta la figura con la línea y como máximo, la cantidad del ancho de x (nunca o casi nunca será este valor,  pero nos ale saber que es el valor máximo de picos).  

Con respecto al "scanner horizontal" lo hare desde fuera hacia dentro. Cuando encuentre un pixel negro entonces la siguiente linea llegara como maximo hasta esa posicion y agregará el pixel a un array.
Como máximo hasta esa posición... o la línea diagonal si aparece antes de esa posición. Pero en este último caso, no se añade píxel solo se actualiza el valor límite (yo lo llamé 'dX').

Mira la última imagen que puse,. date cuenta como casi lllegando a la parte baja, se encuentra la diagonal, y todavía después encuentra algún pico...

Se puede decir que el "scanner" horizontal no me detectara el punto mas saliente de cada pico, sino que me detectara un conjunto de posibles puntos salientes, en ese conjunto de puntos esta incluido el punto saliente que estoy buscando
Si. Y luego con la siguient eparte de calcular el ángulo más saliente, identifica finalmente los correctos dejando fuera al resto de 'promesas'.
Aún así, se puede optimizar bastante... date cuenta que si en la línea se detecta un pico en x en 345, y 3 líneas más abajo en 543, la diferencia horizontal entre solo 3 líneas hace descartar la previa.... pero primero logra que funciones correctamente y luego ya te entretienes en optimizarlo. Si te hubier apuesto un pseudocódigo muy optimizado, a buen seguro sería muy farrafgoso de entender el por qué de cada cosa... tal como te lo dejé es sencillo de entender y se presta a optimizaciones aún...


teniendo en cuenta la siguiente imagen:
(https://image.ibb.co/d2kue5/img2.png)
Esto seria el scanner horizontal en el cuadrante cuatro (anti reloj)

Por ejemplo en la imagen cada cuadrado amarillo es un punto detectado por el scanner entonces cada punto amarillo sera agregado al arraylist "posiblesPuntosSalientes"
No. Cada punto amarillo que tienes no. Solo si está más a la derecha que el punto anteriormente añadido. Es decir si tienes un punto en x=234 en Y=7, lo añades, pero no hay que añadir el x=234 para Y=8, Y=9, y=10...

De hecho al recorrerlo verticalmente (este cuadrante desde arriba hacia abajo) casi aseguramos que el bueno cuando varios en vertical son 'igual de salientes' el más prometedor será el que esté más arriba. Y digo casi para no entrar en polémica...
En tu dibujo, suponiendo que cada cuadradito fuera:
---- un píxel solo habría unos 5-6 puntos (contando el primero y el último).
---- una retícula de 5x5 píxels, seguramente haya tantos como 18 (sobre unos 30 que esería el ancho).

Se añaden siempre al comienzo, antes del bucle el PuntoA, y al final tras el bucle el PuntoB. De tal modo que si finalmente todo el tramo entre ellos estuyviera interno a la línea diagonal, solo esos 2 puntos definirían el perímetro exterior en ese cuadrante.

luego queda ver cual de todos esos puntos son los que busco (en la imagen son solo 2 puntos los que busco ya que son dos picos pero en el array de posibles puntos tendre: 14 puntos, para saber cual es el que busco entonces calculo el angulo en esos catorce puntos tomando el ultimo punto del cuadrante como punto central y el posible punto saliente que mas angulo me dé será el más saliente de todos, eso me lleva a decir tambien que los angulos que luego usare para comparar no se calcularan con cada punto saliente sino que se calculara con cada posible punto saliente, es correcto esto?...
Hago una imagen con ángulos y puntos más acentuados que permitan ver mejor los detalle y añado más comentarios que aclaren la situación. Ya están (varias, ahora las explico).

En la primera imagen, en el apartado 1. Cada 'e' (entra) y 's' (sale), cuenta los picos mínimos... 7 en total.
La línea amarilla, es la solución, 4 puntos intermedios + los 2 externos = 6 puntos delimitan ese cuadrante.
La línea cyan, deine el valor que en cada cilo tomará 'dX' al comienzo del bucle. Esta línea no son todos los puntos salientes. Las líneas verticales y horizontales (cyan), no se añadirán como 'promesas'. Tampoco (aunque en este ejemplo no sucede ninguna vez), cuando tocan la línea diagonal. esos tampoco se añaden, solo se añade aquel punto que en una línea hace el cambio de blanco a negro (o negro a blanco, según hayamos tratado la imagen) y que está en esa línea lo más a la derecha posible (para este cuadrante).

En la última imagen que subiré, he trazado la misma línea y luego he tachado los puntos que no se añadirán y luego a distancia he reasaltado (en azul) los que se irán añadiendo (las promesas).

(http://i.imgur.com/O4cwVng.png)


En la siguiente imagen he trazado varias líneas fiormando ángulos (la diagonal roja va desde el PuntoA (Picos(0) al PuntoB  (Picos(k) y desde éste a cada uno de los que forman el bucle 'j'. Lógicamente he abreviado, habrá muchos más puntos promesa...
(http://i.imgur.com/3B98vH6.png)

En esta otra, ahora el punto K, es el que antes fue el 'j' elegido como el de mayor ángulo. Y el bucle 'j' recorre los puntos que están 'por encima de él' (encima, debajo, ya saber que depende de la forma de recorrer los bucles, la imagen ayuda aentender y fijar el caso).
Para el caso concreto, he vuelto a trazar de rojo, la línea que va desde Picos(0) a Picos(k) (el que ahora es k, el bucle externo).
Fíjate que una posible optimización es descartar todos los picos (por encima de él), que tengan ángulo inferior a 0, es decir los que queden a la izquierda de la línea roja entre él y el puntoA de origen. al caos he marcado 2 puntos (color verde), como representantes de este caso.
Ahora bien esa optimización solo lo será en función de cuantos haya, si sale más caro una cosa que otra. Pero en cualquier caso, si el ánguilo es negativo, ya ni siquiera lo comparamos, se descarta...o mejor se eliminan d ela colección, así cuando vayamos subiendo más arriba no hay que volverlos a calcular ni comparar...
(http://i.imgur.com/oC1YVT5.png)

En la siguiente imagen ya quedan pocos puntos promesas (serán más, yo resumo para nio poner tantas líneas que no quede claro).
(http://i.imgur.com/39oC0vG.png)

Finalmente hallamos el último punto, es decir es el de origen, no pasa por poco por otro en medio.
Fíjate que tiene ángulo negativo. En cambio el ángulo resultante es 0.
(http://i.imgur.com/wSjfSpZ.png)

Ahora una imagen que muestra otros aspectos de interés y que espero que ayude a aclararte las dudas que puedna quedarte.
Tiene 3 apartados, al 1º me refiero aquí, los otros dos son para más abajo, donde voy respondiendo, y no se hace necesario poner más imágenes independientes.

Nota como los "puntos promesa", realmente sólo son aquellos que tiran por la línea azul. De las líneas que 'caen verticalmente solo se toma como promesa el que se encuentra por primera vez, si en la siguiente línea no hay uno más a la derecha que ese anterior, no se añade.
Con las líneas horizontales pasa los mismo, solo se añade el que está más a la derecha.
Igualmente aunque estén más a la derecha que en líneas anteriores, si no cambian tocando un pixel de blanco a negro, no cuentan aunque toquen la diagonal y estén más a la derecha... porque 'acaba la línea' sin haber tocado un punto negro', luego no se añade.
(http://i.imgur.com/7sC4QEd.png)


Con respecto a calcular el angulo he visto en el pseudocodigo que para calcular el angulo envias tres parametros, Picos(0), Picos(k), Picos(j), por que no se envian solo dos parametros? punto central y punto del que se quiere saber el angulo?
En efecto, Picos(0) es fijo para todos... pero el ángulo se calcula con 3 puntos. Además el orden de estos es importante, si no estarías tomando otro ángulo del 'triángulo que forman los 3 puntos.

En la última imagen subida, en el apartado 3, constan 3 puntos y el ángulo que forman entre si...

Si llamas a una función, puede pasar solo el 2º y 3º puntos siempre y cuando compartas el array y por tanto la función llamada, pueda saber el valor del punto primero ( Picos(0) ).

Picos(0) : Es el punto superior que hallamos al comienzo.
Picos(k) : Es el punto desde el cual estamos tirando ángulos hasta el resto de picos.
Picos(j) : Son cada uno de los puntos que en el presente bucle interno, nos dará los ángulos entre los cuales, se debe conocer el ángulo mayor.

Hallado el punto de este bucle, este hallado pasa a ser el el siguiente ciclo el Picos(k). (en el siguiente bucle, se descartan los picos intermedios entre el k actual y el j, es decir k pasa a ser j... este bucle puede ser un while... pero no  quiero condicionarte con detalles, tu busca la salida y ya si te alejas mucho yo te reoriento...

" Si dos o más puntos tuvieran casualmente el mismo ángulo, se toma por bueno el que quede mas lejos "
Supongo que sera mas lejos del punto que se toma como central para calcular los angulos en este caso el punto B.
En la última imagen en el apartado '2', pongo un ejemplo con dos casos. Hay varios picos salientes, pero están en líonea.
Es decir, los angulos: IAB, IAC, IAD e IAE, son iguales, luego sus puntos están alineados en línea recta).
Entonces el punto más alejado es IAE, ya que sería redundante dar por válido como picos a B,C,D y E.
Al decir más alejado, me refiero a la dirección en la que avance el bucle, como los picos los vamos recorriendo hacia atrás, el más 'lejano' será: E, si fuera creciente, desde E, el más lejano sería A (B,C y D serían redundantes).
He puesto el mismo caso con E, F, G, H e I , están en línea recta, todos tienen el mismo ángulo:
IEF = IFG = IGH = IHI (olvida el caso de que I esté alineado con ellos, y el ángulo sea 0...
Nota que todos los pìcos por dentro de la diagonal IA, tienen ángulo menor de 0, por eso la respuesta en ese caso sería la línea I-A.


Sobre el pseodocodigo:
si, la figura es toda negra y el fondo es blanco.
si aplico este pseudocodigo pasara lo de la imagen de arriba, cada vez que detecte pixel negro se agregara al array, pero esto no garantiza que el pixel que se agrega sea el punto saliente sino que sera un posible punto saliente y entre esas posibilidades esta el que se busca (el mas saliente de ese pico) que se detectara con su angulo mayor al de los demas (para ese pico).
Si, lo hemos comentado más arriba...


Sobre el algoritmo de Bresenham, lo busque y lo estuve viendo, algunas cosas las entiendo otras no... igual para mi suerte puede implementarlo y usarlo para hacer lineas rectas, eso queda pendiente saber como funciona al 100% ese algoritmo, una de las dudas era:
 p = 2*dy - dx; Eso se puede leer como: 2 veces la distancia en el eje 'y' menos 1 vez la distancia en el eje 'x' pero no se que es eso visto del punto de vista de la matematica, que representa, que nombre tiene, que significa... etc.
Ok, mañana a ver si después de comer saco un tiempito y te doy unas explicaciones y un sencillo pseudocódigo que te ayude a entenderlo bien...


He escrito algo de codigo, el codigo resuelve el primer cuadrante de cada imagen, los cuadrantes se cuentan en sentido contrario a las agujas del reloj, lo hice asi por que asi habia comenzado a hacerlo con la idea anterior (la del scanner con lineas diagonales) y para no perder tiempo modificando algo que ya estaba hecho lo hice de esta manera

El codigo tiene algunos comentarios, se hace partiendo desde la deteccion de poligono ya que lo anterior es para convertir la img en escala de grises y sacar los bordes, pintar la img etc. Tambien se incluye la imagen (que trae 5 imagenes dentro 5 en 1) esta img se llama "a.png". Al ejecutar el programa guarda en el disco "D:/" varias imagenes, que son los pasos del programa, las que tienen mas importancia son las imagenes llamadas "PPS0.png", "PPS1.png"... en esas imagenes se ven los resultados del scanner horizontal donde cada posible punto saliente es marcado en verde, los puntos rojos son los puntos mas salientes de cada lado. Luego las imagenes que se llaman "TrazarLineaX.png"... son las imagenes que muestran los puntos mas salientes y los posibles puntos salientes pero ademas de eso tambien muestra los puntos salientes que resuelven ese cuadrante (puntos de color azul), en la imagen 4 hay un error que es por la forma en que se calculan los angulos entre dos puntos, toma una recta en el eje de absisas positivo como perteneciente al cuadrante 4 entonces eso hace que tenga angulo de 360 cuando tiene 0.
Bien, aunque lo descargué tengo pendiente mirarlo, a ver si saco tiempo y te comento.

PD: en entos dias subire una imagen que refleje una duda que tengo sobre esta forma de detectar los puntos salientes.
De acuerdo.
Piensa que se puede optimizar, pero lo interesante al principio es que lo entiendas bien y te funcione correctamente. Luego cuando ya lo tengas perfectamente claro puedes tratar de optimizarlo.
es evidente que si te pongo un pseudiocódigo muy optimizado, resultará complejo entender y no quedará claro el porqué de cada cosa... ahora mismo tal como está es muy sencillo y fácil de entender (creo yo, claro  :laugh: :laugh: :laugh: o al menos esa es la idea  :silbar: :silbar: ).








Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 2 Septiembre 2017, 03:27 am
Ajustado de tiempo, iba a apuntarte a wikipedia, para el algoritmo de Bresenham, pero luego que he ido a verlo solo tiene un párrafo y el 'pseudocódigo' es desastroso e incomprensible. Así que en vez de ponerte aquí la descripción del algoritmo de Bresenham, lo editaré en la wikipedia y te paso el enlace (así será útil para todo el mundo), además en el foro no he encontrado ninguno específico dedicado a algoritmos donde ponerlo y dejarlo aquí 'encerrado' acabará perdiéndose en la 'maleza del bosque'.

Mañana estaré ocupado con un evento familiar, así que será cuando saque un tiempito el domingo (incluso probablemente en la madrugada del lunes antes de ir al trabajo). Las imágenes con las que lo acompañe, serán a mano alzada (así que alguno (bueno, muchos) en wikipedia se quejarán y espero que gente con más tiempo libre y buen hacer, con el tiempo las cambie por algunas bien trabajadas  :laugh: :laugh: :laugh:).


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: footer en 9 Septiembre 2017, 04:09 am
Hola NEBIRE, una vez mas te doy gracias por la explicacion y pido disculpas por el tiempo de respuesta, es que he estado teniendo algunas complicaciones y poco tiempo, ademas mi codigo es un lio.

Asi que voy a empezar de nuevo todo el proyecto desde cero, y voy a aplicar lo que me dijiste que haga, puntos centrales, cuadrantes, promesas, cantidad minima de picos, etc.

Cuando tenga mi codigo hecho lo publicare aqui, por ahora las ideas quedaron claras, saludos,

PD: voy a revisar la wikipedia apara ver tus explicaciones, hasta la proxima. (Y)


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 10 Septiembre 2017, 01:45 am
Bien...

Es importante hacer siempre un buen reparto de clases. si son un par de métodos sólo, s epueden meter de forma privada a una clase, pero cuando son muchos, acaba siendo más práctico y claro, crear una clase al efecto que contenga y mantenga toda la funcionalidad relacionada.

...mientras iré editando el artículo en wikipedia... es realmente sencillo, pero tal como estaba era incomprensible y el pseudocódigo actual, más de lo mismo, amén que no se atiene al algoritmo final... eso csí, lo iré editando sin prisas  :laugh: :laugh: :laugh: :laugh:


Título: Re: Comparar Imagenes y encontrar similitudes.
Publicado por: Serapis en 12 Septiembre 2017, 06:37 am
Ya he editado prácticamente el artículo con el pseudocódigo (que ahora es inteligible, claro y eficaz, antes era un caos y estaba inacabado).

Me falta poner alguna imagen más y acompañarlo de un ejemplo didáctico que muestre paso a paso como funciona.

...y bueno, quizás retocarlo un poco más para que quede más 'enciclopédico', aunque eso ya lo harán otros con el tiempo, de hecho puede que lo acaben dotando con un desarrollo matemático que al final resulte de nuevo ininteligible para la mayoría de los mortales (a pesar de su simplicidad), cuestiones de idiotez en la pureza de las formas, frente a la claridad para el entendimiento...

https://es.wikipedia.org/wiki/Algoritmo_de_Bresenham