1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of Intel Corporation may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 42 #include "_cv.h" 43 44 IPCVAPI_IMPL( CvStatus, icvUpdateMotionHistory_8u32f_C1IR, 45 (const uchar * silIm, int silStep, float *mhiIm, int mhiStep, 46 CvSize size, float timestamp, float mhi_duration), 47 (silIm, silStep, mhiIm, mhiStep, size, timestamp, mhi_duration) ) 48 { 49 int x, y; 50 51 /* function processes floating-point images using integer arithmetics */ 52 Cv32suf v; 53 int ts, delbound; 54 int *mhi = (int *) mhiIm; 55 56 v.f = timestamp; 57 ts = v.i; 58 59 if( !silIm || !mhiIm ) 60 return CV_NULLPTR_ERR; 61 62 if( size.height <= 0 || size.width <= 0 || 63 silStep < size.width || mhiStep < size.width * CV_SIZEOF_FLOAT || 64 (mhiStep & (CV_SIZEOF_FLOAT - 1)) != 0 ) 65 return CV_BADSIZE_ERR; 66 67 if( mhi_duration < 0 ) 68 return CV_BADFACTOR_ERR; 69 70 mhi_duration = timestamp - mhi_duration; 71 72 v.f = mhi_duration; 73 delbound = CV_TOGGLE_FLT( v.i ); 74 75 mhiStep /= sizeof(mhi[0]); 76 77 if( mhiStep == size.width && silStep == size.width ) 78 { 79 size.width *= size.height; 80 size.height = 1; 81 } 82 83 if( delbound > 0 ) 84 for( y = 0; y < size.height; y++, silIm += silStep, mhi += mhiStep ) 85 for( x = 0; x < size.width; x++ ) 86 { 87 int val = mhi[x]; 88 89 /* val = silIm[x] ? ts : val < delbound ? 0 : val; */ 90 val &= (val < delbound) - 1; 91 val ^= (ts ^ val) & ((silIm[x] == 0) - 1); 92 mhi[x] = val; 93 } 94 else 95 for( y = 0; y < size.height; y++, silIm += silStep, mhi += mhiStep ) 96 for( x = 0; x < size.width; x++ ) 97 { 98 int val = mhi[x]; 99 100 /* val = silIm[x] ? ts : val < delbound ? 0 : val; */ 101 val &= (CV_TOGGLE_FLT( val ) < delbound) - 1; 102 val ^= (ts ^ val) & ((silIm[x] == 0) - 1); 103 mhi[x] = val; 104 } 105 106 return CV_OK; 107 } 108 109 110 /* motion templates */ 111 CV_IMPL void 112 cvUpdateMotionHistory( const void* silhouette, void* mhimg, 113 double timestamp, double mhi_duration ) 114 { 115 CvSize size; 116 CvMat silhstub, *silh = (CvMat*)silhouette; 117 CvMat mhistub, *mhi = (CvMat*)mhimg; 118 int mhi_step, silh_step; 119 120 CV_FUNCNAME( "cvUpdateMHIByTime" ); 121 122 __BEGIN__; 123 124 CV_CALL( silh = cvGetMat( silh, &silhstub )); 125 CV_CALL( mhi = cvGetMat( mhi, &mhistub )); 126 127 if( !CV_IS_MASK_ARR( silh )) 128 CV_ERROR( CV_StsBadMask, "" ); 129 130 if( CV_MAT_CN( mhi->type ) > 1 ) 131 CV_ERROR( CV_BadNumChannels, "" ); 132 133 if( CV_MAT_DEPTH( mhi->type ) != CV_32F ) 134 CV_ERROR( CV_BadDepth, "" ); 135 136 if( !CV_ARE_SIZES_EQ( mhi, silh )) 137 CV_ERROR( CV_StsUnmatchedSizes, "" ); 138 139 size = cvGetMatSize( mhi ); 140 141 mhi_step = mhi->step; 142 silh_step = silh->step; 143 144 if( CV_IS_MAT_CONT( mhi->type & silh->type )) 145 { 146 size.width *= size.height; 147 mhi_step = silh_step = CV_STUB_STEP; 148 size.height = 1; 149 } 150 151 IPPI_CALL( icvUpdateMotionHistory_8u32f_C1IR( (const uchar*)(silh->data.ptr), silh_step, 152 mhi->data.fl, mhi_step, size, 153 (float)timestamp, (float)mhi_duration )); 154 __END__; 155 } 156 157 158 CV_IMPL void 159 cvCalcMotionGradient( const CvArr* mhiimg, CvArr* maskimg, 160 CvArr* orientation, 161 double delta1, double delta2, 162 int aperture_size ) 163 { 164 CvMat *dX_min = 0, *dY_max = 0; 165 IplConvKernel* el = 0; 166 167 CV_FUNCNAME( "cvCalcMotionGradient" ); 168 169 __BEGIN__; 170 171 CvMat mhistub, *mhi = (CvMat*)mhiimg; 172 CvMat maskstub, *mask = (CvMat*)maskimg; 173 CvMat orientstub, *orient = (CvMat*)orientation; 174 CvMat dX_min_row, dY_max_row, orient_row, mask_row; 175 CvSize size; 176 int x, y; 177 178 float gradient_epsilon = 1e-4f * aperture_size * aperture_size; 179 float min_delta, max_delta; 180 181 CV_CALL( mhi = cvGetMat( mhi, &mhistub )); 182 CV_CALL( mask = cvGetMat( mask, &maskstub )); 183 CV_CALL( orient = cvGetMat( orient, &orientstub )); 184 185 if( !CV_IS_MASK_ARR( mask )) 186 CV_ERROR( CV_StsBadMask, "" ); 187 188 if( aperture_size < 3 || aperture_size > 7 || (aperture_size & 1) == 0 ) 189 CV_ERROR( CV_StsOutOfRange, "aperture_size must be 3, 5 or 7" ); 190 191 if( delta1 <= 0 || delta2 <= 0 ) 192 CV_ERROR( CV_StsOutOfRange, "both delta's must be positive" ); 193 194 if( CV_MAT_TYPE( mhi->type ) != CV_32FC1 || CV_MAT_TYPE( orient->type ) != CV_32FC1 ) 195 CV_ERROR( CV_StsUnsupportedFormat, 196 "MHI and orientation must be single-channel floating-point images" ); 197 198 if( !CV_ARE_SIZES_EQ( mhi, mask ) || !CV_ARE_SIZES_EQ( orient, mhi )) 199 CV_ERROR( CV_StsUnmatchedSizes, "" ); 200 201 if( orient->data.ptr == mhi->data.ptr ) 202 CV_ERROR( CV_StsInplaceNotSupported, "orientation image must be different from MHI" ); 203 204 if( delta1 > delta2 ) 205 { 206 double t; 207 CV_SWAP( delta1, delta2, t ); 208 } 209 210 size = cvGetMatSize( mhi ); 211 min_delta = (float)delta1; 212 max_delta = (float)delta2; 213 CV_CALL( dX_min = cvCreateMat( mhi->rows, mhi->cols, CV_32F )); 214 CV_CALL( dY_max = cvCreateMat( mhi->rows, mhi->cols, CV_32F )); 215 216 /* calc Dx and Dy */ 217 CV_CALL( cvSobel( mhi, dX_min, 1, 0, aperture_size )); 218 CV_CALL( cvSobel( mhi, dY_max, 0, 1, aperture_size )); 219 cvGetRow( dX_min, &dX_min_row, 0 ); 220 cvGetRow( dY_max, &dY_max_row, 0 ); 221 cvGetRow( orient, &orient_row, 0 ); 222 cvGetRow( mask, &mask_row, 0 ); 223 224 /* calc gradient */ 225 for( y = 0; y < size.height; y++ ) 226 { 227 dX_min_row.data.ptr = dX_min->data.ptr + y*dX_min->step; 228 dY_max_row.data.ptr = dY_max->data.ptr + y*dY_max->step; 229 orient_row.data.ptr = orient->data.ptr + y*orient->step; 230 mask_row.data.ptr = mask->data.ptr + y*mask->step; 231 cvCartToPolar( &dX_min_row, &dY_max_row, 0, &orient_row, 1 ); 232 233 /* make orientation zero where the gradient is very small */ 234 for( x = 0; x < size.width; x++ ) 235 { 236 float dY = dY_max_row.data.fl[x]; 237 float dX = dX_min_row.data.fl[x]; 238 239 if( fabs(dX) < gradient_epsilon && fabs(dY) < gradient_epsilon ) 240 { 241 mask_row.data.ptr[x] = 0; 242 orient_row.data.i[x] = 0; 243 } 244 else 245 mask_row.data.ptr[x] = 1; 246 } 247 } 248 249 CV_CALL( el = cvCreateStructuringElementEx( aperture_size, aperture_size, 250 aperture_size/2, aperture_size/2, CV_SHAPE_RECT )); 251 cvErode( mhi, dX_min, el ); 252 cvDilate( mhi, dY_max, el ); 253 254 /* mask off pixels which have little motion difference in their neighborhood */ 255 for( y = 0; y < size.height; y++ ) 256 { 257 dX_min_row.data.ptr = dX_min->data.ptr + y*dX_min->step; 258 dY_max_row.data.ptr = dY_max->data.ptr + y*dY_max->step; 259 mask_row.data.ptr = mask->data.ptr + y*mask->step; 260 orient_row.data.ptr = orient->data.ptr + y*orient->step; 261 262 for( x = 0; x < size.width; x++ ) 263 { 264 float d0 = dY_max_row.data.fl[x] - dX_min_row.data.fl[x]; 265 266 if( mask_row.data.ptr[x] == 0 || d0 < min_delta || max_delta < d0 ) 267 { 268 mask_row.data.ptr[x] = 0; 269 orient_row.data.i[x] = 0; 270 } 271 } 272 } 273 274 __END__; 275 276 cvReleaseMat( &dX_min ); 277 cvReleaseMat( &dY_max ); 278 cvReleaseStructuringElement( &el ); 279 } 280 281 282 CV_IMPL double 283 cvCalcGlobalOrientation( const void* orientation, const void* maskimg, const void* mhiimg, 284 double curr_mhi_timestamp, double mhi_duration ) 285 { 286 double angle = 0; 287 int hist_size = 12; 288 CvHistogram* hist = 0; 289 290 CV_FUNCNAME( "cvCalcGlobalOrientation" ); 291 292 __BEGIN__; 293 294 CvMat mhistub, *mhi = (CvMat*)mhiimg; 295 CvMat maskstub, *mask = (CvMat*)maskimg; 296 CvMat orientstub, *orient = (CvMat*)orientation; 297 void* _orient; 298 float _ranges[] = { 0, 360 }; 299 float* ranges = _ranges; 300 int base_orient; 301 double shift_orient = 0, shift_weight = 0, fbase_orient; 302 double a, b; 303 float delbound; 304 CvMat mhi_row, mask_row, orient_row; 305 int x, y, mhi_rows, mhi_cols; 306 307 CV_CALL( mhi = cvGetMat( mhi, &mhistub )); 308 CV_CALL( mask = cvGetMat( mask, &maskstub )); 309 CV_CALL( orient = cvGetMat( orient, &orientstub )); 310 311 if( !CV_IS_MASK_ARR( mask )) 312 CV_ERROR( CV_StsBadMask, "" ); 313 314 if( CV_MAT_TYPE( mhi->type ) != CV_32FC1 || CV_MAT_TYPE( orient->type ) != CV_32FC1 ) 315 CV_ERROR( CV_StsUnsupportedFormat, 316 "MHI and orientation must be single-channel floating-point images" ); 317 318 if( !CV_ARE_SIZES_EQ( mhi, mask ) || !CV_ARE_SIZES_EQ( orient, mhi )) 319 CV_ERROR( CV_StsUnmatchedSizes, "" ); 320 321 if( mhi_duration <= 0 ) 322 CV_ERROR( CV_StsOutOfRange, "MHI duration must be positive" ); 323 324 if( orient->data.ptr == mhi->data.ptr ) 325 CV_ERROR( CV_StsInplaceNotSupported, "orientation image must be different from MHI" ); 326 327 // calculate histogram of different orientation values 328 CV_CALL( hist = cvCreateHist( 1, &hist_size, CV_HIST_ARRAY, &ranges )); 329 _orient = orient; 330 cvCalcArrHist( &_orient, hist, 0, mask ); 331 332 // find the maximum index (the dominant orientation) 333 cvGetMinMaxHistValue( hist, 0, 0, 0, &base_orient ); 334 base_orient *= 360/hist_size; 335 336 // override timestamp with the maximum value in MHI 337 cvMinMaxLoc( mhi, 0, &curr_mhi_timestamp, 0, 0, mask ); 338 339 // find the shift relative to the dominant orientation as weighted sum of relative angles 340 a = 254. / 255. / mhi_duration; 341 b = 1. - curr_mhi_timestamp * a; 342 fbase_orient = base_orient; 343 delbound = (float)(curr_mhi_timestamp - mhi_duration); 344 mhi_rows = mhi->rows; 345 mhi_cols = mhi->cols; 346 347 if( CV_IS_MAT_CONT( mhi->type & mask->type & orient->type )) 348 { 349 mhi_cols *= mhi_rows; 350 mhi_rows = 1; 351 } 352 353 cvGetRow( mhi, &mhi_row, 0 ); 354 cvGetRow( mask, &mask_row, 0 ); 355 cvGetRow( orient, &orient_row, 0 ); 356 357 /* 358 a = 254/(255*dt) 359 b = 1 - t*a = 1 - 254*t/(255*dur) = 360 (255*dt - 254*t)/(255*dt) = 361 (dt - (t - dt)*254)/(255*dt); 362 -------------------------------------------------------- 363 ax + b = 254*x/(255*dt) + (dt - (t - dt)*254)/(255*dt) = 364 (254*x + dt - (t - dt)*254)/(255*dt) = 365 ((x - (t - dt))*254 + dt)/(255*dt) = 366 (((x - (t - dt))/dt)*254 + 1)/255 = (((x - low_time)/dt)*254 + 1)/255 367 */ 368 for( y = 0; y < mhi_rows; y++ ) 369 { 370 mhi_row.data.ptr = mhi->data.ptr + mhi->step*y; 371 mask_row.data.ptr = mask->data.ptr + mask->step*y; 372 orient_row.data.ptr = orient->data.ptr + orient->step*y; 373 374 for( x = 0; x < mhi_cols; x++ ) 375 if( mask_row.data.ptr[x] != 0 && mhi_row.data.fl[x] > delbound ) 376 { 377 /* 378 orient in 0..360, base_orient in 0..360 379 -> (rel_angle = orient - base_orient) in -360..360. 380 rel_angle is translated to -180..180 381 */ 382 double weight = mhi_row.data.fl[x] * a + b; 383 int rel_angle = cvRound( orient_row.data.fl[x] - fbase_orient ); 384 385 rel_angle += (rel_angle < -180 ? 360 : 0); 386 rel_angle += (rel_angle > 180 ? -360 : 0); 387 388 if( abs(rel_angle) < 90 ) 389 { 390 shift_orient += weight * rel_angle; 391 shift_weight += weight; 392 } 393 } 394 } 395 396 // add the dominant orientation and the relative shift 397 if( shift_weight == 0 ) 398 shift_weight = 0.01; 399 400 base_orient = base_orient + cvRound( shift_orient / shift_weight ); 401 base_orient -= (base_orient < 360 ? 0 : 360); 402 base_orient += (base_orient >= 0 ? 0 : 360); 403 404 angle = base_orient; 405 406 __END__; 407 408 cvReleaseHist( &hist ); 409 return angle; 410 } 411 412 413 CV_IMPL CvSeq* 414 cvSegmentMotion( const CvArr* mhiimg, CvArr* segmask, CvMemStorage* storage, 415 double timestamp, double seg_thresh ) 416 { 417 CvSeq* components = 0; 418 CvMat* mask8u = 0; 419 420 CV_FUNCNAME( "cvSegmentMotion" ); 421 422 __BEGIN__; 423 424 CvMat mhistub, *mhi = (CvMat*)mhiimg; 425 CvMat maskstub, *mask = (CvMat*)segmask; 426 Cv32suf v, comp_idx; 427 int stub_val, ts; 428 int x, y; 429 430 if( !storage ) 431 CV_ERROR( CV_StsNullPtr, "NULL memory storage" ); 432 433 CV_CALL( mhi = cvGetMat( mhi, &mhistub )); 434 CV_CALL( mask = cvGetMat( mask, &maskstub )); 435 436 if( CV_MAT_TYPE( mhi->type ) != CV_32FC1 || CV_MAT_TYPE( mask->type ) != CV_32FC1 ) 437 CV_ERROR( CV_BadDepth, "Both MHI and the destination mask" ); 438 439 if( !CV_ARE_SIZES_EQ( mhi, mask )) 440 CV_ERROR( CV_StsUnmatchedSizes, "" ); 441 442 CV_CALL( mask8u = cvCreateMat( mhi->rows + 2, mhi->cols + 2, CV_8UC1 )); 443 cvZero( mask8u ); 444 cvZero( mask ); 445 CV_CALL( components = cvCreateSeq( CV_SEQ_KIND_GENERIC, sizeof(CvSeq), 446 sizeof(CvConnectedComp), storage )); 447 448 v.f = (float)timestamp; ts = v.i; 449 v.f = FLT_MAX*0.1f; stub_val = v.i; 450 comp_idx.f = 1; 451 452 for( y = 0; y < mhi->rows; y++ ) 453 { 454 int* mhi_row = (int*)(mhi->data.ptr + y*mhi->step); 455 for( x = 0; x < mhi->cols; x++ ) 456 { 457 if( mhi_row[x] == 0 ) 458 mhi_row[x] = stub_val; 459 } 460 } 461 462 for( y = 0; y < mhi->rows; y++ ) 463 { 464 int* mhi_row = (int*)(mhi->data.ptr + y*mhi->step); 465 uchar* mask8u_row = mask8u->data.ptr + (y+1)*mask8u->step + 1; 466 467 for( x = 0; x < mhi->cols; x++ ) 468 { 469 if( mhi_row[x] == ts && mask8u_row[x] == 0 ) 470 { 471 CvConnectedComp comp; 472 int x1, y1; 473 CvScalar _seg_thresh = cvRealScalar(seg_thresh); 474 CvPoint seed = cvPoint(x,y); 475 476 CV_CALL( cvFloodFill( mhi, seed, cvRealScalar(0), _seg_thresh, _seg_thresh, 477 &comp, CV_FLOODFILL_MASK_ONLY + 2*256 + 4, mask8u )); 478 479 for( y1 = 0; y1 < comp.rect.height; y1++ ) 480 { 481 int* mask_row1 = (int*)(mask->data.ptr + 482 (comp.rect.y + y1)*mask->step) + comp.rect.x; 483 uchar* mask8u_row1 = mask8u->data.ptr + 484 (comp.rect.y + y1+1)*mask8u->step + comp.rect.x+1; 485 486 for( x1 = 0; x1 < comp.rect.width; x1++ ) 487 { 488 if( mask8u_row1[x1] > 1 ) 489 { 490 mask8u_row1[x1] = 1; 491 mask_row1[x1] = comp_idx.i; 492 } 493 } 494 } 495 comp_idx.f++; 496 cvSeqPush( components, &comp ); 497 } 498 } 499 } 500 501 for( y = 0; y < mhi->rows; y++ ) 502 { 503 int* mhi_row = (int*)(mhi->data.ptr + y*mhi->step); 504 for( x = 0; x < mhi->cols; x++ ) 505 { 506 if( mhi_row[x] == stub_val ) 507 mhi_row[x] = 0; 508 } 509 } 510 511 __END__; 512 513 cvReleaseMat( &mask8u ); 514 return components; 515 } 516 517 /* End of file. */ 518