Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - razormta

#1
Cita de: cobein en  8 Octubre 2010, 07:28 AM
A ver, si mal no tengo entendido el software de reconocimiento facial comercial ronda el 60% de efectividad, con esto quiero decir, si una compania que se dedica exclusivamente a eso 24/7 con presupuesto, tiempo y recursos no logra un grado de serteza aceptable vale la pena envarcarse en esto?

Este tema es de hace 5 años. Probablemente me digan algo por reabrirlo, pero está interesante lo que dices, ¿Vale la pena enbarcarse en esto?. Claro que vale la pena!.
Tengo más de un año sin programar en c++, volveré, usaré la libreria openCV y cuando lo haya terminado volveré a responder este tema.
#2
Programación C/C++ / Re: Libro opengl 4 en espanol
16 Septiembre 2014, 15:22 PM
si quieres entrarle en serio a la programacion entonces ve aprendiendo ingles  ....

http://user.xmission.com/~nate/tutors.html

esa pagina no tiene nada en español te dire de una vez xd pero tiene un link de descarga con varios codigos de fuente y varios ejecutables, si aprendes a dibujar un triangulo con opengl entonces estas listo para ver que pueden hacer esos ejemplos de nate robins , son bastante basicos pero aprendes demasiados con solo abrir el ejecutable, por otro lado ... yo llegue hasta la parte donde cargas modelos y los texturizas en opengl sin leer manuales xd solo tutoriales ...

como dibujar un triangulo ?, como mover un objeto ? como mover la camara ? ( bastante dificil te sera la creacion de una free camera, utiliza las matrices de rotacion de algebra ).

te he dado varias pistas que entenderas a su momento, por ahora solo empieza con lo que tengas en mente ....


librerias ? te recomiendo GLFW 3, glew, glut, glm, esas son las basicas y GLFW es bastante buena ! en la pagina de GLFW tienes un codigo para crear una ventana bastante sencilla
suerte y acostumbrate al ingles -_-

espero te haya servido de ayuda
#3
Redes / Re: UDP streamming
16 Septiembre 2014, 06:25 AM
Cita de: engel lex en 16 Septiembre 2014, 06:17 AM
esto está relacionado con tu velocidad de subida por lo que parece, normalnente los operadores nos dan una velocidad de descarga mayor que la de subida (porque en teoria nosotros somos consumidores y no servidores, así que mucho te dan cosas como 2Mbps de bajada y 512Kbps de subida), si revisas tu plan contratado podrías corroborar

por qué configuras el tamaño de paquete a mano? el trabajo del protocolo normalmente lo hace el sistema operativo... en que lenguake estás programando?

por cierto... y por aclarar un ultimo punto...

no sobrepasa 100Kbps (kilobits por segundo) o no sobrepasa 100KBps(kilobytes por segundo)?

kilobytes, y en c++, lo programo manual porque quiero probar sabes, es una necesidad ! xd queria ver si el size del packet interferia directamente en la velocidad ... y si, la velocidad de bajada es mas alta que la de subida, pero es mi pc la que descarga  y es la otra pc la que envia los packets , algo he de estar haciendo mal xd mañana revisare el codigo, ahora estoy muy cansado




512 kilobits/s = 64 kilobytes, es justo lo que descarga el programa, pero esa es mi velocidad de subida ... es sencillo de explicar, si no puedo descargar mas de 100kilobytes/s es porque no existe esa cantidad en la red ... solo puedo subir 64kb/s y es eso lo maximo que descargare ...

eso explica porque pude descargar datos a mayor velocidad de la pc de mi amiga de costarica que de la pc de mi amigo al otro lado de la ciudad xd ...
osea, la velocidad de subida de ella debe ser mayor que la de mi amigo xd ... cuando se despierten les pedire que hagan un test de velocidad y comprobare mi teoria o.ó

gracias por darme la idea xd


[MOD] No hagas doble post, para añadir comentarios, usa "modificar". Gracias.
#4
Redes / UDP streamming
16 Septiembre 2014, 06:12 AM
Ok dicen que el protocolo UDP es mejor que el TCP para el video streamming, ok lo entiendo, leo teoria y tiene sentido, entonces programo una aplicacion que envia paquetes no mayores a 1.45kb ( este es el limite, el mtu ), pero la aplicacion no logra enviar mas de 100kb en un segundo .... lo probe con un amigo al otro lado de la ciudad y con una amiga de costa rica y no sobrepasa los 100kb/s ... lo cual no es de mi agrado porque cuando descargo algo de mega o de mediafre , o de cualquier otro lugar, descargo a 160kb/s, .... quiero entender el protocolo udp y no me refiero a guias o manuales.. porque he leido muchos ... me refiero a porque eso ocurre .... ? algun experimentado tiene idea ?
#5
Programación C/C++ / Re: teoria de una videollamada
12 Septiembre 2014, 03:23 AM
Cita de: engel lex en 12 Septiembre 2014, 01:19 AM
si XD se llaman algoritmos de video XD y si, son NOTABLEMENTE diferentes a los de imagen... especialmente porque no son un bmp sino más como un jpeg...

puedes usar el algoritmo de compresion mp4, avi o webm con codec de audio ogg y revisar como enviarlo en stream, esa es la tecnica


