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

MPColorTrackerFilter.cpp

Go to the documentation of this file.
00001 //==========================================================================;
00002 //  MPColorTrackerFilter
00003 //  This is intended to be a very fast face tracker. 
00004 //  It is based on very primitive color, shape and motion information.
00005 //  This allows it to do its job very fast. However it will get confused
00006 //  by things that look like a flesh-colored blob and move.
00007 //  In applications the system should be complemented by a
00008 //  template/feature based face detection module 
00009 //
00010 //
00011 //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
00012 //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
00013 //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
00014 //  PURPOSE.
00015 //
00016 //  Original version developed by Boris E. Shpungin at UCSD's Machine Perception Lab
00017 //  Under the supersvision of Javier R. Movellan
00018 //  Copyright (c) Machine Perception Laboratory, UCSD
00019 //  Licensed under the GNU GPL agreement 
00020 //--------------------------------------------------------------------------;
00021 
00022 //#include <windows.h>
00023 #include <streams.h>
00024 #include <initguid.h>
00025 #if (1100 > _MSC_VER)
00026 #include <olectlid.h>
00027 #else
00028 #include <olectl.h>
00029 #endif
00030 #include "DirectShow/MPUFilter_uids.h"
00031 #include "iMPColorTrackerFilter.h"
00032 //#include "MPColorTrackerFilter_prop.h"
00033 #include "MPColorTrackerFilter.h"
00034 #include "resource.h"
00035 #include <ctime>
00036 
00037 // ================================================================
00038 
00039 // Setup information
00040 const AMOVIESETUP_MEDIATYPE sudPinTypes =
00041 {
00042         &MEDIATYPE_Video,      // Major type
00043                 &MEDIASUBTYPE_NULL      // Minor type
00044 };
00045 
00046 // ================================================================
00047 
00048 const AMOVIESETUP_PIN sudpPins[] =
00049 {
00050         { L"Input",            // Pins string name
00051                 FALSE,                // Is it rendered
00052                 FALSE,                // Is it an output
00053                 FALSE,                // Are we allowed none
00054                 FALSE,                // And allowed many
00055                 &CLSID_NULL,          // Connects to filter
00056                 NULL,                // Connects to pin
00057                 1,                    // Number of types
00058                 &sudPinTypes          // Pin information  
00059         },
00060         { L"Output",            // Pins string name
00061         FALSE,                // Is it rendered
00062         TRUE,                // Is it an output
00063         FALSE,                // Are we allowed none
00064         FALSE,                // And allowed many
00065         &CLSID_NULL,          // Connects to filter
00066         NULL,                // Connects to pin
00067         1,                    // Number of types
00068         &sudPinTypes          // Pin information
00069         }
00070 };
00071 
00072 // ================================================================
00073 
00074 const AMOVIESETUP_FILTER sudMPColorTrackerFilter =
00075 {
00076         &CLSID_MPColorTrackerFilter, // Filter CLSID
00077                 L"MPColorTrackerFilter",      // String name
00078                 MERIT_DO_NOT_USE,      // Filter merit
00079                 2,                      // Number of pins
00080                 sudpPins                // Pin information
00081 };
00082 
00083 // ================================================================
00084 
00085 // List of class IDs and creator functions for the class factory. This
00086 // provides the link between the OLE entry point in the DLL and an object
00087 // being created. The class factory will call the static CreateInstance
00088 CFactoryTemplate g_Templates[] = {
00089         { L"MPLab Color Tracker Filter"
00090                 , &CLSID_MPColorTrackerFilter
00091                 , MPColorTrackerFilter::CreateInstance
00092                 , NULL
00093                 , &sudMPColorTrackerFilter },
00094 //      { L"MPLab Color Tracker Fiter Properties"
00095 //      , &CLSID_MPColorTrackerFilterPropertyPage }
00096 };
00097 int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
00098 
00099 // ================================================================
00100 
00101 //
00102 // DllRegisterServer
00103 //
00104 // Handles sample registry and unregistry
00105 //
00106 STDAPI DllRegisterServer()
00107 {
00108         return AMovieDllRegisterServer2( TRUE );
00109         
00110 } // DllRegisterServer
00111 
00112 // ================================================================
00113 
00114 //
00115 // DllUnregisterServer
00116 //
00117 STDAPI DllUnregisterServer()
00118 {
00119         return AMovieDllRegisterServer2( FALSE );
00120 } // DllUnregisterServer
00121 
00122 // ================================================================
00123 
00124 //
00125 // Constructor
00126 //
00127 MPColorTrackerFilter::MPColorTrackerFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr) 
00128 : CTransformFilter(tszName, punk, CLSID_MPColorTrackerFilter)
00129 , m_effect(IDC_RED)
00130 , m_lBufferRequest(1)
00131 , CPersistStream(punk, phr)
00132 {
00133         char sz[60];
00134         GetProfileStringA("Adaptability", "ResetInterval", "30.0", sz, 60);
00135         m_resetInterval = COARefTime(atof(sz));
00136         
00137         m_currentTime = COARefTime(0.0);     
00138         m_lastValidTime = COARefTime(0.0);
00139         
00141         
00142         srand( (unsigned)time( NULL ) );
00143 } // (Constructor)
00144 
00145 // ================================================================
00146 
00147 //
00148 // CreateInstance
00149 //
00150 // Provide the way for COM to create a MPColorTrackerFilter object
00151 //
00152 CUnknown *MPColorTrackerFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
00153 {
00154         MPColorTrackerFilter *pNewObject = new MPColorTrackerFilter(NAME("Face Tracker MPLab"), punk, phr);
00155         if (pNewObject == NULL)
00156                 *phr = E_OUTOFMEMORY;
00157         return pNewObject;
00158 } // CreateInstance
00159 
00160 // ================================================================
00161 
00162 //
00163 // NonDelegatingQueryInterface
00164 //
00165 // Reveals IIPEffect and ISpecifyPropertyPages
00166 //
00167 STDMETHODIMP MPColorTrackerFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv)
00168 {
00169         CheckPointer(ppv,E_POINTER);
00170         if (riid == IID_IIPEffect) {
00171                 return GetInterface((IIPEffect *) this, ppv);
00172         } else if (riid == IID_ISpecifyPropertyPages) {
00173                 return GetInterface((ISpecifyPropertyPages *) this, ppv);
00174         } else {
00175                 return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
00176         }
00177 } // NonDelegatingQueryInterface
00178 
00179 // ================================================================
00180 
00181 HRESULT MPColorTrackerFilter::StartStreaming(){
00182 //      m_colortracker.InitStreaming();
00183         return S_OK;
00184 }
00185 
00186 // ================================================================
00187 
00188 HRESULT MPColorTrackerFilter::StopStreaming(){
00189 //      m_colortracker.EndStreaming();
00190         return S_OK;
00191 }
00192 
00193 // ================================================================
00194 
00195 //
00196 // Transform
00197 //
00198 // Copy the input sample into the output sample - then transform the output
00199 // sample 'in place'. If we have all keyframes, then we shouldn't do a copy
00200 // If we have cinepak or indeo and are decompressing frame N it needs frame
00201 // decompressed frame N-1 available to calculate it, unless we are at a
00202 // keyframe. So with keyframed codecs, you can't get away with applying the
00203 // transform to change the frames in place, because you'll screw up the next
00204 // frames decompression. The runtime MPEG decoder does not have keyframes in
00205 // the same way so it can be done in place. We know if a sample is key frame
00206 // as we transform because the sync point property will be set on the sample
00207 //
00208 HRESULT MPColorTrackerFilter::Transform(IMediaSample *pIn, IMediaSample *pOut)
00209 {
00210         // Copy the properties across
00211         HRESULT hr = Copy(pIn, pOut);
00212         if (FAILED(hr)) {
00213                 return hr;
00214         }
00215         
00216         CRefTime temp;
00217         pIn->GetTime((REFERENCE_TIME *) &m_currentTime, (REFERENCE_TIME *)&temp);
00218         
00219         return Transform(pOut);
00220         
00221 } // Transform
00222 
00223 // ================================================================
00224 
00225 //
00226 // Copy
00227 //
00228 // Make destination an identical copy of source
00229 //
00230 HRESULT MPColorTrackerFilter::Copy(IMediaSample *pSource, IMediaSample *pDest)
00231 {
00232         // Copy the sample data
00233         
00234         BYTE *pSourceBuffer, *pDestBuffer;
00235         long lSourceSize = pSource->GetActualDataLength();
00236         long lDestSize  = pDest->GetSize();
00237         
00238         ASSERT(lDestSize >= lSourceSize);
00239         
00240         pSource->GetPointer(&pSourceBuffer);
00241         pDest->GetPointer(&pDestBuffer);
00242         
00243         m_interface.printFrame((RGBTRIPLE*)pSourceBuffer, m_imgWidth, m_imgHeight);
00244         CopyMemory( (PVOID) pDestBuffer,(PVOID) pSourceBuffer,lSourceSize);
00245         
00246         // Copy the sample times
00247         
00248         REFERENCE_TIME TimeStart, TimeEnd;
00249         if (NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) {
00250                 pDest->SetTime(&TimeStart, &TimeEnd);
00251         }
00252         
00253         LONGLONG MediaStart, MediaEnd;
00254         if (pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {
00255                 pDest->SetMediaTime(&MediaStart,&MediaEnd);
00256         }
00257         
00258         // Copy the Sync point property
00259         
00260         HRESULT hr = pSource->IsSyncPoint();
00261         if (hr == S_OK) {
00262                 pDest->SetSyncPoint(TRUE);
00263         }
00264         else if (hr == S_FALSE) {
00265                 pDest->SetSyncPoint(FALSE);
00266         }
00267         else {  // an unexpected error has occured...
00268                 return E_UNEXPECTED;
00269         }
00270         
00271         // Copy the media type
00272         
00273         AM_MEDIA_TYPE *pMediaType;
00274         pSource->GetMediaType(&pMediaType);
00275         pDest->SetMediaType(pMediaType);
00276         DeleteMediaType(pMediaType);
00277         
00278         // Copy the preroll property
00279         
00280         hr = pSource->IsPreroll();
00281         if (hr == S_OK) {
00282                 pDest->SetPreroll(TRUE);
00283         }
00284         else if (hr == S_FALSE) {
00285                 pDest->SetPreroll(FALSE);
00286         }
00287         else {  // an unexpected error has occured...
00288                 return E_UNEXPECTED;
00289         }
00290         
00291         // Copy the discontinuity property
00292         hr = pSource->IsDiscontinuity();
00293         
00294         if (hr == S_OK)
00295                 pDest->SetDiscontinuity(TRUE);
00296         
00297         else if (hr == S_FALSE)
00298                 pDest->SetDiscontinuity(FALSE);
00299         
00300         else 
00301                 return E_UNEXPECTED; // an unexpected error has occured...
00302         
00303         // Copy the actual data length
00304         long lDataLength = pSource->GetActualDataLength();
00305         pDest->SetActualDataLength(lDataLength);
00306         
00307         return NOERROR;
00308 } // Copy
00309 
00310 // ================================================================
00311 
00312 // //////////////////////////////////////////////////////////////////// 
00313 //  This is where the MPColorTrackerFilter and tracking algorithm is implemented
00314 //  This is intended to be a very fast face tracker. 
00315 //  It is based on very primitive color, shape and motion information.
00316 //  This allows it to do its job very fast. However it will get confused
00317 //  by things that look like a flesh-colored blob and move.
00318 //  In applications the system should be complemented by a
00319 //  template/feature based face detection module 
00320 //
00321 //
00322 //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
00323 //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
00324 //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
00325 //  PURPOSE.
00326 //
00327 //  Original version developed by Boris E. Shpungin at UCSD's Machine Perception Lab
00328 //  Under the supersvision of Javier R. Movellan
00329 //  Copyright (c) Machine Perception Laboratory, UCSD
00330 //  Licensed under the GNU GPL agreement 
00332 HRESULT MPColorTrackerFilter::Transform(IMediaSample *pMediaSample)
00333 {
00334         AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType();
00335         VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat;
00336         
00337         BYTE *pData;                // Pointer to the actual image buffer
00338         pMediaSample->GetPointer(&pData);
00339         
00340         // Get the image properties from the BITMAPINFOHEADER
00341 
00342         m_imgWidth = pvi->bmiHeader.biWidth;
00343         m_imgHeight = pvi->bmiHeader.biHeight;
00344 
00345         m_interface.runInterface(pData, m_imgWidth, m_imgHeight);
00346 
00347         return NOERROR;
00348 }
00349 
00350 // ================================================================
00351 
00352 // Check the input type is OK - return an error otherwise
00353 HRESULT MPColorTrackerFilter::CheckInputType(const CMediaType *mtIn)
00354 {
00355         // check this is a VIDEOINFOHEADER type
00356         if (*mtIn->FormatType() != FORMAT_VideoInfo)
00357                 return E_INVALIDARG;
00358         // Can we transform this type
00359         if (CanPerformMPColorTrackerFilter(mtIn)) 
00360                 return NOERROR;
00361         return E_FAIL;
00362 }
00363 
00364 // ================================================================
00365 
00366 //
00367 // Checktransform
00368 //
00369 // Check a transform can be done between these formats
00370 //
00371 HRESULT MPColorTrackerFilter::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
00372 {
00373         if (CanPerformMPColorTrackerFilter(mtIn)) {
00374                 if (*mtIn == *mtOut)
00375                         return NOERROR;   
00376         }
00377         return E_FAIL;
00378 } // CheckTransform
00379 
00380 // ================================================================
00381 
00382 //
00383 // DecideBufferSize
00384 //
00385 // Tell the output pin's allocator what size buffers we
00386 // require. Can only do this when the input is connected
00387 //
00388 HRESULT MPColorTrackerFilter::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties)
00389 {
00390         // Is the input pin connected
00391         if (m_pInput->IsConnected() == FALSE)
00392                 return E_UNEXPECTED;
00393         ASSERT(pAlloc);
00394         ASSERT(pProperties);
00395         HRESULT hr = NOERROR;
00396         pProperties->cBuffers = 1;
00397         pProperties->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize();
00398         ASSERT(pProperties->cbBuffer);
00399         // Ask the allocator to reserve us some sample memory, NOTE the function
00400         // can succeed (that is return NOERROR) but still not have allocated the
00401         // memory that we requested, so we must check we got whatever we wanted
00402         ALLOCATOR_PROPERTIES Actual;
00403         hr = pAlloc->SetProperties(pProperties,&Actual);
00404         if (FAILED(hr))
00405                 return hr;
00406         ASSERT( Actual.cBuffers == 1 );
00407         if (pProperties->cBuffers > Actual.cBuffers ||
00408                 pProperties->cbBuffer > Actual.cbBuffer) {
00409                 return E_FAIL;  
00410         }
00411         return NOERROR;
00412 } // DecideBufferSize
00413 
00414 // ================================================================
00415 
00416 //
00417 // GetMediaType
00418 //
00419 // I support one type, namely the type of the input pin
00420 // This type is only available if my input is connected
00421 //
00422 HRESULT MPColorTrackerFilter::GetMediaType(int iPosition, CMediaType *pMediaType)
00423 {
00424         // Is the input pin connected
00425         if (m_pInput->IsConnected() == FALSE) 
00426                 return E_UNEXPECTED;
00427         // This should never happen
00428         if (iPosition < 0) 
00429                 return E_INVALIDARG;
00430         // Do we have more items to offer
00431         if (iPosition > 0)
00432                 return VFW_S_NO_MORE_ITEMS;
00433         *pMediaType = m_pInput->CurrentMediaType();
00434         return NOERROR;
00435 } // GetMediaType
00436 
00437 // ================================================================
00438 
00439 //
00440 // CanPerformMPColorTrackerFilter
00441 //
00442 // Check if this is a RGB24 true colour format
00443 //
00444 BOOL MPColorTrackerFilter::CanPerformMPColorTrackerFilter(const CMediaType *pMediaType) const
00445 {
00446         if (IsEqualGUID(*pMediaType->Type(), MEDIATYPE_Video)) {
00447                 if (IsEqualGUID(*pMediaType->Subtype(), MEDIASUBTYPE_RGB24)) {
00448                         VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pMediaType->Format();
00449                         return (pvi->bmiHeader.biBitCount == 24);
00450                 } 
00451         }
00452         return FALSE;
00453 } // CanPerformMPColorTrackerFilter
00454 
00455 // ================================================================
00456 
00457 #define WRITEOUT(var) hr = pStream->Write(&var, sizeof(var), NULL); \
00458 if (FAILED(hr)) return hr;
00459 
00460 #define READIN(var)   hr = pStream->Read(&var, sizeof(var), NULL); \
00461 if (FAILED(hr)) return hr;
00462 
00463 // ================================================================
00464 
00465 //
00466 // GetClassID
00467 //
00468 // This is the only method of IPersist
00469 //
00470 STDMETHODIMP MPColorTrackerFilter::GetClassID(CLSID *pClsid)
00471 {
00472         return CBaseFilter::GetClassID(pClsid);
00473 } // GetClassID
00474 
00475 // ================================================================
00476 
00477 //
00478 // ScribbleToStream
00479 //
00480 // Overriden to write our state into a stream
00481 //
00482 HRESULT MPColorTrackerFilter::ScribbleToStream(IStream *pStream)
00483 {
00484         HRESULT hr;
00485         WRITEOUT(m_effect);
00486         return NOERROR;
00487 } // ScribbleToStream
00488 
00489 // ================================================================
00490 
00491 //
00492 // ReadFromStream
00493 //
00494 // Likewise overriden to restore our state from a stream
00495 //
00496 HRESULT MPColorTrackerFilter::ReadFromStream(IStream *pStream)
00497 {
00498         HRESULT hr;
00499         READIN(m_effect);
00500         return NOERROR;
00501 } // ReadFromStream
00502 
00503 // ================================================================
00504 
00505 //
00506 // GetPages
00507 //
00508 // Returns the clsid's of the property pages we support
00509 //
00510 STDMETHODIMP MPColorTrackerFilter::GetPages(CAUUID *pPages)
00511 {
00512         pPages->cElems = 1;
00513         pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
00514         if (pPages->pElems == NULL)
00515                 return E_OUTOFMEMORY; 
00516 //      *(pPages->pElems) = CLSID_MPColorTrackerFilterPropertyPage;
00517         return NOERROR;
00518 } // GetPages
00519 
00520 // ================================================================
00521 
00522 //
00523 // get_IPEffect
00524 //
00525 // Return the current effect selected
00526 //
00527 STDMETHODIMP MPColorTrackerFilter::get_IPEffect(int *IPEffect) //,REFTIME *start,REFTIME *length)
00528 {
00529         CAutoLock cAutolock(&m_MPColorTrackerFilterLock);
00530         CheckPointer(IPEffect,E_POINTER);
00531         //    CheckPointer(start,E_POINTER);
00532         //    CheckPointer(length,E_POINTER);
00533         *IPEffect = m_effect;
00534         //    *start = COARefTime(m_effectStartTime);
00535         //    *length = COARefTime(m_effectTime);
00536         return NOERROR;
00537 } // get_IPEffect
00538 
00539 // ================================================================
00540 
00541 //
00542 // put_IPEffect
00543 //
00544 // Set the required video effect
00545 //
00546 STDMETHODIMP MPColorTrackerFilter::put_IPEffect(int IPEffect) //,REFTIME start,REFTIME length)
00547 {
00548         CAutoLock cAutolock(&m_MPColorTrackerFilterLock);
00549         m_effect = IPEffect;
00550         //    m_effectStartTime = COARefTime(start);
00551         //    m_effectTime = COARefTime(length);
00552         SetDirty(TRUE);
00553         return NOERROR;
00554 } // put_IPEffect
00555 
00556 // ================================================================
00557 
00558 MPColorTrackerFilter::~MPColorTrackerFilter() {}
00559 
00560 // ================================================================
00561 
00562 /*
00563  * 
00564  * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
00565  * 
00566  *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00567  *    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.
00568  *    3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
00569  * 
00570  * 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.
00571  * 
00572  */

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