static void cvTsMHIGradient( const CvMat* mhi, CvMat* mask, CvMat* orientation, double delta1, double delta2, int aperture_size ) { CvPoint anchor = { aperture_size/2, aperture_size/2 }; CvMat* src = cvCreateMat( mhi->rows + aperture_size - 1, mhi->cols + aperture_size - 1, CV_32FC1 ); CvMat* kernel = cvCreateMat( aperture_size, aperture_size, CV_32FC1 ); CvMat* dx = cvCreateMat( mhi->rows, mhi->cols, CV_32FC1 ); CvMat* dy = cvCreateMat( mhi->rows, mhi->cols, CV_32FC1 ); CvMat* min_mhi = cvCreateMat( mhi->rows, mhi->cols, CV_32FC1 ); CvMat* max_mhi = cvCreateMat( mhi->rows, mhi->cols, CV_32FC1 ); IplConvKernel* element = cvCreateStructuringElementEx( aperture_size, aperture_size, aperture_size/2, aperture_size/2, CV_SHAPE_RECT ); int i, j; double limit = 1e-4*aperture_size*aperture_size; cvTsPrepareToFilter( mhi, src, anchor ); cvTsCalcSobelKernel2D( 1, 0, aperture_size, 0, kernel ); cvTsConvolve2D( src, dx, kernel, anchor ); cvTsCalcSobelKernel2D( 0, 1, aperture_size, 0, kernel ); cvTsConvolve2D( src, dy, kernel, anchor ); cvReleaseMat( &kernel ); cvTsMinMaxFilter( src, min_mhi, element, CV_TS_MIN ); cvTsMinMaxFilter( src, max_mhi, element, CV_TS_MAX ); cvReleaseStructuringElement( &element ); if( delta1 > delta2 ) { double t; CV_SWAP( delta1, delta2, t ); } for( i = 0; i < mhi->rows; i++ ) { uchar* mask_row = mask->data.ptr + i*mask->step; float* orient_row = (float*)(orientation->data.ptr + i*orientation->step); const float* dx_row = (float*)(dx->data.ptr + i*dx->step); const float* dy_row = (float*)(dy->data.ptr + i*dy->step); const float* min_row = (float*)(min_mhi->data.ptr + i*min_mhi->step); const float* max_row = (float*)(max_mhi->data.ptr + i*max_mhi->step); for( j = 0; j < mhi->cols; j++ ) { double delta = max_row[j] - min_row[j]; double _dx = dx_row[j], _dy = dy_row[j]; if( delta1 <= delta && delta <= delta2 && (fabs(_dx) > limit || fabs(_dy) > limit) ) { mask_row[j] = 1; double angle = atan2( _dy, _dx ) * (180/CV_PI); if( angle < 0 ) angle += 360.; orient_row[j] = (float)angle; } else { mask_row[j] = 0; orient_row[j] = 0.f; } } } cvReleaseMat( &dx ); cvReleaseMat( &dy ); cvReleaseMat( &min_mhi ); cvReleaseMat( &max_mhi ); }
static void icvTsCanny( const CvMat* src, CvMat* dst, double threshold1, double threshold2, int aperture_size, int use_true_gradient ) { int m = aperture_size; CvMat* _src = cvCreateMat( src->rows + m - 1, src->cols + m - 1, CV_16S ); CvMat* dx = cvCreateMat( src->rows, src->cols, CV_16S ); CvMat* dy = cvCreateMat( src->rows, src->cols, CV_16S ); CvMat* kernel = cvCreateMat( m, m, CV_32F ); CvPoint anchor = {m/2, m/2}; CvMat* mag = cvCreateMat( src->rows, src->cols, CV_32F ); const double tan_pi_8 = tan(CV_PI/8.); const double tan_3pi_8 = tan(CV_PI*3/8); float lowThreshold = (float)MIN(threshold1, threshold2); float highThreshold = (float)MAX(threshold1, threshold2); int x, y, width = src->cols, height = src->rows; cvTsConvert( src, dx ); cvTsPrepareToFilter( dx, _src, anchor, CV_TS_BORDER_REPLICATE ); cvTsCalcSobelKernel2D( 1, 0, m, 0, kernel ); cvTsConvolve2D( _src, dx, kernel, anchor ); cvTsCalcSobelKernel2D( 0, 1, m, 0, kernel ); cvTsConvolve2D( _src, dy, kernel, anchor ); /* estimate magnitude and angle */ for( y = 0; y < height; y++ ) { const short* _dx = (short*)(dx->data.ptr + dx->step*y); const short* _dy = (short*)(dy->data.ptr + dy->step*y); float* _mag = (float*)(mag->data.ptr + mag->step*y); for( x = 0; x < width; x++ ) { float mval = use_true_gradient ? (float)sqrt((double)(_dx[x]*_dx[x] + _dy[x]*_dy[x])) : (float)(abs(_dx[x]) + abs(_dy[x])); _mag[x] = mval; } } /* nonmaxima suppression */ for( y = 0; y < height; y++ ) { const short* _dx = (short*)(dx->data.ptr + dx->step*y); const short* _dy = (short*)(dy->data.ptr + dy->step*y); float* _mag = (float*)(mag->data.ptr + mag->step*y); for( x = 0; x < width; x++ ) { int y1 = 0, y2 = 0, x1 = 0, x2 = 0; double tg; float a = _mag[x], b = 0, c = 0; if( a <= lowThreshold ) continue; if( _dx[x] ) tg = (double)_dy[x]/_dx[x]; else tg = DBL_MAX*CV_SIGN(_dy[x]); if( fabs(tg) < tan_pi_8 ) { y1 = y2 = y; x1 = x + 1; x2 = x - 1; } else if( tan_pi_8 <= tg && tg <= tan_3pi_8 ) { y1 = y + 1; y2 = y - 1; x1 = x + 1; x2 = x - 1; } else if( -tan_3pi_8 <= tg && tg <= -tan_pi_8 ) { y1 = y - 1; y2 = y + 1; x1 = x + 1; x2 = x - 1; } else { assert( fabs(tg) > tan_3pi_8 ); x1 = x2 = x; y1 = y + 1; y2 = y - 1; } if( (unsigned)y1 < (unsigned)height && (unsigned)x1 < (unsigned)width ) b = (float)fabs((double)mag->data.fl[y1*width+x1]); if( (unsigned)y2 < (unsigned)height && (unsigned)x2 < (unsigned)width ) c = (float)fabs((double)mag->data.fl[y2*width+x2]); if( (a > b || (a == b && ((x1 == x+1 && y1 == y) || (x1 == x && y1 == y+1)))) && a > c ) ; else _mag[x] = -a; } } cvTsZero( dst ); /* hysteresis threshold */ for( y = 0; y < height; y++ ) { const float* _mag = (float*)(mag->data.ptr + mag->step*y); uchar* _dst = dst->data.ptr + dst->step*y; for( x = 0; x < width; x++ ) if( _mag[x] > highThreshold && !_dst[x] ) icvTsCannyFollow( x, y, lowThreshold, mag, dst ); } cvReleaseMat( &_src ); cvReleaseMat( &dx ); cvReleaseMat( &dy ); cvReleaseMat( &kernel ); cvReleaseMat( &mag ); }