Kinect Basics: Background Subtracction (clipping)

El tratamiento o procesamiento digital de imágenes (TDI o PDI) es una de las etapas fundamentales de un sistema de visión artificial. De forma superficial el TDI o PDI puede definirse como un conjunto de procedimientos que realizan sobre una imagen para su almacenamiento, trasmisión o tratamiento, este tipo de sistemas están enfocados principalmente a la restauración o mejora de imágenes, por lo tanto la entrada para un sistema de este tipo o naturaleza es una imagen de dimensiones definidas(la imagen del kinect) y por ende la salida luego del tratamiento y procesamiento será una imagen con las mismas dimensiones que la de entrada o información(datos) de interés. Sin embargo las entradas y salidas del sistema varían dependiendo del dominio del problema.

El TDI es un proceso que requiere tanto del uso de hardware y software especializado para tal fin. A continuación se describen en términos generales las etapas fundamentales del procesamiento de imágenes.

1) la adquisición de la imagen, para ello es necesario un sensor de imágenes (analógica o digital), capaz de digitalizar la señal de entrada, como por ejemplo una cámara de video, una cámara fotográfica monocroma o a color, un escáner o un Kinect y de producir una imagen para su procesamiento por lo menos cada 1/30 de segundo. Sensible a un segmento del espectro electromagnético (como las bandas de rayos x, ultravioleta, visible o infrarrojo).

2) pre-procesamiento, en esta etapa se busca mejorar la calidad de las imágenes, captadas o capturadas por el sensor, a través de diferentes técnicas de mejoramiento y procesamiento de imágenes, como por ejemplo la atenuación o eliminación total del ruido, mejora del brillo o del contraste de la misma entre otras, se busca aumentar las posibilidades de éxitos y disminuir el margen de error en las etapas posteriores, por lo tanto esta es quizás una de las etapas más importantes dentro del proceso general.

Luego del pre-procesamiento de la imagen, la siguiente etapa y quizás la más importante dentro de un sistema de procesamiento de imágenes debido a su impacto es 3) la segmentación, consiste en dividir la imagen de entrada en sus componentes, es uno de los procesos más complejos, lo que se espera como resultado en esta etapa son los pixeles en brutos que constituyen bien sea una región de interés o los puntos que definen un contorno.

4)la descripción, también denominada selección de rasgos, consiste en extraer o identificar información de interés y que puede llegar a ser útil para el reconocimiento e interpretación de los objetos en las imágenes de entrada

Finalmente la última etapa dentro del procesamiento digital de imágenes es 5) el reconocimiento e interpretación, en la cual a partir de la información recolectada en los procesos anteriores y teniendo en cuenta como punto de comparación si es el caso las imágenes que se tienen como base de datos (6) base de conocimiento), implica asignar significado a un conjunto de objetos reconocidos para posteriormente identificar correspondencias entre estos. De este grupo de objetos saldrá el resultado.

 

Clipping: Es una técnica de segmentación de objetos que consiste en usando la información de profundidad  de los pixeles recolectada por el sensor (kinect)  tomar de cada frame de video los objetos mas cercanos a este(el player) . a continuación el código fuente de como lograrlo usando el SDK de kinect, opencv en C++:

 

#include "stdafx.h"
#include <Windows.h>
#include <NuiApi.h>
#include <opencv2/opencv.hpp>


