Reconocimiento de patrones en Android con OpenCV - dEIC

Transcripción

Reconocimiento de patrones en Android con OpenCV - dEIC
Reconocimiento de patrones
en Android con OpenCV
Rubén Serrano
1.Introducción
2.Herramientas de desarrollo
3.Proyecto
1.Código Android SDK
2.Código Android NDK
3.Código OpenCV
Introducción

Formas de trabajar con OpenCV

Java API

Librerías nativas (C/C++)
Herramientas...

... que vamos a utilizar hoy

Eclipse
http://www.eclipse.org/downloads/

Android SDK
http://developer.android.com/sdk/index.html

Android NDK
http://developer.android.com/sdk/ndk/index.html

OpenCV
http://opencv.willowgarage.com/wiki/InstallGuide
Herramientas

Compilación de OpenCV para Android

Linux i Windows
http://opencv.willowgarage.com/wiki/AndroidTrunk

”el Unix de la manzana”

El enlace anterior, y
whichlight.com/blog
Proyecto


App en el Android Market

Buscar: ”Demo Reconocimiento Patrones”

https://market.android.com/details?id=org.cvc.gtugbcn.patrec
Proyecto base para Eclipse
http://deic.uab.cat/~rserrano/android/proyecto.tar.gz

Estas transparencias
http://deic.uab.cat/~rserrano/android/patternrecog.pdf
Código Android SDK

Añadir llamadas a código nativo

En la clase SampleView
public native long ObtainPattern(int width, int height, byte yuv[], int[] rgba);
public native void FindPattern(long processor, int width, int height, byte yuv[], int[] rgba);
static
{
System.loadLibrary("pattern_recognition");
}

En processFrame, en el switch
case MainActivity.PATTERN_RECORD:
mProcessor = ObtainPattern(getFrameWidth(), getFrameHeight(), data, rgba);
MainActivity.mProcessMode = MainActivity.VIDEO_MODE;
break;
case MainActivity.INSPECTION_MODE:
FindPattern(mProcessor, getFrameWidth(), getFrameHeight(), data, rgba);
break;
Código JNI / OpenCV

Método ObtainPattern
jbyte* _yuv = env->GetByteArrayElements(yuv, 0);
jint* _bgra = env->GetIntArrayElements(bgra, 0);
Mat matGray(height, width, CV_8UC1, (unsigned char *)_yuv);
Mat myuv(height + height/2, width, CV_8UC1, (unsigned char *)_yuv);
Mat mbgra(height, width, CV_8UC4, (unsigned char *)_bgra);
Processor* processor = new Processor();
processor->obtainPattern(matGray);
drawText(mbgra, "Patron adquirido");
return (long)processor;
env->ReleaseIntArrayElements(bgra, _bgra, 0);
env->ReleaseByteArrayElements(yuv, _yuv, 0);
Código OpenCV (Patrón)

Constructor de Processor
storage = cvCreateMemStorage(0);
params = cvSURFParams(500, 1);

Función obtainPattern()
objectKeypoints = 0;
objectDescriptors = 0;
cvExtractSURF( &(static_cast<IplImage>(imgMat)), 0, &objectKeypoints, &objectDescriptors, storage, params );
Código JNI / OpenCV

Método FindPattern
jbyte* _yuv = env->GetByteArrayElements(yuv, 0);
jint* _bgra = env->GetIntArrayElements(bgra, 0);
Mat matGray(height, width, CV_8UC1, (unsigned char *)_yuv);
Mat myuv(height + height/2, width, CV_8UC1, (unsigned char *)_yuv);
Mat mbgra(height, width, CV_8UC4, (unsigned char *)_bgra);
//Please make attention about BGRA byte order
//ARGB stored in java as int array becomes BGRA at native level
cvtColor(myuv, mbgra, CV_YUV420sp2BGR, 4);
Processor* processor = (Processor*) pProcessor;
processor->detectAndDrawFeatures(mbgra, matGray);
env->ReleaseIntArrayElements(bgra, _bgra, 0);
env->ReleaseByteArrayElements(yuv, _yuv, 0);
Código OpenCV
Función detectAndDrawFeatures()

