00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <cstring>
00012 #include "ImageMaskCV.h"
00013
00014
00015 #include <math.h>
00016 #include <iostream>
00017
00018 #define THIS ImageMaskCV
00019
00020
00021 THIS::THIS()
00022 {
00023 m_Width = 0;
00024 m_Height = 0;
00025 m_Data = 0;
00026 }
00027
00028 THIS::THIS ( unsigned width, unsigned height, unsigned char* data )
00029 {
00030 m_Width = width;
00031 m_Height = height;
00032 if ( !data )
00033 {
00034 m_Data = new unsigned char[width*height];
00035 fill ( MASKED );
00036 }
00037 else
00038 {
00039 m_Data = data;
00040 }
00041 }
00042
00043
00044 THIS::THIS ( unsigned width, unsigned height, unsigned char* data, char voidMin, char voidMax )
00045 {
00046 m_Width = width;
00047 m_Height = height;
00048 unsigned dataSize = width * height;
00049 m_Data = new unsigned char[dataSize];
00050 if ( !data )
00051 {
00052
00053 fill ( MASKED );
00054 }
00055 else
00056 {
00057 for ( unsigned i = 0; i < dataSize; i++ )
00058 {
00059 if ( ( data[i] >= voidMin ) && ( data[i] <= voidMax ) )
00060 {
00061 m_Data[i] = MASKED;
00062 }
00063 else
00064 {
00065 m_Data[i] = VISIBLE;
00066 }
00067 }
00068 }
00069 }
00070
00071
00072 THIS::THIS ( const ImageMaskCV& other )
00073 {
00074 m_Data = 0;
00075 operator= ( other );
00076 }
00077
00078 THIS& THIS::operator= ( const ImageMaskCV & other )
00079 {
00080 if ( m_Data ) { delete m_Data; }
00081 m_Width = other.m_Width;
00082 m_Height = other.m_Height;
00083 m_Data = new unsigned char[m_Width*m_Height];
00084 memcpy ( m_Data, other.m_Data, m_Width*m_Height );
00085 return *this;
00086 }
00087
00088 THIS::~THIS()
00089 {
00090 if ( m_Data )
00091 {
00092 delete[] m_Data;
00093 }
00094 }
00095
00096 THIS::THIS ( cv::Mat& image, unsigned char minVal, unsigned char maxVal )
00097 {
00098 m_Width = image.cols;
00099 m_Height = image.rows;
00100 m_Data = new unsigned char[m_Width*m_Height];
00101 fill ( 255 );
00102
00103 unsigned offsetMask = 0;
00104 for ( unsigned y = 0; y < m_Height; y++ )
00105 {
00106 for ( unsigned x = 0; x < m_Width; x++ )
00107 {
00108
00109 if(image.type() == CV_8UC1)
00110 {
00111 if ( ( image.at<unsigned char>(y,x) >= minVal ) && ( image.at<unsigned char>(y,x) <= maxVal ) )
00112 {
00113 m_Data[offsetMask] = MASKED;
00114 }
00115 }
00116
00117 else if(image.type() == CV_8UC3)
00118 {
00119 if ( ( image.at<cv::Vec3b>(y,x)[0] >= minVal ) )
00120 {
00121 m_Data[offsetMask] = MASKED;
00122 }
00123 }
00124 offsetMask++;
00125 }
00126 }
00127 }
00128
00129
00130 THIS::THIS (cv::Mat& foregroundY, cv::Mat& foregroundUv,
00131 cv::Mat& backgroundY, cv::Mat& backgroundUv,
00132 int threshold )
00133 {
00134 if ( ( foregroundUv.cols != foregroundY.cols ) ||
00135 ( foregroundUv.rows != foregroundY.rows ) ||
00136 ( foregroundUv.cols != backgroundY.cols ) ||
00137 ( foregroundUv.rows != backgroundY.rows ) ||
00138 ( foregroundUv.cols != backgroundUv.cols ) ||
00139 ( foregroundUv.rows != backgroundUv.rows ) )
00140 {
00141
00142 m_Data = 0;
00143 return;
00144 }
00145
00146 m_Width = foregroundY.cols;
00147 m_Height = foregroundY.rows;
00148 int threshold2 = threshold * threshold;
00149
00150 m_Data = new unsigned char[m_Width*m_Height];
00151 fill ( 255 );
00152
00153 unsigned char* currentMaskPixel = m_Data;
00154
00155 for ( unsigned int y = 0; y < m_Height ; y++ )
00156 {
00157 for ( unsigned int x = 0; x < m_Width ; x++ )
00158 {
00159
00160
00161 int grayDiff = foregroundY.at<unsigned char>(y,x) - backgroundY.at<unsigned char>(y,x);
00162
00163 int bDiff = foregroundUv.at<cv::Vec3b>(y,x)[0] - backgroundUv.at<cv::Vec3b>(y,x)[0];
00164 int gDiff = foregroundUv.at<cv::Vec3b>(y,x)[1] - backgroundUv.at<cv::Vec3b>(y,x)[1];
00165 int rDiff = foregroundUv.at<cv::Vec3b>(y,x)[2] - backgroundUv.at<cv::Vec3b>(y,x)[2];
00166
00167 int distance = grayDiff * grayDiff + bDiff * bDiff + gDiff * gDiff + rDiff * rDiff;
00168
00169 if ( distance < threshold2 )
00170 {
00171 *currentMaskPixel = MASKED;
00172 }
00173 currentMaskPixel++;
00174 }
00175 }
00176
00177 }
00178
00179 void THIS::fill ( unsigned char value )
00180 {
00181 if ( !m_Data )
00182 {
00183
00184 return;
00185 }
00186 memset ( m_Data, value, m_Width*m_Height );
00187 }
00188
00189
00190 void THIS::expand ( const ImageMaskCV& other )
00191 {
00192 if ( !m_Data )
00193 {
00194
00195 return;
00196 }
00197 if ( !other.m_Data )
00198 {
00199
00200 return;
00201 }
00202 if ( ( m_Width != other.m_Width ) || ( m_Height != other.m_Height ) )
00203 {
00204
00205 return;
00206 }
00207 for ( unsigned i = 0; i < m_Width*m_Height; i++ )
00208 {
00209 m_Data[i] |= other.m_Data[i];
00210 }
00211 }
00212
00213
00214 void THIS::apply ( cv::Mat& image, unsigned char fillValue )
00215 {
00216 if ( !m_Data )
00217 {
00218
00219 return;
00220 }
00221 if ( ( unsigned ( image.cols ) != m_Width ) != ( unsigned ( image.rows ) != m_Height ) )
00222 {
00223
00224 return;
00225 }
00226
00227 unsigned char* currentMaskPixel = m_Data;
00228
00229 for ( unsigned y = 0; y < m_Height; y++ )
00230 for ( unsigned x = 0; x < m_Width; x++ )
00231 {
00232 if ( ! ( *currentMaskPixel ) )
00233 {
00234 image.at<unsigned char>(y,x) = fillValue;
00235 }
00236 currentMaskPixel++;
00237 }
00238 }
00239
00240
00241 void THIS::apply ( cv::Mat& image, unsigned char fillR, unsigned char fillG, unsigned char fillB )
00242 {
00243 if ( !m_Data )
00244 {
00245
00246 return;
00247 }
00248 if ( ((unsigned) image.cols != m_Width) != ( (unsigned) image.rows != m_Height ) )
00249 {
00250
00251 return;
00252 }
00253
00254 unsigned char* currentMaskPixel = m_Data;
00255
00256 for ( unsigned y = 0; y < m_Height; y++ )
00257 for ( unsigned x = 0; x < m_Width; x++ )
00258 {
00259 if ( ! ( *currentMaskPixel ) )
00260 {
00261 image.at<cv::Vec3b>(y,x) = cv::Vec3b(fillG, fillR, fillB);
00262 }
00263 currentMaskPixel++;
00264 }
00265 }
00266
00267
00268 void THIS::grayOut ( cv::Mat& colorImage, cv::Mat& graimageY )
00269 {
00270 if ( !m_Data )
00271 {
00272
00273 return;
00274 }
00275
00276 if( colorImage.type() != CV_8UC3)
00277 {
00278
00279 return;
00280 }
00281
00282 if( graimageY.type() != CV_8UC1)
00283 {
00284
00285 return;
00286 }
00287
00288 if ( ( ( unsigned ( colorImage.cols ) != m_Width ) != ( unsigned ( colorImage.rows ) != m_Height ) ) ||
00289 ( ( unsigned ( graimageY.cols ) != m_Width ) != ( unsigned ( graimageY.rows ) != m_Height ) ) )
00290 {
00291
00292 return;
00293 }
00294
00295 unsigned char* currentMaskPixel = m_Data;
00296 unsigned val;
00297
00298 for ( unsigned y = 0; y < m_Height; y++ )
00299 for ( unsigned x = 0; x < m_Width; x++ )
00300 {
00301 if ( ! ( *currentMaskPixel ) )
00302 {
00303 val = graimageY.at<unsigned char>(y,x) / 2 + 64;
00304 colorImage.at<cv::Vec3b>(y,x) = cv::Vec3b(val,val,val);
00305 }
00306 currentMaskPixel++;
00307 }
00308 }
00309
00310
00311 void THIS::grayOut ( cv::Mat& colorImage )
00312 {
00313 if ( !m_Data )
00314 {
00315
00316 return;
00317 }
00318
00319 if( colorImage.type() != CV_8UC3)
00320 {
00321
00322 return;
00323 }
00324
00325 unsigned char* currentMaskPixel = m_Data;
00326 unsigned val;
00327
00328 for ( unsigned y = 0; y < m_Height; y++ )
00329 for ( unsigned x = 0; x < m_Width; x++ )
00330 {
00331 if ( ! ( *currentMaskPixel ) )
00332 {
00333 cv::Vec3b currentRgbPixel = colorImage.at<cv::Vec3b>(y,x);
00334 val = ( currentRgbPixel[0] + currentRgbPixel[1] + currentRgbPixel[2] ) / 6 + 64;
00335 colorImage.at<cv::Vec3b>(y,x) = cv::Vec3b(val,val,val);
00336 }
00337 currentMaskPixel++;
00338 }
00339 }
00340
00341
00342 bool THIS::findValue ( int centerX, int centerY, unsigned char value, float radius )
00343 {
00344 if ( !m_Data )
00345 {
00346
00347 return false;
00348 }
00349
00350 int startX = int ( centerX - radius );
00351 int startY = int ( centerY - radius );
00352 int endX = int ( centerX + radius );
00353 int endY = int ( centerY + radius );
00354
00355 if ( startX < 0 ) { startX = 0; }
00356 if ( startY < 0 ) { startY = 0; }
00357 if ( endX >= int ( m_Width ) ) { endX = m_Width - 1; }
00358 if ( endY >= int ( m_Height ) ) { endY = m_Height - 1; }
00359
00360 float sqrRadius = radius*radius;
00361
00362 for ( int y = startY; y <= endY; y++ )
00363 for ( int x = startX; x <= endX; x++ )
00364 {
00365
00366 if ( m_Data[x+m_Width*y] == value )
00367 {
00368 float sqrDist = float ( x - centerX ) * float ( x - centerX ) + float ( y - centerY ) * float ( y - centerY );
00369 if ( sqrDist <= sqrRadius ) { return true; }
00370 }
00371 }
00372
00373 return false;
00374 }
00375
00376
00377 void THIS::erode ( float radius )
00378 {
00379 maskOperation ( erodeOperation, radius );
00380 }
00381
00382
00383 void THIS::dilate ( float radius )
00384 {
00385 maskOperation ( dilateOperation, radius );
00386 }
00387
00388
00389 void THIS::maskOperation ( maskOperationT operation, float radius )
00390 {
00391 if ( !m_Data )
00392 {
00393
00394 return;
00395 }
00396
00397 if ( radius < 1.0 ) { return; }
00398
00399 int* offsetMask;
00400 int halfMaskSize;
00401 unsigned maskLength;
00402
00403
00404 createCircularKernel ( radius, offsetMask, halfMaskSize, maskLength );
00405
00406
00407 unsigned char* data = new unsigned char[m_Width*m_Height];
00408 memcpy ( data, m_Data, m_Width*m_Height );
00409
00410
00411 unsigned i = halfMaskSize + m_Width * halfMaskSize;
00412 unsigned char fillValue;
00413
00414 switch ( operation )
00415 {
00416 case erodeOperation:
00417 fillValue = MASKED;
00418 break;
00419 case dilateOperation:
00420 fillValue = VISIBLE;
00421 break;
00422 default:
00423 fillValue = MASKED;
00424
00425 }
00426
00427 for ( unsigned y = halfMaskSize; y < m_Height - halfMaskSize; y++ )
00428 {
00429 for ( unsigned x = halfMaskSize; x < m_Width - halfMaskSize; x++ )
00430 {
00431 if ( m_Data[i] && ! ( m_Data[i-1] && m_Data[i+1] && m_Data[i-m_Width] && m_Data[i+m_Width] ) )
00432 {
00433 for ( unsigned j = 0; j < maskLength; j++ )
00434 {
00435 data[ i + offsetMask[j] ] = fillValue;
00436 }
00437 }
00438 i++;
00439 }
00440 i += halfMaskSize * 2;
00441 }
00442
00443
00444 delete[] m_Data;
00445 m_Data = data;
00446
00447 delete[] offsetMask;
00448 }
00449
00450
00451 void THIS::findBorders( )
00452 {
00453 if ( !m_Data )
00454 {
00455
00456 return;
00457 }
00458
00459
00460 unsigned char* data = new unsigned char[m_Width*m_Height];
00461 memset ( data, VISIBLE, m_Width*m_Height );
00462
00463
00464 unsigned i = m_Width + 1;
00465
00466 for ( unsigned y = 1; y < m_Height - 1; y++ )
00467 {
00468 for ( unsigned x = 1; x < m_Width - 1; x++ )
00469 {
00470 if ( m_Data[i] && ! ( m_Data[i-1] && m_Data[i+1] && m_Data[i-m_Width] && m_Data[i+m_Width] ) )
00471 {
00472 data[i] = MASKED;
00473 }
00474 i++;
00475 }
00476 i += 2;
00477 }
00478
00479
00480 delete[] m_Data;
00481 m_Data = data;
00482 }
00483
00484
00485 void THIS::createCircularKernel ( float radius, int*& offsetMask, int& halfMaskSize, unsigned& maskLength )
00486 {
00487 unsigned maskSize = unsigned ( radius ) * 2 + 1;
00488 halfMaskSize = maskSize / 2;
00489 offsetMask = new int[maskSize*maskSize-1];
00490 unsigned i = 0;
00491 float dist;
00492 for ( int y = -halfMaskSize; y <= halfMaskSize; y++ )
00493 for ( int x = -halfMaskSize; x <= halfMaskSize; x++ )
00494 {
00495 dist = sqrt ( float ( x ) * float ( x ) + float ( y ) * float ( y ) );
00496 if ( dist <= radius )
00497 {
00498 offsetMask[i] = x + m_Width * y;
00499 i++;
00500 }
00501 }
00502 maskLength = i;
00503 }
00504
00505 Point2D THIS::getGravCenter ( )
00506 {
00507 double centerX = 0;
00508 double centerY = 0;
00509 int numPixels = 0;
00510 int i = 0;
00511
00512 for ( unsigned y = 0; y < m_Height; y++ )
00513 {
00514 for ( unsigned x = 0; x < m_Width; x++ )
00515 {
00516 if ( m_Data[i] == VISIBLE )
00517 {
00518 centerX += x;
00519 centerY += y;
00520 numPixels ++;
00521 }
00522 i++;
00523 }
00524 }
00525 centerX /= numPixels;
00526 centerY /= numPixels;
00527
00528 return Point2D( centerX, centerY );
00529 }
00530
00531 Box2D<int> THIS::getBoundingBox()
00532 {
00533
00534 Box2D<int> bBox( m_Width, m_Height, 0, 0 );
00535 int i = 0;
00536
00537 for ( unsigned y = 0; y < m_Height; y++ )
00538 {
00539 for ( unsigned x = 0; x < m_Width; x++ )
00540 {
00541 if ( m_Data[i] == VISIBLE )
00542 {
00543 bBox.enclose( x, y );
00544 }
00545 i++;
00546 }
00547 }
00548 bBox.enclose( bBox.maxX()+1, bBox.maxY()+1 );
00549
00550 return bBox;
00551 }
00552
00553 THIS* THIS::subMask( Box2D<int> area )
00554 {
00555 int newWidth = area.width();
00556 int newHeight= area.height();
00557 THIS* result = new THIS( newWidth, newHeight );
00558 unsigned char* newData = result->getData();
00559
00560 int minX = area.minX();
00561 int minY = area.minY();
00562
00563 int i = 0;
00564
00565 for ( int y = 0; y < newHeight; y++ )
00566 {
00567 for ( int x = 0; x < newWidth; x++ )
00568 {
00569 newData[i] = m_Data[ minX+x + ( minY+y )*m_Width ];
00570 i++;
00571 }
00572 }
00573
00574 return result;
00575 }
00576
00577 #undef DEBUG_OUTPUT
00578 #undef THIS