me diste una idea ... se me vino a la mente youtube .... y otros reproductores en linea ... reproducen videos en tiempo real ! no solo eso sino que hasta ... hasta son capaces de cargar  mientras los reproduces, mi projecto no tiene mucho que ver con eso pero ... wow ! ahi esta la solucion, gracias xd ahora buscare donde mierdas aprender eso xd
#6
es a tu comodidad pero yo , personalmente te recomiendo poner la textura de un objeto en la clase de dicho objeto, aca te dejo una clase mia de un model 3d

Código (cpp) [Seleccionar]

class eiSprite
{
public:
eiSprite( void );
~eiSprite( void );

bool pushTexture( const char filename[] );
bool loadTexture( const char filename[], const unsigned indice );
bool unloadTexture( const GLuint indice );

bool loadModel( const char filename[] );
bool unloadModel( void );

void unloadAll( void );

bool setDrawingMode( int pMode );
int getDrawingMode( void );

void update( void );

private:

void _loadTexture( const unsigned indice );

void drawTexture( void );
void drawModel( void );
void drawModelTextured( void );

struct
{
glm::vec3 position;
glm::vec3 lookingAt;
glm::vec3 movement;
glm::vec3 rotation;

struct
{
std::vector<eiPic_t> chunk;
std::vector<unsigned> vbo;
}textures;

struct
{
std::vector<unsigned char*> bits;
unsigned size;

std::vector<unsigned> meshesSize;
std::vector<unsigned> meshesIndice;

std::vector<eiModel_Material_t> Materials;
std::vector<unsigned> materialsIndice;

unsigned vao;
unsigned vbo;
}model;

void ( eiSprite::*ptrDraw )();
}self;
};



fijate que yo creo una clase llamada "sprite" que puede ser cualquier objeto, un snake o un bloque lo que sea, y cada uno tiene una textura , si la ves en mi clase esta en la structura self ->texture, claro esto es para que te ilustres, suerte con tu juego
#7
Programación C/C++ / teoria de una videollamada
12 Septiembre 2014, 00:24 AM
Bueno, voy a ser directo, un programa que funciona a manera de videollamda, por ejemplo

servidor: envia datos visuales al cliente
cliente: decodifica datos y los muestra a manera de imagen

se hace esto varios frames en un segudo ..

buum videollamada xd

es esta la manera en que funciona no ? ,  esa pregunta no es el objetivo de este post, resulta que tengo una duda ... tomemos una imagen bmp cualquiera de 800x600x3 pixeles eso es equivalente a 1.4mb no ? hahaha ... yo recibo buena señal por videollamada, sin mucho lag ... pero mi internet solo puede bajar 150kb/s, asi que la teoria de que se envia una imagen bmp es falsa, se necesitarian 10 segundos para enviar una imagen bmp xd entonces .... comprimimos la imagen ? la transformamos en jpg ? ya lo intente con varias imagenes y lo mas que puedo reducir es hasta 50kb , puedo enviar 3 imagenes jpg en 1 segundo .. pero eso seria lag !!!!


entonces la pregutna ... existe alguna manera que ignore , algun algoritmo, alguna forma de enviar informacion visual en vivo ? alguien sabe ? llevo todo el dia pensando ... y no encuentro nada ! xd
#8
Cita de: eferion en 21 Abril 2014, 10:38 AM
La idea está genial. Enhorabuena.

Lo que no veo del todo claro es que en "cannyAlgorithm" tenga que ser todo público.

Quizás sería mejor crear una clase para gestionar la imagen y pasar una instancia de dicha clase a cannyAlgoritm para hacer el trabajo... incluso cannyAlgoritm podría almacenar los resultados en una nueva instancia de imagen y devolverla con un return... así la imagen original no sufre cambios.

Otra idea puede ser la utilización de "interfaces", que en C++ son clases virtuales puras. La idea es poder tener una colección de filtros y usarlos a discrección sin importar su tipo.

La cosa es tener una clase base con un método virtual puro para forzar a sus derivadas a implementarlo... después se hace que los diferentes filtros hereden de la clase base y así puedes usarlos todos de la misma forma ( incluso meterlos en un vector para poder ejectuar diferentes filtros en un orden concreto sin importar su tipo ).

Un ejemplo:

Código (cpp) [Seleccionar]

class Filtro
{
  public:

    Filtro( );

    // El destructor virtual, esto es importante en herencia
    virtual ~Filtro( );

    // Imagen es la clase que te he comentado, se pasa por referencia porque asi
    // te aseguras de que no te pasan punteros nulos
    // el '= 0' es para indicar que esta clase no implementa esta funcion, es
    // responsabilidad de las hijas implementarla.
    // En este caso la imagen que se pasa como argumento se modifica segun el filtro.
    virtual void Filtrar( Imagen& imagen ) = 0;   
};

class FiltroCanny
  : public Filtro
{
  public:

    FiltroCanny( );

    // Este destructor ya no es necesario declararlo virtual, pero tampoco hace ningun mal
    // Es buena idea acostumbrarse a declarar los destructores siempre virtuales
    // para evitar problemas
    virtual ~FiltroCanny( );

    // Esta funcion sera la que implemente tu algoritmo de deteccion de bordes
    // Luego en private puedes poner todas las funciones auxiliares que necesites
    virtual void Filtrar( Imagen& imagen );
};