IplImage img = greyMat;
int i;
imageKeypoints = 0;
imageDescriptors = 0;
cvExtractSURF( &img, 0, &imageKeypoints, &imageDescriptors, storage, params );
CvPoint src_corners[4] = {{0,0}, {img.width,0}, {img.width, img.height}, {0, img.height}};
CvPoint dst_corners[4];
if( locatePlanarObject( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, src_corners, dst_corners ))
{
for( i = 0; i < 4; i++ )
{
CvPoint r1 = dst_corners[i%4];
CvPoint r2 = dst_corners[(i+1)%4];
line(imgMat, cvPoint(r1.x, r1.y), cvPoint(r2.x, r2.y), CV_RGB(0, 0, 0), 6, CV_AA);
}
drawText(imgMat, "Found ya!");
}
Código OpenCV

Función locatePlanarObject()
double h[9];
CvMat _h = cvMat(3, 3, CV_64F, h);
vector<int> ptpairs;
vector<CvPoint2D32f> pt1, pt2;
CvMat _pt1, _pt2;
int i, n;
flannFindPairs(objectDescriptors, imageDescriptors, ptpairs );
n = (int)(ptpairs.size()/2);
if( n < 4 )
return 0;
pt1.resize(n);
pt2.resize(n);
for( i = 0; i < n; i++ )
{
pt1[i] = ((CvSURFPoint*)cvGetSeqElem(objectKeypoints,ptpairs[i*2]))->pt;
pt2[i] = ((CvSURFPoint*)cvGetSeqElem(imageKeypoints,ptpairs[i*2+1]))->pt;
}
Código OpenCV
_pt1 = cvMat(1, n, CV_32FC2, &pt1[0] );
_pt2 = cvMat(1, n, CV_32FC2, &pt2[0] );
if( !cvFindHomography( &_pt1, &_pt2, &_h, CV_RANSAC, 5 ))
return 0;
for( i = 0; i < 4; i++ )
{
double x = src_corners[i].x, y = src_corners[i].y;
double Z = 1./(h[6]*x + h[7]*y + h[8]);
double X = (h[0]*x + h[1]*y + h[2])*Z;
double Y = (h[3]*x + h[4]*y + h[5])*Z;
dst_corners[i] = cvPoint(cvRound(X), cvRound(Y));
}
return 1;
Código OpenCV

Función flannFindPairs()
int length = (int)(objectDescriptors->elem_size/sizeof(float));
Mat m_object(objectDescriptors->total, length, CV_32F);
Mat m_image(imageDescriptors->total, length, CV_32F);
// copy descriptors
CvSeqReader obj_reader;
float* obj_ptr = m_object.ptr<float>(0);
cvStartReadSeq( objectDescriptors, &obj_reader );
for(int i = 0; i < objectDescriptors->total; i++ )
{
const float* descriptor = (const float*)obj_reader.ptr;
CV_NEXT_SEQ_ELEM( obj_reader.seq->elem_size, obj_reader );
memcpy(obj_ptr, descriptor, length*sizeof(float));
obj_ptr += length;
}
CvSeqReader img_reader;
float* img_ptr = m_image.ptr<float>(0);
cvStartReadSeq( imageDescriptors, &img_reader );
for(int i = 0; i < imageDescriptors->total; i++ )
{
const float* descriptor = (const float*)img_reader.ptr;
CV_NEXT_SEQ_ELEM( img_reader.seq->elem_size, img_reader );
memcpy(img_ptr, descriptor, length*sizeof(float));
img_ptr += length;
}
Código OpenCV
// find nearest neighbors using FLANN
Mat m_indices(objectDescriptors->total, 2, CV_32S);
Mat m_dists(objectDescriptors->total, 2, CV_32F);
flann::Index flann_index(m_image, flann::KDTreeIndexParams(4)); // using 4 randomized kdtrees
flann_index.knnSearch(m_object, m_indices, m_dists, 2, flann::SearchParams(64) ); // maximum number of leafs checked
int* indices_ptr = m_indices.ptr<int>(0);
float* dists_ptr = m_dists.ptr<float>(0);
for (int i=0;i<m_indices.rows;++i) {
if (dists_ptr[2*i]<0.6*dists_ptr[2*i+1]) {
ptpairs.push_back(i);
ptpairs.push_back(indices_ptr[2*i]);
}
}
APM?
¡Muchas gracias por vuestra atención!

Documentos relacionados