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


obj_rec_gui
Author(s): AGAS/agas@uni-koblenz.de
autogenerated on Mon Oct 6 2014 02:53:43