// Returns the number of clean char int FTS_ANPR_Seg::findCleanChar( FTS_ANPR_SegResult& oSegResult, CvCmpFunc is_equal ) { cvClearSeq( m_poSegCharSeq ); // Fill an opencv sequence with chars // -------------------------------------------------------------------- std::list<FTS_ANPR_SegChar*>::iterator i = oSegResult.m_oChars.begin(); std::list<FTS_ANPR_SegChar*>::iterator iE = oSegResult.m_oChars.end(); for( ; i != iE; ++i ) { FTS_ANPR_SegChar* poSegChar = *i; cvSeqPush( m_poSegCharSeq, &poSegChar ); } // Partition into equivalent classes such that all chars in the same class // are the same size and non-overlapping. // -------------------------------------------------------------------- CvSeq* poLabels = 0; int nClassCount = cvSeqPartition( m_poSegCharSeq, 0, &poLabels, is_equal,// FTS_ANPR_Seg::isSameSizeAndNoOverlap, this ); int nCleanCharCount = 0; if( nClassCount < (int) oSegResult.m_oChars.size() ) // means there's at least one class with at least 2 chars in it { // Find the biggest partition. This partition contains all the chars that are // the same size and DO NOT overlap with each other. // -------------------------------------------------------------------- std::vector<int>& oCount = m_oIntVector; // Num chars in each class oCount.clear(); oCount.assign( nClassCount, 0 ); for( int n = 0; n < poLabels->total; ++n ) { int nClassIdx = *(int*) cvGetSeqElem( poLabels, n ); ++oCount.at( nClassIdx ); } int nBiggestClassIdx = std::distance( oCount.begin(), std::max_element( oCount.begin(), oCount.end() ) ); // Mark all chars in the biggest class as clean chars. // -------------------------------------------------------------------- i = oSegResult.m_oChars.begin(); iE = oSegResult.m_oChars.end(); for( unsigned int nIdx = 0; i != iE; ++i, ++nIdx ) { int nClassIdx = *(int*) cvGetSeqElem(poLabels, nIdx); if (nClassIdx == nBiggestClassIdx) { (*i)->m_bClean = true; ++nCleanCharCount; } else { (*i)->m_bClean = false; } } } // if at least one class with more than one char // Release the memory storage of label sequence // -------------------------------------------------------------------- cvClearSeq( poLabels ); cvClearSeq( m_poSegCharSeq ); cvClearMemStorage( m_poStorage ); // clear, don't deallocate return nCleanCharCount; }
void cvFindBlobsByCCClasters(IplImage* pFG, CvBlobSeq* pBlobs, CvMemStorage* storage) { /* Create contours: */ IplImage* pIB = NULL; CvSeq* cnt = NULL; CvSeq* cnt_list = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvSeq*), storage ); CvSeq* clasters = NULL; int claster_cur, claster_num; pIB = cvCloneImage(pFG); cvThreshold(pIB,pIB,128,255,CV_THRESH_BINARY); cvFindContours(pIB,storage, &cnt, sizeof(CvContour), CV_RETR_EXTERNAL); cvReleaseImage(&pIB); /* Create cnt_list. */ /* Process each contour: */ for(; cnt; cnt=cnt->h_next) { cvSeqPush( cnt_list, &cnt); } claster_num = cvSeqPartition( cnt_list, storage, &clasters, CompareContour, NULL ); for(claster_cur=0; claster_cur<claster_num; ++claster_cur) { int cnt_cur; CvBlob NewBlob; double M00,X,Y,XX,YY; /* image moments */ CvMoments m; CvRect rect_res = cvRect(-1,-1,-1,-1); CvMat mat; for(cnt_cur=0; cnt_cur<clasters->total; ++cnt_cur) { CvRect rect; CvSeq* cnt; int k = *(int*)cvGetSeqElem( clasters, cnt_cur ); if(k!=claster_cur) continue; cnt = *(CvSeq**)cvGetSeqElem( cnt_list, cnt_cur ); rect = ((CvContour*)cnt)->rect; if(rect_res.height<0) { rect_res = rect; } else { /* Unite rects: */ int x0,x1,y0,y1; x0 = MIN(rect_res.x,rect.x); y0 = MIN(rect_res.y,rect.y); x1 = MAX(rect_res.x+rect_res.width,rect.x+rect.width); y1 = MAX(rect_res.y+rect_res.height,rect.y+rect.height); rect_res.x = x0; rect_res.y = y0; rect_res.width = x1-x0; rect_res.height = y1-y0; } } if(rect_res.height < 1 || rect_res.width < 1) { X = 0; Y = 0; XX = 0; YY = 0; } else { cvMoments( cvGetSubRect(pFG,&mat,rect_res), &m, 0 ); M00 = cvGetSpatialMoment( &m, 0, 0 ); if(M00 <= 0 ) continue; X = cvGetSpatialMoment( &m, 1, 0 )/M00; Y = cvGetSpatialMoment( &m, 0, 1 )/M00; XX = (cvGetSpatialMoment( &m, 2, 0 )/M00) - X*X; YY = (cvGetSpatialMoment( &m, 0, 2 )/M00) - Y*Y; } NewBlob = cvBlob(rect_res.x+(float)X,rect_res.y+(float)Y,(float)(4*sqrt(XX)),(float)(4*sqrt(YY))); pBlobs->AddBlob(&NewBlob); } /* Next cluster. */ #if 0 { // Debug info: IplImage* pI = cvCreateImage(cvSize(pFG->width,pFG->height),IPL_DEPTH_8U,3); cvZero(pI); for(claster_cur=0; claster_cur<claster_num; ++claster_cur) { int cnt_cur; CvScalar color = CV_RGB(rand()%256,rand()%256,rand()%256); for(cnt_cur=0; cnt_cur<clasters->total; ++cnt_cur) { CvSeq* cnt; int k = *(int*)cvGetSeqElem( clasters, cnt_cur ); if(k!=claster_cur) continue; cnt = *(CvSeq**)cvGetSeqElem( cnt_list, cnt_cur ); cvDrawContours( pI, cnt, color, color, 0, 1, 8); } CvBlob* pB = pBlobs->GetBlob(claster_cur); int x = cvRound(CV_BLOB_RX(pB)), y = cvRound(CV_BLOB_RY(pB)); cvEllipse( pI, cvPointFrom32f(CV_BLOB_CENTER(pB)), cvSize(MAX(1,x), MAX(1,y)), 0, 0, 360, color, 1 ); } cvNamedWindow( "Clusters", 0); cvShowImage( "Clusters",pI ); cvReleaseImage(&pI); } /* Debug info. */ #endif } /* cvFindBlobsByCCClasters */
CvSeq * MBLBPDetectMultiScale( const IplImage* img, MBLBPCascade * pCascade, CvMemStorage* storage, int scale_factor1024x, int min_neighbors, int min_size, int max_size) { IplImage stub; CvMat mat, *pmat; CvSeq* seq = 0; CvSeq* seq2 = 0; CvSeq* idx_seq = 0; CvSeq* result_seq = 0; CvSeq* positions = 0; CvMemStorage* temp_storage = 0; CvAvgComp* comps = 0; CV_FUNCNAME( "MBLBPDetectMultiScale" ); __BEGIN__; int factor1024x; int factor1024x_max; int coi; if( ! pCascade) CV_ERROR( CV_StsNullPtr, "Invalid classifier cascade" ); if( !storage ) CV_ERROR( CV_StsNullPtr, "Null storage pointer" ); CV_CALL( img = cvGetImage( img, &stub)); CV_CALL( pmat = cvGetMat( img, &mat, &coi)); if( coi ) CV_ERROR( CV_BadCOI, "COI is not supported" ); if( CV_MAT_DEPTH(pmat->type) != CV_8U ) CV_ERROR( CV_StsUnsupportedFormat, "Only 8-bit images are supported" ); if( CV_MAT_CN(pmat->type) > 1 ) CV_ERROR( CV_StsUnsupportedFormat, "Only single-channel images are supported" ); min_size = MAX(pCascade->win_width, min_size); if(max_size <=0 ) max_size = MIN(img->width, img->height); if(max_size < min_size) return NULL; CV_CALL( temp_storage = cvCreateChildMemStorage( storage )); seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvRect), temp_storage ); seq2 = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), temp_storage ); result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvAvgComp), storage ); positions = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), temp_storage ); if( min_neighbors == 0 ) seq = result_seq; factor1024x = ((min_size<<10)+(pCascade->win_width/2)) / pCascade->win_width; factor1024x_max = (max_size<<10) / pCascade->win_width; //do not round it, to avoid the scan window be out of range #ifdef _OPENMP omp_init_lock(&lock); #endif for( ; factor1024x <= factor1024x_max; factor1024x = ((factor1024x*scale_factor1024x+512)>>10) ) { IplImage * pSmallImage = cvCreateImage( cvSize( ((img->width<<10)+factor1024x/2)/factor1024x, ((img->height<<10)+factor1024x/2)/factor1024x), IPL_DEPTH_8U, 1); try{ cvResize(img, pSmallImage); } catch(...) { cvReleaseImage(&pSmallImage); return NULL; } CvSize winStride = cvSize( (factor1024x<=2048)+1, (factor1024x<=2048)+1 ); cvClearSeq(positions); MBLBPDetectSingleScale( pSmallImage, pCascade, positions, winStride); for(int i=0; i < (positions ? positions->total : 0); i++) { CvPoint pt = *(CvPoint*)cvGetSeqElem( positions, i ); CvRect r = cvRect( (pt.x * factor1024x + 512)>>10, (pt.y * factor1024x + 512)>>10, (pCascade->win_width * factor1024x + 512)>>10, (pCascade->win_height * factor1024x + 512)>>10); cvSeqPush(seq, &r); } cvReleaseImage(&pSmallImage); } #ifdef _OPENMP omp_destroy_lock(&lock); #endif if( min_neighbors != 0 ) { // group retrieved rectangles in order to filter out noise int ncomp = cvSeqPartition( seq, 0, &idx_seq, (CvCmpFunc)is_equal, 0 ); CV_CALL( comps = (CvAvgComp*)cvAlloc( (ncomp+1)*sizeof(comps[0]))); memset( comps, 0, (ncomp+1)*sizeof(comps[0])); // count number of neighbors for(int i = 0; i < seq->total; i++ ) { CvRect r1 = *(CvRect*)cvGetSeqElem( seq, i ); int idx = *(int*)cvGetSeqElem( idx_seq, i ); assert( (unsigned)idx < (unsigned)ncomp ); comps[idx].neighbors++; comps[idx].rect.x += r1.x; comps[idx].rect.y += r1.y; comps[idx].rect.width += r1.width; comps[idx].rect.height += r1.height; } // calculate average bounding box for(int i = 0; i < ncomp; i++ ) { int n = comps[i].neighbors; if( n >= min_neighbors ) { CvAvgComp comp; comp.rect.x = (comps[i].rect.x*2 + n)/(2*n); comp.rect.y = (comps[i].rect.y*2 + n)/(2*n); comp.rect.width = (comps[i].rect.width*2 + n)/(2*n); comp.rect.height = (comps[i].rect.height*2 + n)/(2*n); comp.neighbors = comps[i].neighbors; cvSeqPush( seq2, &comp ); } } // filter out small face rectangles inside large face rectangles for(int i = 0; i < seq2->total; i++ ) { CvAvgComp r1 = *(CvAvgComp*)cvGetSeqElem( seq2, i ); int j, flag = 1; for( j = 0; j < seq2->total; j++ ) { CvAvgComp r2 = *(CvAvgComp*)cvGetSeqElem( seq2, j ); int distance = (r2.rect.width *2+5)/10;//cvRound( r2.rect.width * 0.2 ); if( i != j && r1.rect.x >= r2.rect.x - distance && r1.rect.y >= r2.rect.y - distance && r1.rect.x + r1.rect.width <= r2.rect.x + r2.rect.width + distance && r1.rect.y + r1.rect.height <= r2.rect.y + r2.rect.height + distance && (r2.neighbors > MAX( 3, r1.neighbors ) || r1.neighbors < 3) ) { flag = 0; break; } } if( flag ) { cvSeqPush( result_seq, &r1 ); /* cvSeqPush( result_seq, &r1.rect ); */ } } } __END__; cvReleaseMemStorage( &temp_storage ); cvFree( &comps ); return result_seq; }