int _tmain(int argc, _TCHAR* argv[])
{
	cv::setUseOptimized( true );


	INuiSensor* pSensor;
	HRESULT hResult = S_OK;
	hResult = NuiCreateSensorByIndex( 0, &pSensor );
	if( FAILED( hResult ) ){
		std::cerr << "Error : NuiCreateSensorByIndex" << std::endl;
		return -1;
	}

	hResult = pSensor->NuiInitialize( NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX );
	if( FAILED( hResult ) ){
		std::cerr << "Error : NuiInitialize" << std::endl;
		return -1;
	}

	
	HANDLE hColorEvent = INVALID_HANDLE_VALUE;
	HANDLE hColorHandle = INVALID_HANDLE_VALUE;
	hColorEvent = CreateEvent( nullptr, true, false, nullptr );
	hResult = pSensor->NuiImageStreamOpen( NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, 0, 2, hColorEvent, &hColorHandle );
	if( FAILED( hResult ) ){
		std::cerr << "Error : NuiImageStreamOpen( COLOR )" << std::endl;
		return -1;
	}


	HANDLE hDepthPlayerEvent = INVALID_HANDLE_VALUE;
	HANDLE hDepthPlayerHandle = INVALID_HANDLE_VALUE;
	hDepthPlayerEvent = CreateEvent( nullptr, true, false, nullptr );
	hResult = pSensor->NuiImageStreamOpen( NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_640x480, 0, 2, hDepthPlayerEvent, &hDepthPlayerHandle );
	if( FAILED( hResult ) ){
		std::cerr << "Error : NuiImageStreamOpen( DEPTH&PLAYER )" << std::endl;
		return -1;
	}

	HANDLE hEvents[2] = { hColorEvent, hDepthPlayerEvent };

	cv::namedWindow( "Mask" );
	cv::namedWindow( "Clip" );

	
	int iterationErode = 2;
	int iterationDilate = 2;
	cv::createTrackbar( "erode", "Mask", &iterationErode, 10 );
	cv::createTrackbar( "dilate", "Mask", &iterationDilate, 10 );

	while( 1 ){
	
		ResetEvent( hColorEvent );
		ResetEvent( hDepthPlayerEvent );
		WaitForMultipleObjects( ARRAYSIZE( hEvents ), hEvents, true, INFINITE );

		
		NUI_IMAGE_FRAME pColorImageFrame = { 0 };
		hResult = pSensor->NuiImageStreamGetNextFrame( hColorHandle, 0, &pColorImageFrame );
		if( FAILED( hResult ) ){
			std::cerr << "Error : NuiImageStreamGetNextFrame( COLOR )" << std::endl;
			return -1;
		}

	
		NUI_IMAGE_FRAME pDepthPlayerImageFrame = { 0 };
		hResult = pSensor->NuiImageStreamGetNextFrame( hDepthPlayerHandle, 0, &pDepthPlayerImageFrame );
		if( FAILED( hResult ) ){
			std::cerr << "Error : NuiImageStreamGetNextFrame( DEPTH&PLAYER )" << std::endl;
			return -1;
		}

	
		INuiFrameTexture* pColorFrameTexture = pColorImageFrame.pFrameTexture;
		NUI_LOCKED_RECT sColorLockedRect;
		pColorFrameTexture->LockRect( 0, &sColorLockedRect, nullptr, 0 );

		
		INuiFrameTexture* pDepthPlayerFrameTexture = pDepthPlayerImageFrame.pFrameTexture;
		NUI_LOCKED_RECT sDepthPlayerLockedRect;
		pDepthPlayerFrameTexture->LockRect( 0, &sDepthPlayerLockedRect, nullptr, 0 );

		
		cv::Mat colorMat( 480, 640, CV_8UC4, reinterpret_cast<uchar*>( sColorLockedRect.pBits ) );
		LONG registX = 0;
		LONG registY = 0;
		ushort* pBuffer = reinterpret_cast<ushort*>( sDepthPlayerLockedRect.pBits );
		cv::Mat maskMat = cv::Mat::zeros( 480, 640, CV_8UC1 );
		for( int y = 0; y < 480; y++ ){
			for( int x = 0; x < 640; x++ ){
				pSensor->NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution( NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_640x480, nullptr, x, y, *pBuffer, &registX, &registY );
				if( ( registX >= 0 ) && ( registX < 640 ) && ( registY >= 0 ) && ( registY < 480 ) ){
					if( ( *pBuffer & 0x7 ) != 0 ){
						maskMat.at<uchar>( registY, registX ) = 0xff; // 255
					}
				}
				pBuffer++;
			}
		}

		
		// Mathematical Morphology - opening
		cv::erode( maskMat, maskMat, cv::Mat(), cv::Point( -1, -1 ), iterationErode );
		cv::dilate( maskMat, maskMat, cv::Mat(), cv::Point( -1, -1 ), iterationDilate );

		// Mathematical Morphology - cpening
		cv::dilate( maskMat, maskMat, cv::Mat(), cv::Point( -1, -1 ), iterationDilate );
		cv::erode( maskMat, maskMat, cv::Mat(), cv::Point( -1, -1 ), iterationErode );
		
		cv::Mat clipMat = cv::Mat::zeros( 480, 640, CV_8UC4 );
		colorMat.copyTo( clipMat, maskMat );

		cv::imshow( "Mask", maskMat );
		cv::imshow( "Clip", clipMat );

	
		pColorFrameTexture->UnlockRect( 0 );
		pDepthPlayerFrameTexture->UnlockRect( 0 );
		pSensor->NuiImageStreamReleaseFrame( hColorHandle, &pColorImageFrame );
		pSensor->NuiImageStreamReleaseFrame( hDepthPlayerHandle, &pDepthPlayerImageFrame );

	
		if( cv::waitKey( 30 ) == VK_ESCAPE ){
			break;
		}
	}


	pSensor->NuiShutdown();
	CloseHandle( hColorEvent );
	CloseHandle( hDepthPlayerEvent );
	CloseHandle( hColorHandle );
	CloseHandle( hDepthPlayerHandle );

	cv::destroyAllWindows();

	return 0;
}

 

El link de descarga: https://github.com/haruiz/Kinect_Blog

El resultado:

image

image

 

Espero les sea de utilidad para sus proyectos.

 

saludos

Anuncio publicitario

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s