[PROYECTO] Procesamiento digital de imagen - Seguimiento de color por webcam

Iniciado por LixKeÜ, 8 Febrero 2011, 10:28 AM

0 Miembros y 1 Visitante están viendo este tema.

LixKeÜ

 Hola a todos ;-). Voy a tratar de explicar mas o menos que es el procesamiento digital de imagen y las utilidades que tiene este campo hoy en día y la amplia utilidad de la misma.
Las imágenes digitales son una matriz ó arreglo rectangular de elementos
que, usualmente son números reales. En este caso trabajaremos con imágenes RGB, es decir los colores de cada pixel de la imagen estará representado mediante la combinación de los colores rojo, verde y azul, cada uno en diferente proporción.
La combinación RGB estándar indica 256 niveles por cada canal, es decir por cada
color rojo, verde o azul.
Para representar el valor de 256, requerimos de 8 bits para cada canal de color. Lo que nos permite una combinación del orden 2563 lo que nos permite una combinación de casi 17 millones de colores. (16,777,216).  

  • Ejemplo de una matriz imagen:

    |(234,067,098) (003,078,067) (056,004,006)|
    |(034,067,067) (036,255,255) (067,056,255)|


    Como las imágenes son una matriz de números podemos hacer operaciones de la álgebra lineal y de este modo realizar filtros para poder obtener una cierta información de la imagen ó realizar cambios en la misma para una mejor compresión del objeto al cual se esta viendo.

    En este programa lo que se hace es habilitar la webcam para la toma de imágenes y capturar la imagen en un picture secundario  el cual luego esa imagen la leemos, el valor de cada pixel osea los valores RGB. Esta es la parte encargada de realizar esa operación:
    modulo: MatrizImagen

    For ContadorY = 0 To Pic.ScaleHeight - 1
    For ContadorX = 0 To (Pic.ScaleWidth * 3) - 1 Step 3
    Rojo = lpBits(ContadorX + 2, ContadorY)
    Verde = lpBits(ContadorX + 1, ContadorY)
    Azul = lpBits(ContadorX, ContadorY)


    Con eso leemos el valor del RGB que compone el color del pixel, por ejemplo: el color ROJO es (255,0,0), el VERDE es (0,255,0), y así las combinaciones van formando los diferentes tonos.

      1.1 Detección de color rojo

    En este programa trataremos de detectar el color rojo para ello usaremos una cierta tolerancia de detección dada por el hscrollbar.
    '++++++++++++++++++++++detecta el color rojo+++++++++++++++++++++++++++++++++++
    '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    If (Rojo - Tolerancia > Azul) And (Rojo - Tolerancia > Verde) Then
    n = n + 1
    Rojo = 0
    Verde = 200
    Azul = 0
    posX = posX + (ContadorX / 3 - 2) '+ posX
    posY = posY + (234 - ContadorY) '+ posY
    End If
     

    Con esto detectamos el color rojo y luego con la posición de los pixel rojo dentro del picture, hacemos un promedio y dibujamos un circulo :P.

    En el segundo ejemplo voy a pasar la imagen a binario, pero primero voy a tratar de hacerla en escala de gris.

      1.2 Escala de Grises:

    Las conversiones entre las imágenes de color y las imágenes en escala de grises no son del todo directas. El ajuste de escala de grises consiste en la multiplicación de cada componente por 3 constantes definidas: Alfa, Beta y Gamma. Posteriormente se promedian las intensidades obtenidas en cada canal . Este proceso sustrae toda la información de color que contiene cada pixel y nos deja una separación de 255 niveles entre el blanco y el negro. Estas 3 constantes se obtienen como la separación entre los canales RGB y el negro:
    Alfa: Separación entre el rojo y el negro. (0.299)
    Beta: Separación entre el verde y el negro. (0.599)
    Gamma: Separación entre el azul y el negro. (0.111)
    '+++++IMAGEN EN ESCALA DE GRIS++++++++++++++
    Y = (Rojo1 * 0.3) + (Verde1 * 0.59) + (Azul1 * 0.11)

    Otra forma:
    Y = Int((0 + Rojo1 + Verde1 + Azul1) / 3)

      1.3 Imagen binaria:

    Ahora para convertirlas en binario osea 255 ó 0 debemos tomar una cierta tolerancia para considerarla negro ó blanco, en este caso mi valor en el cual considero blanco a todo aquello mayor a 100.
     If Y > 100 Then
      Y = 255
     Else
     Y = 0
     End If


    Y por ultimo solo me queda guardar los cambios en la imagen y listo  :xD
    lpBits1(ContadorX1, ContadorY1) = Y
    lpBits1(ContadorX1 + 1, ContadorY1) = Y
    lpBits1(ContadorX1 + 2, ContadorY1) = Y


  • Librerías Utilizadas:
    Public Declare Function CreateDIBSection Lib "gdi32" (ByVal hDC As Long, pBitmapInfo As BITMAPINFO24, ByVal un As Long, lplpVoid As Long, ByVal handle As Long, ByVal dw As Long) As Long 'Si la función tiene éxito, el valor de retorno es un manipulador de lo creado DIB, y * ppvBits recién puntos al bit los valores de mapa de bits.Si la función falla, el valor de retorno es NULL, y ppvBits * es NULL.
    Public Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long 'identifica error
    Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long 'dentifica un contexto de dispositivo existente.
    Public Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long 'El valor devuelto indica si la DC fue puesto en libertad. Si la DC fue puesto en libertad, el valor de retorno es 1.Si la DC no fue puesto en libertad, el valor de retorno es cero.
    Public Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long 'hdc[En] identifica el contexto de dispositivo.hgdiobj[En] identifica el objeto que desea seleccionar.
    Public Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long 'hdcDest [en]Un identificador para el contexto de dispositivo de destino.nXDest [en]La coordenada x, en unidades lógicas, de la esquina superior izquierda del rectángulo de destino.nYDest [en]La coordenada y, en unidades lógicas, de la esquina superior izquierda del rectángulo de destino.[NWidth en]La anchura, en unidades lógicas, de los rectángulos de origen y destino.[NHeight en]La altura, en unidades lógicas, de la fuente y los rectángulos de destino.[HdcSrc en]Un identificador para el contexto de dispositivo de origen.[NXSrc en]La coordenada x, en unidades lógicas, de la esquina superior izquierda del rectángulo de origen.[NYSrc en]La coordenada y, en unidades lógicas, de la esquina superior izquierda del rectángulo de origen.[DwRop en]
    'Un código raster-operación. Estos códigos definen cómo los datos de color para el rectángulo de origen debe ser combinado con los datos de color para el rectángulo de destino para lograr el color final.http://msdn.microsoft.com/en-us/library/dd183370(VS.85).aspx
    Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    Public Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    Public Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr() As Any) As Long
    Public Declare Function capCreateCaptureWindow Lib "avicap32.dll" _
       Alias "capCreateCaptureWindowA" ( _
       ByVal lpszWindowName As String, _
       ByVal dwStyle As Long, _
       ByVal X As Long, _
       ByVal Y As Long, _
       ByVal nWidth As Long, _
       ByVal nHeight As Long, _
       ByVal hwndParent As Long, _
       ByVal nID As Long) As Long
     
    Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
       ByVal hWnd As Long, _
       ByVal wMsg As Long, _
       ByVal wParam As Long, _
       lParam As Any) As Long
     
    Public Declare Function DestroyWindow Lib "user32" (ByVal hndw As Long) As Boolean
    Private Declare Function BitBlt Lib "gdi32" ( _
       ByVal hDestDC As Long, _
       ByVal X As Long, _
       ByVal Y As Long, _
       ByVal nWidth As Long, _
       ByVal nHeight As Long, _
       ByVal hSrcDC As Long, _
       ByVal xSrc As Long, _
       ByVal ySrc As Long, _
       ByVal dwRop As Long) As Long
     
    ' Recupera la imagen del área del control
    Private Declare Function GetWindowDC Lib "user32" (ByVal hWnd As Long) As Long


    Espero que se puede seguir con este proyecto para realizar diferentes utilidades y para la investigación, yo por lo pronto estoy tratando de hacer la deteccion de contornos para poder identificar formas de objetos y medidas pero estoy con lo teórico recien XD. Les dejo ademas unos artículos sobre tratamiento de imágenes que me ayudaron en mucho y que me van a seguir ayudando jaja.



  • DESCARGA:
    http://www.gigasize.com/get.php?d=s3nqrhtnfpf

      1.4 Invertir colores (Negativo):

    Esta operación consiste en invertir cada canal RGB a su negativo (Sí, suena redundante). Por ejemplo, en una película fotográfica en la cual se plasman los colores invertidos de la imagen real. Esto es que el blanco pasa a ser negro, el azul a amarillo, verde a magenta y rojo a cyan. La utilidad de este filtro, se encuentra en la digitalización de películas fotográficas.
    Operacion del ajuste: [(255-R),(255-G),(255-B)]
    For ContadorY1 = 0 To Pic.ScaleHeight - 1
    For ContadorX1 = 0 To (Pic.ScaleWidth * 3) - 1 Step 3
    Rojo1 = lpBits1(ContadorX1 + 2, ContadorY1)
    Verde1 = lpBits1(ContadorX1 + 1, ContadorY1)
    Azul1 = lpBits1(ContadorX1, ContadorY1)
    '++++++++++++++++matriz operacion++++++++++++++++++++++++++++++++++
    lpBits1(ContadorX1, ContadorY1) = 255 - Rojo1
    lpBits1(ContadorX1 + 1, ContadorY1) = 255 - Verde1
    lpBits1(ContadorX1 + 2, ContadorY1) = 255 - Azul1
    '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Next ContadorX1
    Next ContadorY1
    CopyMemory ByVal VarPtrArray(lpBits1), 0&, 4
    dl1 = BitBlt(Pic.hDC, 0, 0, Pic.ScaleWidth, Pic.ScaleHeight, TmpDC1, 0, 0, SRCCOPY)
    dl1 = SelectObject(TmpDC1, AntBmp1)
    dl1 = DeleteObject(mBmp1)
    dl1 = DeleteDC(TmpDC1)
    Pic.Refresh



      1.5 Detección de contornos (by 79137913)

    Esta técnica utiliza el cambio numérico dado por los pixel (en escala de gris)  de un entorno del mismo. Cuando estos cambios son menores a un valor dado (en este caso 9) es por que en el existe un entorno ó borde.
    ΔX = X1-X2
    Dim tmp1 As Integer, tmp2 As Integer, tmp3 As Integer
    '+++++IMAGEN EN ESCALA DE GRIS++++++++++++++
    Y = Int((0 + Rojo1 + Verde1 + Azul1) / 3)
    lpBits1(ContadorX1, ContadorY1) = Y
    lpBits1(ContadorX1 + 1, ContadorY1) = Y
    lpBits1(ContadorX1 + 2, ContadorY1) = Y
    '+++++DETECCION DE BORDE++++++++++++++++
    If ContadorX1 <> 0 And ContadorY1 <> 0 Then 'osea distinto de cero
               tmp3 = lpBits1(ContadorX1 - 1, ContadorY1 - 1)
               tmp2 = lpBits1(ContadorX1 - 1, ContadorY1)
               tmp1 = lpBits1(ContadorX1, ContadorY1 - 1)
               If Abs(tmp2 - tmp1) > 9 Or Abs(tmp3 - tmp1) > 9 Then
                   lpBits1(ContadorX1 - 1, ContadorY1 - 1) = 0
                   lpBits1(ContadorX1 - 2, ContadorY1 - 1) = 0
                   lpBits1(ContadorX1 - 3, ContadorY1 - 1) = 0
               Else
                   'PINTA DE NEGRO EL PIXEL POR QUE AHI HAY UN BORDE
                   lpBits1(ContadorX1 - 1, ContadorY1 - 1) = 255
                   lpBits1(ContadorX1 - 2, ContadorY1 - 1) = 255
                   lpBits1(ContadorX1 - 3, ContadorY1 - 1) = 255
               End If
               End If

    Next ContadorX1
    Next ContadorY1




79137913

HOLA!!!

Mira, aca te dejo mi funcion (con ayuda de LeaA) que marca contornos y piel (por separado) espero que te sirva!
http://goo.gl/fi9DX

GRACIAS POR LEER!!!
"Como no se puede igualar a Dios, ya he decidido que hacer, ¡SUPERARLO!"
"La peor de las ignorancias es no saber corregirlas"

79137913                          *Shadow Scouts Team*

LixKeÜ

 Esta bueno el método para detectar el contorno, es una diferencial. Yo intente esa forma pero no me gusta mucho detectar máximos jeje. Estoy por probar alguna forma de convolucion. La forma de detectar piel no se si servirá mucho para lo q necesitas. Creo q para detectar rostros tendrías q mirar un poco la parte geometrica de la cara

LeandroA

buena LixKeÜ  seguis con el proyecto, espero que le puedas sacar lo maximo

Saludos.

Psyke1

Sin duda alguna tiene muy buena pinta, más tarde le hecho un vistazo! :P

DoEvents! :P