// Esta clase representa un filtro que convierte una imagen a escala de grises
class FiltroGrayScale
  : public Filtro
{
  public:

    FiltroGrayScale( );

    virtual ~FiltroGrayScale( );

    virtual void Filtrar( Imagen& imagen );
};

// En esta funcion se supone que se va a convertir una imagen en escala de grises
// y despues se va a pasar tu algoritmo
// Es un ejemplo sencillo para ilustrar un poco la flexibilidad de este diseño.
void func( Imagen& imagen )
{
  std::vector< Filtro* > filtros;
  filtros.push_back( new FiltroGrayScale( ) );
  filtros.push_back( new FiltroCanny( ) );

  for ( int i = 0; i < filtros.size( ); i++ )
    filtros[ i ]->Filtrar( imagen );

  for ( int i = 0; i < filtros.size( ); i++ )
    delete filtros[ i ]; 
}


gracias por la idea xd tengo otros filtros , pensare en lo que dijiste y tal ves vuelva con otro post xd
#9
Código (cpp) [Seleccionar]

   gaussianBlur(15, 2);
   grayScale();
   cannyAlgorithm cpix( ~self.data, self.width, self.height, self.bpp / 8 );

   cpix.AutoEdgeDetection( ~self.data, 0.2f, 0.25f );


La linea 1 es necesaria y asumo que ya tienen una funcion llamada "gaussian blur" que aplica el algoritmo gaussiano para disminuir el ruido de una imagen, si no la tienen pueden continuar , pero notaran la diferencia.

La linea 2 es necesaria, asumo que ya tienen una funcion llamada "grayscale" que convierta la imagen a escala de grises , el concepto es sencillo , gray = (r + g + b) / 3
r = g = b = gray

la linea 3 es la inicializacion del algoritmo en mi caso ~self.data es el unsigned char, self.width el ancho, self.height el alto, self.bpp / 8 los bits por pixel.

la linea 4 es iniciar la dectecion de bordes , le introduzco el unsigned char de salida , y dos valores decimales que luego explicare el porque los introduje




Código (cpp) [Seleccionar]

grayScaleCompress();
computeGradients();
nonMaxSupress();
hysteresis(lowV, highV);
grayScaleDecompress();


Son las  5 fases del algoritmo, sin contar la fase de aplicacion de Gauss, iré explicando una por una  y al final mostrare imagenes de lo que obtuve.

1) Gray scale compresión

La imagen introducida debe tener 1 byte por pixel o superior, y se va a trabajar con una imagen que obligatoriamente debe ser de 1 byte por pixel, para eso se comprime la imagen, para evitar errores, ademas se obtiene un mejor resultado si la imagen esta en escala de grises.

Código (cpp) [Seleccionar]
        void grayScaleCompress( void )
       {
           unsigned char * compressed = new unsigned char[ size ];

           for( unsigned offset = 0; offset < size; offset++ )
               compressed[offset] = image[offset* bpp];

           delete[] image;
           image = new unsigned char[ size ];
           memcpy( image, compressed, size );

           delete[] compressed;
       }


Como se ve facilmente, se crea una nueva data con un tamaño de solo ancho x alto y se obliga a la imagen a estar en escala de grises , osea, se convierte a 1 byte por pixel


2) Calcular gradientes

Tuve que leer demasiado ... No soy el mejor en matemáticas , pero se me dan bien y me encuentro con esto. Gradientes ?

Gradientes esta definido como la velocidad con que una función varia.
En nuestro caso estamos trabajando con colores !, es necesario calcular y guardar la velocidad con que en un punto I los colores varian en el eje X y en el eje Y

Código (cpp) [Seleccionar]

void computeGradients( void )
       {
           // Compute Gradients in X
           for( unsigned y = 0; y < height; y++ )
           {
               unsigned offset = y* width;

               Gx[offset] = image[offset + 1] - image[offset];

               offset++;
               for( unsigned x = 1; x < width - 1; x++, offset++ )
                   Gx[offset] = image[offset + 1] - image[offset - 1];

               Gx[offset] = image[offset] - image[offset - 1];
           }
           // Compute Gradients in Y
           for( unsigned x = 0; x < width; x++ )
           {
               unsigned offset = x;

               Gy[offset] = image[offset + width] - image[offset];

               offset += width;
               for( unsigned y = 1; y < height - 1; y++, offset += width )
                   Gy[offset] = image[offset + width] - image[offset - width];

               Gy[offset] = image[offset] - image[offset - width];
           }
           // Hypotenuse = sqrt(x^2 + y^2)
           for( unsigned y = 0, offset = 0; y < height; y++ )
               for( unsigned x = 0; x < width; x++, offset++ )
                   Magnitude[offset] = hypotenuse( Gx[offset], Gy[offset] );
           // Okay, edges of the image must be null
           for( unsigned x = 0; x < width; x++ )
               Magnitude[x] = 0;

           for( unsigned x = 0, offset = width* (height - 1); x < width; x++, offset++ )
               Magnitude[offset] = 0;

           for( unsigned y = 0; y < width* height; y += width )
               Magnitude[y] = 0;

           for( unsigned y = 0, offset = width - 1; y < width* height; y += width, offset += width)
               Magnitude[offset] = 0;
       }



