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!