The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

mpisearchthread.cpp

Go to the documentation of this file.
00001 /*
00002  *  mpisearchthread.cpp
00003  *  
00004  *
00005  *  Created by John Hershey 2002.
00006  *  Copyright (c) 2003 Machine Perception Laboratory
00007  *  University of California San Diego.
00008  *  Please read the disclaimer and notes about redistribution
00009  *  at the end of this file.
00010  *
00011  *  Authors: John Hershey, Josh Susskind, Bret Fortenberry
00012  */
00013 #ifdef WIN32
00014 #pragma warning(disable:4786)
00015 #endif
00016 
00017 #include "mpisearch.h"
00018 #include "mpisearchthread.h"
00019 #include "iniconfig.h"
00020 #include <cmath>
00021 #include <list>
00022 #include <vector>
00023 #include "Rectangle.h"
00024 #include "Images/imageio.h"
00025 #include "common.h"
00026 #ifdef WIN32
00027 #include <process.h>
00028 #else
00029 #include <pthread.h>
00030 #endif
00031 
00032 /* for call to feature detector */
00033 const int FRACTIONAL_SCALES=1;
00034 
00035 /* Alternative to non-blocking or infinite mutex waits */
00036 const int WAIT_EXTERNAL=16;
00037 
00038 #define MPI_IMAGE_WIDTH 320 // reduce the width & height of pixels for mpisearch for higher performance
00039 /* ================================================================ */
00040 
00041 THREAD_RETURN_TYPE MPISearchThread::StartThreadedTracker(void *ThisMPISearchThread)
00042 {
00043         MPISearchThread *MPI = static_cast<MPISearchThread *>(ThisMPISearchThread);
00044         while (MPI->m_ThreadRunning)
00045                 MPI->Process();
00046 #ifdef WIN32
00047         _endthread();
00048 #endif
00049 }
00050 
00051 /* ================================================================ */
00052 
00053 /* Constructor */
00054 MPISearchThread::MPISearchThread()
00055 {
00056         //      ASSERT( (m_Detector.DataLoaded()) );
00057         m_MyPixels = 0;
00058         m_NumPixels = m_NumFaces = m_lastWidth = m_lastHeight = 0;
00059         m_ColorMeanX = m_ColorMeanY = m_MPIMeanX = m_MPIMeanY = 0.0;
00060         m_ResetTracker = 0;
00061         m_llikePix = 0;
00062         m_shiftAmount = 1;
00063         //sets max pixel value based on max pixel possibility of FFImage<float>
00064         m_Detector.setPixelMax(2560);
00065 
00066         CreateMutex (m_DataMutex);
00067         CreateMutex (m_FaceMutex);
00068         CreateMutex (m_ImageMutex);
00069         CreateMutexEvent(m_GotBufferFillRequest);
00070         
00071 }
00072 
00073 /* ================================================================ */
00074 
00075 #ifdef USEHUE
00076 void MPISearchThread::GetColorModel(MPHistogramHue<float, NUMBINS> *lpf, MPHistogramHue<float, NUMBINS> *lpb, int *reset, double *llike)
00077 #else
00078 void MPISearchThread::GetColorModel(MPHistogram<float, NUMBINS> *lpf, MPHistogram<float, NUMBINS> *lpb, int *reset, double *llike)
00079 #endif
00080 {
00081 
00082         MUTEX_LOCK_RETURN_TYPE waitResult = TryLockMutex(m_DataMutex);
00083 
00084         switch( waitResult ) {
00085         case WAIT_OBJECT_0:  
00086 
00087                 *lpf = m_LogProbColorGivenFace;
00088                 *lpb = m_LogProbColorGivenBack;         
00089                 *reset = m_ResetTracker;
00090                 //m_ResetTracker = 0;
00091                 *llike = m_llikePix;
00092                 ReleaseMutex(m_DataMutex);
00093                 break;
00094         default:
00095                 break;
00096         }
00097 }
00098 
00099 /* ================================================================ */
00100 
00101 void MPISearchThread::Start()
00102 {
00103         LockMutex( m_DataMutex );
00104         m_ThreadRunning = TRUE;
00105         InitColorModel();
00106         ReleaseMutex( m_DataMutex);
00107 #ifdef WIN32
00108         m_ThreadHandle = (HANDLE) (_beginthread( StartThreadedTracker, 0, this ));
00109 #ifdef SHOWPROBS
00110         SetThreadPriority(m_ThreadHandle, THREAD_PRIORITY_NORMAL);
00111 #else
00112         SetThreadPriority(m_ThreadHandle, THREAD_PRIORITY_NORMAL-1);
00113 #endif // SHOWPROBS
00114 #else
00115         pthread_create(&m_ThreadHandle, NULL, &StartThreadedTracker, (void *)this);
00116 #endif
00117 }
00118 
00119 /* ================================================================ */
00120 
00121 void MPISearchThread::PutData(RGBTRIPLE *d, int x, int y, int np, int colorMeanX, int colorMeanY, long curFrame)
00122 {
00123 
00124         MUTEX_LOCK_RETURN_TYPE waitResult = TryLockMutex(m_ImageMutex);
00125         switch( waitResult ) {
00126         case WAIT_OBJECT_0: 
00127                 if (!m_NumPixels) {
00128                         m_NumPixels = np;
00129                         if (!m_MyPixels) m_MyPixels = new RGBTRIPLE[m_NumPixels];
00130                         memcpy(m_MyPixels, d, m_NumPixels*sizeof(RGBTRIPLE));
00131                         m_Width = x;
00132                         m_Height = y;
00133                         m_ColorMeanX = colorMeanX;
00134                         m_ColorMeanY = colorMeanY;
00135                         m_curFrame = curFrame;
00136                         MutexCondSignal(m_GotBufferFillRequest);
00137                 }
00138                 ReleaseMutex( m_ImageMutex);
00139                 break;
00140         default:
00141                 break;
00142         }
00143 }
00144 
00145 /* ================================================================ */
00146 
00147 void MPISearchThread::Process()
00148 {
00149         FaceBoxList faces;
00150         TIMETYPE timeBeginMPISearchSearch; 
00151         
00152         MutexCondWait(m_GotBufferFillRequest, m_ImageMutex); 
00153         if (m_NumPixels) {
00154                 timeBeginMPISearchSearch = getCurTime();
00155                 setShift();
00156                 // Create FFImage wrapper around pixels
00157 #ifdef WIN32 
00158                 //(pthreads)lock is handled in wait condition
00159                 LockMutex(m_ImageMutex);
00160 #endif
00161                 FFImage<RGBTRIPLE> source(m_MyPixels, m_Width, m_Height, IMAGE_FLIPPED);
00162                 // Create New Grayscale version of the FFImage to be used in mpisearch
00163                 FFImage<float> pixels(source, m_shiftAmount);           
00164                 ReleaseMutex(m_ImageMutex);
00165 
00166                 Search(pixels, faces); // do not hold mutex during long process 
00167 
00168                 m_NumFaces=faces.size();
00169 
00170                 if (!faces.empty()) {
00171                         shiftFaces(faces);
00172                         faces.objects.sort();
00173                         faces.objects.reverse();
00174 
00175                         LockMutex(m_FaceMutex);
00176                         m_MPIBoxes = faces;
00177                         m_lastFrame = m_curFrame;
00178                         ReleaseMutex(m_FaceMutex);
00179 
00180                         UpdateTimeMPISearchBoxes(timeBeginMPISearchSearch); // Added by Javier
00181                         UpdateColorModel(faces);
00182                 }
00183                 m_NumPixels=0; // Tells color tracker that processing is done 
00184 
00185         }
00186         //else ReleaseMutex(m_ImageMutex);
00187 }
00188 
00189 /* ================================================================ */
00190 
00191 void MPISearchThread::Search(FFImage<float> &pixels, FaceBoxList &faces)
00192 {
00193         if((pixels.width != m_lastWidth) || (pixels.height != m_lastHeight)){
00194                 m_Detector.resetStream(pixels.width, pixels.height);
00195                 m_lastWidth = pixels.width ; m_lastHeight = pixels.height;
00196         }
00197         m_Detector.search(pixels, faces);
00198         faces.simplify(0.2f);
00199 }
00200 
00201 /* ================================================================ */
00202 
00203 void MPISearchThread::InitColorModel()
00204 {
00205         m_ProbColorGivenFace.InitColorModel(1);
00206         m_CurrentProbColorGivenFace.InitColorModel(1);
00207         m_ProbColorGivenBack.InitColorModel(0);
00208         m_CurrentProbColorGivenBack.InitColorModel(0);
00209         UpdateProbabilities();
00210 }
00211 
00212 /* ================================================================ */
00213 
00214 void MPISearchThread::UpdateColorModel(FaceBoxList & faces)
00215 {
00216         m_CurrentProbColorGivenFace.initialize();
00217         m_CurrentProbColorGivenBack.initialize();
00218 
00219         Square mainface;
00220         mainface = faces.front();
00221         bool isNonFace;
00222 
00223         double shrink = 0.15;
00224         double shrinky = .8;
00225         // We collect stats for the central region of the face box. This central region is 
00226   // n % of the original box but has been modified so that the offset in the y direction is less. 
00227         int offsetx = static_cast<int>(shrink*mainface.size), 
00228                 offsety = (int) (((float) offsetx)*shrinky ),            
00229                 startXMPI, startYMPI, endXMPI, endYMPI,
00230                 startXFace, startYFace, endXFace, endYFace;
00231         
00232         startXMPI = mainface.x;
00233         startYMPI = mainface.y;
00234         endXMPI = startXMPI+mainface.size;
00235         endYMPI = startYMPI+mainface.size;
00236         startXFace      = startXMPI + offsetx;
00237         startYFace      = startYMPI + offsety;
00238         endXFace        = endXMPI - offsetx;
00239         endYFace        = endYMPI - offsety;
00240 
00241 
00242   list<MPRectangle> searchRects;
00243   list<int> xPos;
00244   list<int> yPos;
00245   list<Square>::iterator it = faces.begin();
00246   list<Square>::iterator end = faces.end();
00247 
00248   xPos.push_back(0);
00249   xPos.push_back(m_Width);
00250   yPos.push_back(0);
00251   yPos.push_back(m_Height);
00252   for (;it != end; it++) {
00253     Square face = *(it);
00254     //set rectangle for foreground **there is a cushion set smaller then face box
00255     MPRectangle foreground(face.x+offsetx, face.x+face.size-offsetx, face.y+offsety, face.y+face.size-offsety, true);
00256     searchRects.push_back(foreground);
00257     //set positions to create background rectangles **there is a cushion set larger then face box
00258     xPos.push_back(max(0,face.x-offsetx));
00259     xPos.push_back(min(m_Width,face.x+face.size+offsetx));
00260     yPos.push_back(max(0,face.y-offsety));
00261     yPos.push_back(min(m_Height,face.y+face.size+offsety));
00262   }
00263         xPos.sort();
00264         yPos.sort();
00265         
00266         //set rectange for background from positions created previously
00267   list<int>::iterator itX = xPos.begin();
00268   list<int>::iterator endX = xPos.end();
00269   list<int>::iterator itY = yPos.begin();
00270   list<int>::iterator endY = yPos.end();
00271   int leftX, rightX, topY, bottomY;
00272   float midX, midY;
00273   while (itX != endX) {
00274     leftX = *(itX);
00275     itX++;
00276     if (itX == endX) break;
00277     rightX = *(itX);
00278     midX = (leftX+rightX)*0.5;
00279     //cout << "leftx = " << leftX;
00280     //cout << " rightX = " << rightX << endl;
00281     itY = yPos.begin();
00282     while (itY != endY) {
00283       topY = *(itY);
00284       itY++;
00285       if (itY == endY) break;
00286       bottomY = *(itY);
00287       midY = (topY+bottomY)*0.5;
00288       isNonFace = true;
00289       it = faces.begin();
00290       for(;it != end; it++) {
00291         Square face = *(it);
00292 
00293         if (midX > face.x && midX < (face.x+face.size) &&
00294             midY > face.y && midY < (face.y+face.size))
00295           isNonFace = false;
00296       }
00297       if(isNonFace) {
00298         MPRectangle background(leftX, rightX, topY, bottomY, false);
00299         searchRects.push_back(background);
00300       }
00301     }
00302   }
00303 
00304           // Create FFImage wrapper around pixels
00305           FFImage<RGBTRIPLE> rgbimage(m_MyPixels, m_Width, m_Height, IMAGE_FLIPPED);
00306           RGBTRIPLE temp;
00307 
00308           // get probs for both face and background
00309           list<MPRectangle>::iterator it2 = searchRects.begin();
00310           list<MPRectangle>::iterator end2 = searchRects.end();
00311           for (;it2 != end2; it2++) {
00312                         MPRectangle rect = *(it2);
00313                         for(int y=rect.Y1; y<rect.Y2; y++) {
00314                                 for (int x=rect.X1; x<rect.X2; x++) {
00315                                         temp = rgbimage.getPixel(x,y);
00316                                         if(rect.face)
00317                                                 m_CurrentProbColorGivenFace.addtobin(temp);
00318                                         else
00319                                                 m_CurrentProbColorGivenBack.addtobin(temp);
00320                                 }
00321                         }
00322           }
00323 
00324         LockMutex(m_DataMutex);
00325         UpdateProbabilities();
00326 
00327         // compute likelihood ratio per pixel under new model at current face box 
00328         m_llikePix = 0;
00329         int nPix = 0;
00330         for (int x=startXFace; x<endXFace; x++) {
00331                 for (int y=startYFace; y < endYFace; y++) {
00332                   temp = rgbimage.getPixel(x,y);
00333                   m_llikePix += m_LogProbColorGivenFace.get_prob(temp) - m_LogProbColorGivenBack.get_prob(temp);
00334                   nPix++;
00335                 }
00336         }
00337         m_llikePix /= nPix;
00338         ReleaseMutex(m_DataMutex);
00339 }
00340 
00341 /* ================================================================ */
00342 
00343 void MPISearchThread::CompareColorMPIMeans(Square box)
00344 {
00345         m_MPIMeanX = box.x + box.size/2;
00346         m_MPIMeanY = m_Height - box.y - box.size/2;
00347         double widthBtwn = abs(double(m_ColorMeanX - m_MPIMeanX));
00348         double heightBtwn = abs(double(m_ColorMeanY - m_MPIMeanY));
00349         double distanceBtwn = sqrt(double(widthBtwn*widthBtwn + heightBtwn*heightBtwn));
00350         if (static_cast<int>(distanceBtwn) > box.size)
00351                 m_ResetTracker = 1;
00352 }
00353 
00354 /* ================================================================ */
00355 
00356 void MPISearchThread::UpdateProbabilities()
00357 {
00358 
00359         m_ProbColorGivenBack.update_hist (m_CurrentProbColorGivenBack, m_LogProbColorGivenBack, 0.5);
00360         m_ProbColorGivenFace.update_hist (m_CurrentProbColorGivenFace, m_LogProbColorGivenFace, 0.5);
00361 
00362 } // MPISearchThread::UpdateProbabilities
00363 
00364 /* ================================================================ */
00365 
00366 void MPISearchThread::GetHueMinMax( int r, int g, int b, double &h, int &min, int &max ) {
00367 /*      float delta;
00368         if (r >= g) {max = r; min = g;}
00369         else {max = g; min = r;}
00370         if (b > max) max = b;
00371         else if (b < min) min = b;
00372         delta = (float)(max - min);
00373         if (max == r) h = (g-b)/delta;
00374         else if (max == g) h = 2 + (b-r)/delta;
00375         else h = 4 + (r-g)/delta;
00376         h = (h < 0) ? (float)(h*60.0 + 360.0) : (float)(h*60.0);*/
00377 }
00378 
00379 /* ================================================================ */
00380 
00381 void MPISearchThread::UpdateTimeMPISearchBoxes(TIMETYPE t)
00382 {
00383         m_TimeMPISearchBoxes = t;
00384 }
00385 
00386 /* ================================================================ */
00387 
00388 int MPISearchThread::GetMPIFaceBoxes(FaceBoxList &boxes)
00389 {
00390         MUTEX_LOCK_RETURN_TYPE waitResult = TryLockMutex(m_FaceMutex);
00391         switch( waitResult ) {
00392         case WAIT_OBJECT_0:  
00393                 boxes = m_MPIBoxes;
00394                 ReleaseMutex(m_FaceMutex);
00395                 break;
00396         case WAIT_TIMEOUT: 
00397         case WAIT_ABANDONED:
00398         case WAIT_FAILED:
00399         default:
00400                 break;
00401         }
00402         return 1;
00403 }
00404 
00405 /* ================================================================ */
00406 
00407 TIMETYPE MPISearchThread::getCurTime(){
00408 
00409         TIMETYPE curTime;
00410 #ifdef WIN32
00411         curTime = timeGetTime();
00412 #else
00413         gettimeofday( &curTime, NULL );
00414 #endif
00415         return curTime;
00416 }
00417 
00419 
00420 #ifndef WIN32
00421 double difftv(TIMETYPE t1, TIMETYPE t0)
00422 {
00423   double s;
00424   double secs = t1.tv_sec - t0.tv_sec;
00425   double usecs = ((double)t1.tv_usec) - ((double)t0.tv_usec);
00426   usecs *= 1e-6;
00427   s = secs + usecs;
00428   return s;
00429 }
00430 #endif
00431 
00433 
00434 double MPISearchThread::getElapsedTime(){
00435 
00436         double elapsedTime;
00437 #ifdef WIN32
00438         elapsedTime = timeGetTime()-m_TimeMPISearchBoxes;
00439 #else
00440         TIMETYPE curTime;
00441         gettimeofday( &curTime, NULL );
00442         elapsedTime = difftv(curTime, m_TimeMPISearchBoxes) * 1000.0;
00443 #endif
00444         return elapsedTime;
00445 }
00446 
00447 /* ================================================================ */
00448 
00449 void MPISearchThread::setShift() {
00450         m_shiftAmount = static_cast<int>(m_Width/MPI_IMAGE_WIDTH);
00451         if (m_shiftAmount < 1) m_shiftAmount = 1;
00452 }
00453 
00454 /* ================================================================ */
00455 
00456 void MPISearchThread::shiftFaces(FaceBoxList & faces) {
00457         if(m_shiftAmount < 1) m_shiftAmount = 1;
00458         list<Square>::iterator it = faces.begin();
00459         while (it != faces.end()) {
00460                 it->size *= m_shiftAmount;
00461                 it->x *= m_shiftAmount;
00462                 it->y *= m_shiftAmount;
00463                 *it++;
00464         }
00465 }
00466 
00467 /* ================================================================ */
00468 
00469 int MPISearchThread::GetNumFaces()
00470 {
00471         int nf = 0; 
00472         MUTEX_LOCK_RETURN_TYPE waitResult = TryLockMutex(m_FaceMutex);
00473         switch( waitResult ) {
00474         case WAIT_OBJECT_0: 
00475 
00476                 nf = m_NumFaces;
00477                 ReleaseMutex(m_FaceMutex);
00478         default:
00479                 break;
00480         }
00481         return nf;
00482 }
00483 
00484 /* ================================================================ */
00485 
00486 /* destructor */
00487 MPISearchThread::~MPISearchThread()
00488 {
00489         m_ThreadRunning = FALSE;
00490         if (m_MyPixels) delete [] m_MyPixels;
00491 
00492 }
00493 
00494 
00495 /*
00496  * 
00497  * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00498  * 
00499  *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00500  *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
00501  *    3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
00502  * 
00503  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00504  * 
00505  */

Generated on Mon Nov 8 17:07:46 2004 for MPT by  doxygen 1.3.9.1