Solo piensen, estan en el centro a su izquierda el color negro, a la derecha el azul, la velocidad con que varian es la resta de ellos dos, calculo entonces esta variacion en todos los puntos I , compruebo la variacion hacendo (I+1) - (I -1), pixel de la derecha - pixel de la izquierda.

Realizo lo mismo con el eje Y, pixel de arriba - pixel de abajo: (I + ancho) - ( I - ancho )


Bien, ahora tengo el array de las variaciones en X y las variaciones en Y ahora calculo la magnitud, que ?? magnitud??

la magnitud de un vector es la distancia entre P1 y P2, la distancia entre el punto de X y el punto de Y , la hipotenusa ! , okay okay, para que hago esto ? porque hago todo esto ?

haha Un borde es facil de detectar porque hay una variacion de colores cuando termina una imagen y comienza otra.
Debemos calcular donde ocurren esas variaciones y hacia donde son más altas




3 ) Supresión de los falsos positivos


Oka, hasta ahora todo parece lógico, fácil de entender. Esta es la parte más  dificil de entender ,por ende dificil de explicar.

Código (cpp) [Seleccionar]
         void nonMaxSupress( void )
       {
           /* Compute magnitudes direction and save it */
           for( unsigned y = 0, offset = 0; y < height; y++ )
               for( unsigned x = 0; x < width; x++, offset++ )
                   Direction[offset] = getAngle( Gx[offset], Gy[offset] );
           /*
               The most complicated part:
               If the pixel is not a local maximum then kill it.
               How do I know if my point is a local max ?
               I will compare the current pixel with neighboring pixels in the gradient direction.
               Remember: Pixel with null magnitude are not candidate to be an edge.
           */
           for( unsigned y = 0, offset = 0; y < height; y++ )
               for( unsigned x = 0; x < width; x++, offset++ )
               {
                   if( Magnitude[offset] && isLocalMax(offset) )
                       image[offset] = Magnitude[offset] > 255 ? 255 : (unsigned char)Magnitude[offset];
                   else
                       image[offset] = 0;
               }
       }


Primero, si la variacion de colores es positiva en X y la variacion de colores es positiva en Y , eso significa que en el plano cartesiano, los colores varian hacia el primer cuadrante, entre los grados 0 - 90

Calculare hacia que direccion apunta la variacion de colores de cada pixel
eso se nota en el primer ciclo, en el segundo ciclo viene lo bueno...

Si saben programar y pueden manipular este codigo a voluntad e intentan visualizar la imagen como va en  esta fase, tendrian algo como esto


Los bordes son muy gruesos ...y hay demasiados bordes, no pareciera, pero si los hay, si pusieran todos los colores de los bordes actuales en 255, la imagen se pondria toda blanca ... porque no esta listo ?? que es la supresion de los falsos positivos ?

Explicare ...

Mencione que al llegar al borde en una imagen hay un cambio de color porque pasas a otro objeto no ? bueno, si tienes un cubo blanco, y te situas en un pixel, de que color es el pixel de la derecha ( I + 1 ) ? blanco no ? y el pixel de la izquierda ( I - 1 ) ? blanco tambien xd entonces la gradiente cuanto sera ? blanco - blanco = 0 !

oka resulta que no solo la gradiente en X es 0 sino la gradiente en Y tambien es 0, que se obtiene ? cuanto vale la hipotenusa ? ?? 0 ! xd

hipotenusa = sqrt( x*x + y*y )

Magnitud = hipotenusa.

lo que se hizo en la imagen de arriba es setear el color del pixel cuya magnitud sea 0 en negro, oka, pero quedan pixeles con magnitud de 2 3 6, que aun es muy bajo ! ... esos son los falsos positivos, puntos en la imagen que no son bordes pero que no se han eliminado, por eso se realiza este proceso


Entonces, como sabemos que un pixel es un verdadero positivo ? un verdadero borde ? comparamos el pixel con la magnitudes de los pixeles en la direccion del gradiente... no es tan complicado como suena xd

si la variacion de colores de tu pixel apunta hacia el noroeste, lo compararemos con las variaciones de colores de los pixeles del noroeste y del suroeste y si es mayor es un verdadero positivo, o tambien llamado un maximo local , entonces el pixel es un posible borde,sino es background


Código (cpp) [Seleccionar]
if( Magnitude[offset] && isLocalMax(offset) )





4 ) Histeresis.

oka, despues de la non maximal suppression tendriamos una imagen con bordes muy delgados, pero no conectados. osea, un borde llega a un punto y no conecta a otro hasta varios pixeles despues, entonces venimos con esta fase del algoritmo de canny que nos dice que debemos introducir dos valores

El primer valor ( High Value ) Es el valor minimo que debe tener el inicio de un borde.

Debemos tener una imagen de salida toda negra, y mirar en la imagen de entrada( nuestra imagen con la nms apilcada ) si el color de un pixel es >= que el high Value, si esto es cierto entonces boom empieza el trazado de un borde

Código (cpp) [Seleccionar]

