ImageMaskCV.cpp
Go to the documentation of this file.
00001 /*******************************************************************************
00002  *  ImageMaskCV.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 "ImageMaskCV.h"
00013 // #include "Architecture/Tracer/Tracer.h" // TODO
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     // TRACE_ERROR ( "Mask data is 0-pointer!" ); // TODO use ros
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   //mask all pixels with value maskVal
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         // handle gray level images
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         // handle color images
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     // TRACE_ERROR ( "Image size mismatch in difference mask constructor." ); // TODO use ros
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         // TODO check whether this is working correctly
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    // TRACE_ERROR ( "This mask is empty." );// TODO use ros
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     // TRACE_ERROR ( "This mask is empty." );// TODO use ros
00195     return;
00196   }
00197   if ( !other.m_Data )
00198   {
00199     // TRACE_ERROR ( "Other mask is empty." );// TODO use ros
00200     return;
00201   }
00202   if ( ( m_Width != other.m_Width ) || ( m_Height != other.m_Height ) )
00203   {
00204    // TRACE_ERROR ( "Wrong mask size." );// TODO use ros
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    // TRACE_ERROR ( "This mask is empty." );// TODO use ros
00219     return;
00220   }
00221   if ( ( unsigned ( image.cols ) != m_Width ) != ( unsigned ( image.rows ) != m_Height ) )
00222   {
00223    //  TRACE_ERROR ( "Wrong image size." );// TODO use ros
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     //TRACE_ERROR ( "This mask is empty." );// TODO use ros
00246     return;
00247   }
00248   if ( ((unsigned) image.cols != m_Width)  != ( (unsigned) image.rows != m_Height ) )
00249   {
00250     //TRACE_ERROR ( "Wrong image size." );// TODO use ros
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     //TRACE_ERROR ( "This mask is empty." );// TODO use ros
00273     return;
00274   }
00275 
00276   if( colorImage.type() != CV_8UC3)
00277   {
00278       // TRACE_ERROR ( "Wrong data type: CV_8UC3 is needed." );// TODO use ros
00279        return;
00280   }
00281 
00282   if( graimageY.type() != CV_8UC1)
00283   {
00284       // TRACE_ERROR ( "Wrong data type: CV_8UC1 is needed." );// TODO use ros
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     //TRACE_ERROR ( "Wrong image size." );// TODO use ros
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    // TRACE_ERROR ( "This mask is empty." );// TODO use ros
00316     return;
00317   }
00318 
00319   if( colorImage.type() != CV_8UC3)
00320   {
00321       // TRACE_ERROR ( "Wrong data type: CV_8UC3 is needed." );// TODO use ros
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     //TRACE_ERROR ( "This mask is empty." );// TODO use ros
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 //       std::cout << int(m_Data[x+m_Width*y]) << " ";
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    // TRACE_ERROR ( "This mask is empty." );// TODO use ros
00394     return;
00395   }
00396 
00397   if ( radius < 1.0 ) { return; }
00398 
00399   int* offsetMask;
00400   int halfMaskSize;
00401   unsigned maskLength;
00402 
00403   //create circular filter mask
00404   createCircularKernel ( radius, offsetMask, halfMaskSize, maskLength );
00405 
00406   //copy mask data
00407   unsigned char* data = new unsigned char[m_Width*m_Height];
00408   memcpy ( data, m_Data, m_Width*m_Height );
00409 
00410   //apply filter mask
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       //TRACE_WARNING ( "No mask operation provided, using \"erode operation\"!" );// TODO use ros
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   //switch to new mask
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    // TRACE_ERROR ( "This mask is empty." );// TODO use ros
00456     return;
00457   }
00458 
00459   //copy mask data
00460   unsigned char* data = new unsigned char[m_Width*m_Height];
00461   memset ( data, VISIBLE, m_Width*m_Height );
00462 
00463   //apply filter mask
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   //switch to new mask
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   //initialize "negative" bounding box (min/max swapped)
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


robbie_architecture
Author(s): Viktor Seib
autogenerated on Mon Oct 6 2014 02:53:09