void hysteresis( float lowScale, float highScale )
       {
           /*
           We need a High value and a Low value, High value will be the edge color.
           All pixels with color higher than ' Hight value ' will be edges
           and we will follow this pixel until another pixel is founded.
           The pixel founded must be a color higher than ' Low value ', if that is the case
           then we will set this pixel like edge, else it will be background ( null ).
           */

           lowScale    = lowScale <= 0.0f ? 0.01f : lowScale > 1.0f ? 1.0f : lowScale;
           highScale   = highScale <= 0.0f ? 0.01f : highScale > 1.0f ? 1.0f : highScale;

           unsigned char globalMax = 0;
           for( unsigned offset = 0; offset < size; offset++ )
               if( image[offset] > globalMax )
                   globalMax = image[offset];

           unsigned highV = globalMax* highScale;
           unsigned lowV = globalMax* lowScale;

           unsigned char * finalPic = new unsigned char[ size ];
           memset( finalPic, 0, size );

           for( unsigned y = 1,offset = 1; y < height - 1; y++ )
               for( unsigned x = 1; x < width - 1; x++, offset++ )
                   if( image[offset] >= highV && !finalPic[offset] )
                   {
                       finalPic[offset] = 255;
                       continuousTracing( offset, image, finalPic, lowV );
                   }

           delete[] image;
           image = new unsigned char[ size ];
           memcpy( image, finalPic, size );

           delete[] finalPic;
       }



Entonces, que es el trazado de un borde ?, imaginate dibujando algo, tu lapiz empieza en un punto X,Y y lo mueves hasta otro punto X,Y dependiendo de lo que quieras dibujar ...

si deseas dibujar una linea recta y vertical, entonces tu lapiz se movera unicamente hacia arriba:

Repeat (X, Y+1) Until Y >= limite de la linea a dibujar.

eso es lo que se hara a continuacion , pero no dibujaremos una linea recta, dibujaremos en diferentes direcciones ! , arriba, abajo, izquierda , derecha , etc ! ... dibujaremos siempre y cuando el pixel sobre el que vayamos a dibujar sea mayor que el Low Value


Código (cpp) [Seleccionar]

void continuousTracing( unsigned offset, unsigned char * in, unsigned char * out, unsigned thresholding )
       {
           /*
           The concept is sample:
           I found a possible edge and I will follow this edge until its end.
           Test 8 neighboring pixels and if someone is higher than thresholding then
           that pixel will be another edge and I will follow it.

           This process is repeated until the value of the current pixel tested is null.
           */
           const unsigned edge = 255;

           unsigned dir[2];
           dir[0] = width;      // Top - Bottom
           dir[1] = 1;          // Left - Right

           unsigned top = min( offset + dir[0], size );
           if( in[top] >= thresholding )
               do
               {
                   if( !out[top] )
                   {
                       out[top] = edge;
                       continuousTracing( top, in, out, thresholding );
                   }
                   else
                       break;

                   top += dir[0];

                   if( top > size )
                       break;

               }while( in[top] >= thresholding );

           unsigned bottom = max( offset - dir[0], 0 );
           if( in[bottom >= thresholding] )
               do
               {
                   if( !out[bottom] )
                   {
                       out[bottom] = edge;
                       continuousTracing( bottom, in, out, thresholding );
                   }
                   else
                       break;

                   bottom -= dir[0];

                   if( bottom < 0 )
                       break;

               }while( in[bottom] >= thresholding );

           unsigned right = min( offset + dir[1], size );
           if( in[right] >= thresholding )
               do
               {
                   if( !out[right] )
                   {
                       out[right] = edge;
                       continuousTracing( right, in, out, thresholding );
                   }
                   else
                       break;

                   right += dir[1];

                   if( right > size )
                       break;

               }while( in[right] >= thresholding );

           unsigned left = max( offset - dir[1], 0 );
           if( in[left] >= thresholding )
               do
               {
                   if( !out[left] )
                   {
                       out[left] = edge;
                       continuousTracing( left, in, out, thresholding );
                   }
                   else
                       break;

                   left -= dir[1];

                   if( left < 0 )
                       break;

               }while( in[left] >= thresholding );

           unsigned topRight = min( offset + dir[0] + dir[1], size );
           if( in[topRight] >= thresholding )
               do
               {
                   if( !out[topRight] )
                   {
                       out[topRight] = edge;
                       continuousTracing( left, in, out, thresholding );
                   }
                   else
                       break;

                   topRight += dir[0] + dir[1];

                   if( topRight > size )
                       break;

               }while( in[topRight] >= thresholding );

           unsigned bottomLeft = max( offset - dir[0] - dir[1], 0 );
           if( in[bottomLeft] >= thresholding )
               do
               {
                   if( !out[bottomLeft] )
                   {
                       out[bottomLeft] = edge;
                       continuousTracing( bottomLeft, in, out, thresholding );
                   }
                   else
                       break;

                   bottomLeft -= dir[0] - dir[1];

                   if( bottomLeft < 0 )
                       break;

               }while( in[bottomLeft] >= thresholding );

           unsigned topLeft = min( offset + dir[0] - dir[1], size );
           if( in[topLeft] >= thresholding )
               do
               {
                   if( !out[topLeft] )
                   {
                       out[topLeft] = edge;
                       continuousTracing( topLeft, in, out, thresholding );
                   }
                   else
                       break;

                   topLeft += dir[0] - dir[1];

                   if( topLeft > size )
                       break;

               }while( in[topLeft] >= thresholding );

           unsigned bottomRight = max( offset - dir[0] + dir[1], 0 );
           if( in[bottomRight] >= thresholding )
               do
               {
                   if( !out[bottomRight] )
                   {
                       out[bottomRight] = edge;
                       continuousTracing( bottomRight, in, out, thresholding );
                   }
                   else
                       break;

                   bottomRight -= dir[0] + dir[1];

                   if( bottomRight < 0 )
                       break;

               }while( in[bottomRight] >= thresholding );

           /* Works with feedback and not will be an infinite loop cause I am saving the new data into a new image */
       }



Se dibujara en la imagen de salida, si el punto a pintar ya estaba pintado entonces se rompe el ciclo y se impide que ocurra un bucle infinito..

mi primera función que logra re alimentarse ella misma xd




RESULTADOS FINALES
[/size]





Listop, no puse más porque me da pereza, esto lo hize con la mera intencion de que si alguien busca en google "Canny algorithm" y busca resultados en español, obtenga una buena ayuda.

Y perdonen si mi codigo es desordenado, volvi a la programacion hace un par de meses y solo he leido un par de tutoriales .. en ingles depaso xd
#10
Hola, hace un par de meses realize un post para pedir que me ayudaran a leer una imagen haha, lo logré hacer por mi cuenta y he aprendido bastante sobre el manejo básico de imagenes.

El siguiente post lo realizo porque me molesta que haya tan pocos artículos en español sobre este tema. Lo que pondré es un algoritmo de detección de bordes de una imagen en c++, lo acabo de terminar xd

Lo pondré luego explicaré cada parte.

Código (cpp) [Seleccionar]


struct cannyAlgorithm
   {
       unsigned char * image;

       unsigned width;
       unsigned height;
       unsigned size;
       unsigned bpp;

       short * Gx;
       short * Gy;

       short * Direction;

       double * Magnitude;

       cannyAlgorithm( unsigned char * data, unsigned imgw, unsigned imgh, unsigned bitsperpixel )
       {
           width   = imgw;
           height  = imgh;

           size = width* height;

           bpp = bitsperpixel;

           Gx = new short[ size ];
           Gy = new short[ size ];

           Direction = new short[ size ];

           Magnitude = new double[ size ];

           image = new unsigned char[ size* bpp ];
           memcpy( image, data, size* bpp );
       }
       ~cannyAlgorithm( void )
       {
           delete[] Gx;
           delete[] Gy;
           delete[] Direction;
           delete[] Magnitude;
       }
       int max( int a, int b )
       {
           int c = a > b ? a : b;
           return c;
       }
       int min( int a, int b )
       {
           int c = a < b ? a : b;
           return c;
       }
       short getAngle( double X, double Y )
       {
           short Angle;

           if( X* Y > 0 )  // Quadrant 1 or 3
           {
               if( abs( X ) >= abs( Y ) )
                   Angle = 0;
               else
                   Angle = 180;
           }
           else            // Quadrant 2 or 4
           {
               if( abs(X) >= abs(Y) )
                   Angle = 90;
               else
                   Angle = 270;
           }

           return( Angle );
       }
       double hypotenuse( double a, double b )
       {
           double h = sqrt( a*a + b*b );
           return(h);
       }
       bool isLocalMax( unsigned offset )
       {
           unsigned bottom     = max(offset - width, 0);
           unsigned top        = min(offset + width, size);
           unsigned left       = max(offset - 1, 0);
           unsigned right      = min(offset + 1, size);
           unsigned bottomLeft = max(bottom - 1, 0);
           unsigned bottomRight= min(bottom + 1, size);
           unsigned topLeft    = max(top - 1, 0);
           unsigned topRight   = min(top + 1, size);

           double thisPoint = 0.0;
           double mag[2]    = { 0.0 };

           switch( Direction[offset] )
           {
               case 0:
               {
                               /*   90
                                     *
                                     |******
                                     |******
                               -------------* 0
                                     |
                                     |

                               */
                   thisPoint = abs( Gx[offset]* Magnitude[offset] );

                   mag[0] = abs( Gy[offset]* Magnitude[topRight  ] + ( Gx[offset] - Gy[offset] )* Magnitude[right] );
                   mag[1] = abs( Gy[offset]* Magnitude[bottomLeft] + ( Gx[offset] - Gy[offset] )* Magnitude[left ] );
                   }break;

               case 90:
               {
                               /*
                                     90
                                     *
                                *****|
                                *****|
                           180 *-------------
                                     |
                                     |
                               */
                   thisPoint = abs(Gx[offset]* Magnitude[offset] );

                   mag[0] = abs( Gy[offset]* Magnitude[bottomRight] - ( Gx[offset] + Gy[offset])* Magnitude[right] );
                   mag[1] = abs( Gy[offset]* Magnitude[topLeft    ] - ( Gx[offset] + Gy[offset])* Magnitude[left ] );
               }break;

               case 180:
               {
                               /*
                                     |
                                     |
                           180 *-------------
                               ******|
                               ******|
                                     *
                                    270
                               */
                   thisPoint = abs( Gy[offset]* Magnitude[offset] );

                   mag[0] = abs( Gx[offset]* Magnitude[topRight  ] + ( Gy[offset] - Gx[offset] )* Magnitude[top   ] );
                   mag[1] = abs( Gx[offset]* Magnitude[bottomLeft] + ( Gy[offset] - Gx[offset] )* Magnitude[bottom] );
               }break;

               case 270:
               {
                               /*
                                     |
                                     |
                               -------------* 0
                                     |*******
                                     |*******
                                     *
                                    270
                               */
                   thisPoint = abs( Gy[offset]* Magnitude[offset] );

                   mag[0] = abs( Gx[offset]* Magnitude[bottomRight] - ( Gy[offset] + Gx[offset] )* Magnitude[bottom] );
                   mag[1] = abs( Gx[offset]* Magnitude[topLeft    ] - ( Gy[offset] + Gx[offset] )* Magnitude[top   ] );
               }break;

               default:
                   break;
           }

           if( thisPoint >= mag[0] && thisPoint >= mag[1] )
               return( true );
           return( false );
       }
       void grayScaleCompress( void )
       {
           unsigned char * compressed = new unsigned char[ size ];

           for( unsigned offset = 0; offset < size; offset++ )
               compressed[offset] = image[offset* bpp];

           delete[] image;
           image = new unsigned char[ size ];
           memcpy( image, compressed, size );

           delete[] compressed;
       }
       void continuousTracing( unsigned offset, unsigned char * in, unsigned char * out, unsigned thresholding )
       {
           /*
           The concept is sample:
           I found a possible edge and I will follow this edge until its end.
           Test 8 neighboring pixels and if someone is higher than thresholding then
           that pixel will be another edge and I will follow it.

           This process is repeated until the value of the current pixel tested is null.
           */
           const unsigned edge = 255;

           unsigned dir[2];
           dir[0] = width;      // Top - Bottom
           dir[1] = 1;          // Left - Right

           unsigned top = min( offset + dir[0], size );
           if( in[top] >= thresholding )
               do
               {
                   if( !out[top] )
                   {
                       out[top] = edge;
                       continuousTracing( top, in, out, thresholding );
                   }
                   else
                       break;

                   top += dir[0];

                   if( top > size )
                       break;

               }while( in[top] >= thresholding );

           unsigned bottom = max( offset - dir[0], 0 );
           if( in[bottom >= thresholding] )
               do
               {
                   if( !out[bottom] )
                   {
                       out[bottom] = edge;
                       continuousTracing( bottom, in, out, thresholding );
                   }
                   else
                       break;

                   bottom -= dir[0];

                   if( bottom < 0 )
                       break;

               }while( in[bottom] >= thresholding );

           unsigned right = min( offset + dir[1], size );
           if( in[right] >= thresholding )
               do
               {
                   if( !out[right] )
                   {
                       out[right] = edge;
                       continuousTracing( right, in, out, thresholding );
                   }
                   else
                       break;

                   right += dir[1];

                   if( right > size )
                       break;

               }while( in[right] >= thresholding );

           unsigned left = max( offset - dir[1], 0 );
           if( in[left] >= thresholding )
               do
               {
                   if( !out[left] )
                   {
                       out[left] = edge;
                       continuousTracing( left, in, out, thresholding );
                   }
                   else
                       break;

                   left -= dir[1];

                   if( left < 0 )
                       break;

               }while( in[left] >= thresholding );

           unsigned topRight = min( offset + dir[0] + dir[1], size );
           if( in[topRight] >= thresholding )
               do
               {
                   if( !out[topRight] )
                   {
                       out[topRight] = edge;
                       continuousTracing( left, in, out, thresholding );
                   }
                   else
                       break;

                   topRight += dir[0] + dir[1];

                   if( topRight > size )
                       break;

               }while( in[topRight] >= thresholding );

           unsigned bottomLeft = max( offset - dir[0] - dir[1], 0 );
           if( in[bottomLeft] >= thresholding )
               do
               {
                   if( !out[bottomLeft] )
                   {
                       out[bottomLeft] = edge;
                       continuousTracing( bottomLeft, in, out, thresholding );
                   }
                   else
                       break;

                   bottomLeft -= dir[0] - dir[1];

                   if( bottomLeft < 0 )
                       break;

               }while( in[bottomLeft] >= thresholding );

           unsigned topLeft = min( offset + dir[0] - dir[1], size );
           if( in[topLeft] >= thresholding )
               do
               {
                   if( !out[topLeft] )
                   {
                       out[topLeft] = edge;
                       continuousTracing( topLeft, in, out, thresholding );
                   }
                   else
                       break;

                   topLeft += dir[0] - dir[1];

                   if( topLeft > size )
                       break;

               }while( in[topLeft] >= thresholding );

           unsigned bottomRight = max( offset - dir[0] + dir[1], 0 );
           if( in[bottomRight] >= thresholding )
               do
               {
                   if( !out[bottomRight] )
                   {
                       out[bottomRight] = edge;
                       continuousTracing( bottomRight, in, out, thresholding );
                   }
                   else
                       break;

                   bottomRight -= dir[0] + dir[1];

                   if( bottomRight < 0 )
                       break;

               }while( in[bottomRight] >= thresholding );

           /* Works with feedback and not will be an infinite loop cause I am saving the new data into a new image */
       }
       void computeGradients( void )
       {
           // Compute Gradients in X
           for( unsigned y = 0; y < height; y++ )
           {
               unsigned offset = y* width;

               Gx[offset] = image[offset + 1] - image[offset];

               offset++;
               for( unsigned x = 1; x < width - 1; x++, offset++ )
                   Gx[offset] = image[offset + 1] - image[offset - 1];

               Gx[offset] = image[offset] - image[offset - 1];
           }
           // Compute Gradients in Y
           for( unsigned x = 0; x < width; x++ )
           {
               unsigned offset = x;

               Gy[offset] = image[offset + width] - image[offset];

               offset += width;
               for( unsigned y = 1; y < height - 1; y++, offset += width )
                   Gy[offset] = image[offset + width] - image[offset - width];

               Gy[offset] = image[offset] - image[offset - width];
           }
           // Hypotenuse = sqrt(x^2 + y^2)
           for( unsigned y = 0, offset = 0; y < height; y++ )
               for( unsigned x = 0; x < width; x++, offset++ )
                   Magnitude[offset] = hypotenuse( Gx[offset], Gy[offset] );
           // Okay, edges of the image must be null
           for( unsigned x = 0; x < width; x++ )
               Magnitude[x] = 0;

           for( unsigned x = 0, offset = width* (height - 1); x < width; x++, offset++ )
               Magnitude[offset] = 0;

           for( unsigned y = 0; y < width* height; y += width )
               Magnitude[y] = 0;

           for( unsigned y = 0, offset = width - 1; y < width* height; y += width, offset += width)
               Magnitude[offset] = 0;
       }
       void nonMaxSupress( void )
       {
           /* Compute magnitudes direction and save it */
           for( unsigned y = 0, offset = 0; y < height; y++ )
               for( unsigned x = 0; x < width; x++, offset++ )
                   Direction[offset] = getAngle( Gx[offset], Gy[offset] );
           /*
               The most complicated part:
               If the pixel is not a local maximum then kill it.
               How do I know if my point is a local max ?
               I will compare the current pixel with neighboring pixels in the gradient direction.
               Remember: Pixel with null magnitude are not candidate to be an edge.
           */
           for( unsigned y = 0, offset = 0; y < height; y++ )
               for( unsigned x = 0; x < width; x++, offset++ )
               {
                   if( Magnitude[offset] && isLocalMax(offset) )
                       image[offset] = Magnitude[offset] > 255 ? 255 : (unsigned char)Magnitude[offset];
                   else
                       image[offset] = 0;
               }
       }
       void hysteresis( float lowScale, float highScale )
       {
           /*
           We need a High value and a Low value, High value will be the edge color.
           All pixels with color higher than ' Hight value ' will be edges
           and we will follow this pixel until another pixel is founded.
           The pixel founded must be a color higher than ' Low value ', if that is the case
           then we will set this pixel like edge, else it will be background ( null ).
           */

           lowScale    = lowScale <= 0.0f ? 0.01f : lowScale > 1.0f ? 1.0f : lowScale;
           highScale   = highScale <= 0.0f ? 0.01f : highScale > 1.0f ? 1.0f : highScale;

           unsigned char globalMax = 0;
           for( unsigned offset = 0; offset < size; offset++ )
               if( image[offset] > globalMax )
                   globalMax = image[offset];

           unsigned highV = globalMax* highScale;
           unsigned lowV = globalMax* lowScale;

           unsigned char * finalPic = new unsigned char[ size ];
           memset( finalPic, 0, size );

           for( unsigned y = 1,offset = 1; y < height - 1; y++ )
               for( unsigned x = 1; x < width - 1; x++, offset++ )
                   if( image[offset] >= highV && !finalPic[offset] )
                   {
                       finalPic[offset] = 255;
                       continuousTracing( offset, image, finalPic, lowV );
                   }

           delete[] image;
           image = new unsigned char[ size ];
           memcpy( image, finalPic, size );

           delete[] finalPic;
       }
       void grayScaleDecompress( void )
       {
           size = width* height* bpp;
           unsigned char * decompressed = new unsigned char[ size ];

           for( unsigned offset = 0; offset < width* height; offset++ )
               decompressed[offset*bpp + 0] = decompressed[offset* bpp + 1] = decompressed[offset* bpp + 2] = image[offset];

           delete[] image;
           image = new unsigned char[ size ];
           memcpy( image, decompressed, size );

           delete[] decompressed;
       }
       void AutoEdgeDetection( unsigned char * data, float lowV, float highV )
       {
           grayScaleCompress();
           computeGradients();
           nonMaxSupress();
           hysteresis(lowV, highV);
           grayScaleDecompress();

           memcpy( data, image, size );
       }
       unsigned char * get_data( void )
       {
           grayScaleDecompress();
           return( image );
       }
   };




Lo puse todo en una estructura para que sea más portable y además para que  no dependa de otras librerias añadí funciones como max, min y hypotenuse, creo que solo debe incluir la libreria <cmath> para la funcion abs

Se preguntarán: Okay, tengo el algorithmo, ¿ Ahora qué ?.

fácil, para usarlo deben iniciailizarlo con el ancho y alto de la imagen, la cantidad de bits por pixel( 1 , 2 , 3 o 4 ) y el unsigned char de la data de la imagen, ejemplo:

Código (cpp) [Seleccionar]


   gaussianBlur(15, 2);
   grayScale();
   cannyAlgorithm cpix( ~self.data, self.width, self.height, self.bpp / 8 );

   cpix.AutoEdgeDetection( ~self.data, 0.2f, 0.25f );



seguire explicando abajo