1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
42 #include <cvstreams.h>
50 #include "CamShiftUIDs.h"
52 #include "iCamShift.h"
53 #include "CamShiftProp.h"
54 #include "CamShiftF.h"
59 const AMOVIESETUP_MEDIATYPE sudPinTypes =
61 &MEDIATYPE_Video, // Major type
62 &MEDIASUBTYPE_NULL // Minor type
65 const AMOVIESETUP_PIN psudPins[] =
68 L"Input", // String pin name
69 FALSE, // Is it rendered
70 FALSE, // Is it an output
71 FALSE, // Allowed none
72 FALSE, // Allowed many
73 &CLSID_NULL, // Connects to filter
74 L"Output", // Connects to pin
76 &sudPinTypes }, // The pin details
77 { L"Output", // String pin name
78 FALSE, // Is it rendered
79 TRUE, // Is it an output
80 FALSE, // Allowed none
81 FALSE, // Allowed many
82 &CLSID_NULL, // Connects to filter
83 L"Input", // Connects to pin
85 &sudPinTypes // The pin details
90 const AMOVIESETUP_FILTER sudCamShift =
92 &CLSID_CamShift, // Filter CLSID
93 L"CamShift", // Filter name
94 MERIT_DO_NOT_USE, // Its merit
96 psudPins // Pin details
100 // List of class IDs and creator functions for the class factory. This
101 // provides the link between the OLE entry point in the DLL and an object
102 // being created. The class factory will call the static CreateInstance
104 CFactoryTemplate g_Templates[2] = {
108 , CCamShiftF::CreateInstance
112 { L"CamShift Property Page"
113 , &CLSID_CamShiftPropertyPage
114 , CCamShiftProperties::CreateInstance }
116 int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
122 CCamShiftF::CCamShiftF(TCHAR *tszName,LPUNKNOWN punk,HRESULT *phr) :
123 CTransformFilter(tszName, punk, CLSID_CamShift)
127 m_params.width = 0.2f;
128 m_params.height = 0.3f;
135 m_params.threshold = 0;
145 // Provide the way for COM to create a CCamShift object
147 CUnknown * WINAPI CCamShiftF::CreateInstance(LPUNKNOWN punk, HRESULT *phr) {
149 CCamShiftF *pNewObject = new CCamShiftF(NAME("CamShift"), punk, phr);
150 if (pNewObject == NULL) {
151 *phr = E_OUTOFMEMORY;
159 // NonDelegatingQueryInterface
161 // Reveals ICamShift and ISpecifyPropertyPages
163 STDMETHODIMP CCamShiftF::NonDelegatingQueryInterface(REFIID riid, void **ppv)
165 CheckPointer(ppv,E_POINTER);
167 if (riid == IID_ICamShift) {
168 return GetInterface((ICamShift *) this, ppv);
169 } else if (riid == IID_ISpecifyPropertyPages) {
170 return GetInterface((ISpecifyPropertyPages *) this, ppv);
172 return CTransformFilter::NonDelegatingQueryInterface(riid, ppv);
175 } // NonDelegatingQueryInterface
181 // Copy the input sample into the output sample
182 // Then transform the output sample 'in place'
184 HRESULT CCamShiftF::Transform(IMediaSample *pIn, IMediaSample *pOut)
186 HRESULT hr = Copy(pIn, pOut);
190 return Transform(pOut);
198 // Make destination an identical copy of source
200 HRESULT CCamShiftF::Copy(IMediaSample *pSource, IMediaSample *pDest) const
202 // Copy the sample data
204 BYTE *pSourceBuffer, *pDestBuffer;
205 long lSourceSize = pSource->GetActualDataLength();
206 long lDestSize = pDest->GetSize();
208 ASSERT(lDestSize >= lSourceSize);
210 pSource->GetPointer(&pSourceBuffer);
211 pDest->GetPointer(&pDestBuffer);
213 CopyMemory( (PVOID) pDestBuffer,(PVOID) pSourceBuffer,lSourceSize);
215 // Copy the sample times
217 REFERENCE_TIME TimeStart, TimeEnd;
218 if (NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) {
219 pDest->SetTime(&TimeStart, &TimeEnd);
222 LONGLONG MediaStart, MediaEnd;
223 if (pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) {
224 pDest->SetMediaTime(&MediaStart,&MediaEnd);
227 // Copy the Sync point property
229 HRESULT hr = pSource->IsSyncPoint();
231 pDest->SetSyncPoint(TRUE);
233 else if (hr == S_FALSE) {
234 pDest->SetSyncPoint(FALSE);
236 else { // an unexpected error has occured...
240 // Copy the media type
242 AM_MEDIA_TYPE *pMediaType;
243 pSource->GetMediaType(&pMediaType);
244 pDest->SetMediaType(pMediaType);
245 DeleteMediaType(pMediaType);
247 // Copy the preroll property
249 hr = pSource->IsPreroll();
251 pDest->SetPreroll(TRUE);
253 else if (hr == S_FALSE) {
254 pDest->SetPreroll(FALSE);
256 else { // an unexpected error has occured...
260 // Copy the discontinuity property
262 hr = pSource->IsDiscontinuity();
264 pDest->SetDiscontinuity(TRUE);
266 else if (hr == S_FALSE) {
267 pDest->SetDiscontinuity(FALSE);
269 else { // an unexpected error has occured...
273 // Copy the actual data length
275 long lDataLength = pSource->GetActualDataLength();
276 pDest->SetActualDataLength(lDataLength);
282 void CCamShiftF::ApplyCamShift( IplImage* image, bool initialize )
285 int bins = m_params.bins;
287 m_cCamShift.set_hist_dims( 1, &bins );
288 m_cCamShift.set_hist_bin_range( 0, 0, 180 );
289 m_cCamShift.set_threshold( 0 );
290 m_cCamShift.set_min_ch_val( 1, m_params.Smin );
291 m_cCamShift.set_max_ch_val( 1, 255 );
292 m_cCamShift.set_min_ch_val( 2, m_params.Vmin );
293 m_cCamShift.set_max_ch_val( 2, m_params.Vmax );
295 cvGetImageRawData( image, 0, 0, &size );
297 if( m_object.x < 0 ) m_object.x = 0;
298 if( m_object.x > size.width - m_object.width - 1 )
299 m_object.x = MAX(0, size.width - m_object.width - 1);
301 if( m_object.y < 0 ) m_object.y = 0;
302 if( m_object.y > size.height - m_object.height - 1 )
303 m_object.y = MAX(0, size.height - m_object.height - 1);
305 if( m_object.width > size.width - m_object.x )
306 m_object.width = MIN(size.width, size.width - m_object.x);
308 if( m_object.height > size.height - m_object.y )
309 m_object.height = MIN(size.height, size.height - m_object.y);
311 m_cCamShift.set_window(m_object);
315 m_cCamShift.reset_histogram();
316 m_cCamShift.update_histogram( image );
319 m_cCamShift.track_object( image );
320 m_object = m_cCamShift.get_window();
324 void CCamShiftF::CheckBackProject( IplImage* image )
326 if( m_params.view == 1 )
328 IplImage* src = m_cCamShift.get_back_project();
329 if( src && src->imageData && image )
331 cvCvtColor( src, image, CV_GRAY2BGR );
334 else if( m_params.view == 2 && IsTracking )
339 m_cCamShift.get_hist_dims( &dims );
340 cvGetImageRawData( image, 0, 0, &size );
342 for( i = 0; i < dims; i++ )
344 int val = cvRound(m_cCamShift.query(&i));
347 p[0].x = p[1].x = i*size.width/(2*dims);
348 p[2].x = p[3].x = (i+1)*size.width/(2*dims);
351 p[0].y = p[3].y = (val*size.height)/(3*255);
353 cvFillConvexPoly( image, p, 4, CV_RGB(255,0,0));
359 void CCamShiftF::DrawCross( IplImage* image )
361 float cs = (float)cos( m_cCamShift.get_orientation() );
362 float sn = (float)sin( m_cCamShift.get_orientation() );
364 int x = m_object.x + m_object.width / 2;
365 int y = m_object.y + m_object.height / 2;
367 CvPoint p1 = {(int)(x + m_cCamShift.get_length() * cs / 2),
368 (int)(y + m_cCamShift.get_length() * sn / 2)};
369 CvPoint p2 = {(int)(x - m_cCamShift.get_length() * cs / 2),
370 (int)(y - m_cCamShift.get_length() * sn / 2)};
371 CvPoint p3 = {(int)(x + m_cCamShift.get_width() * sn / 2),
372 (int)(y - m_cCamShift.get_width() * cs / 2)};
373 CvPoint p4 = {(int)(x - m_cCamShift.get_width() * sn / 2),
374 (int)(y + m_cCamShift.get_width() * cs / 2)};
375 cvLine( image, p1, p2, CV_RGB(255,255,255) );
376 cvLine( image, p4, p3, CV_RGB(255,255,255) );
383 // 'In place' adjust the CamShift of this sample
385 HRESULT CCamShiftF::Transform(IMediaSample *pMediaSample)
390 pMediaSample->GetPointer(&pData);
392 AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType();
393 VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat;
395 // Get the image properties from the BITMAPINFOHEADER
396 CvSize size = cvSize( pvi->bmiHeader.biWidth, pvi->bmiHeader.biHeight );
397 int stride = (size.width * 3 + 3) & -4;
399 cvInitImageHeader( &image, size, IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
400 cvSetImageData( &image, pData, stride );
402 if(IsTracking == false)
408 p1.x = cvRound( size.width * m_params.x );
409 p1.y = cvRound( size.height * m_params.y );
411 p2.x = cvRound( size.width * (m_params.x + m_params.width));
412 p2.y = cvRound( size.height * (m_params.y + m_params.height));
414 CheckBackProject( &image );
416 cvRectangle( &image, p1, p2, -1, 1 );
420 m_object.x = cvRound( size.width * m_params.x );
421 m_object.y = cvRound( size.height * m_params.y );
422 m_object.width = cvRound( size.width * m_params.width );
423 m_object.height = cvRound( size.height * m_params.height );
425 assert( image.roi == 0 );
426 cvSetImageROI( &image, cvRect( m_object.x, m_object.y, m_object.width, m_object.height ));
427 double norm = cvNorm( &image, 0, CV_L1 );
428 cvResetImageROI( &image );
430 ApplyCamShift( &image, true );
431 CheckBackProject( &image );
438 ApplyCamShift( &image, false );
439 CheckBackProject( &image );
451 // Check the input type is OK, return an error otherwise
453 HRESULT CCamShiftF::CheckInputType(const CMediaType *mtIn)
455 // Check this is a VIDEOINFO type
457 if (*mtIn->FormatType() != FORMAT_VideoInfo) {
461 // Is this a palettised format
463 if (CanChangeCamShiftLevel(mtIn)) {
474 // To be able to transform the formats must be identical
476 HRESULT CCamShiftF::CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut)
479 if (FAILED(hr = CheckInputType(mtIn))) {
483 // format must be a VIDEOINFOHEADER
484 if (*mtOut->FormatType() != FORMAT_VideoInfo) {
488 // formats must be big enough
489 if (mtIn->FormatLength() < sizeof(VIDEOINFOHEADER) ||
490 mtOut->FormatLength() < sizeof(VIDEOINFOHEADER))
493 VIDEOINFO *pInput = (VIDEOINFO *) mtIn->Format();
494 VIDEOINFO *pOutput = (VIDEOINFO *) mtOut->Format();
495 if (memcmp(&pInput->bmiHeader,&pOutput->bmiHeader,sizeof(BITMAPINFOHEADER)) == 0) {
506 // Tell the output pin's allocator what size buffers we
507 // require. Can only do this when the input is connected
509 HRESULT CCamShiftF::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties)
511 // Is the input pin connected
513 if (m_pInput->IsConnected() == FALSE) {
519 HRESULT hr = NOERROR;
521 pProperties->cBuffers = 1;
522 pProperties->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize();
524 ASSERT(pProperties->cbBuffer);
526 // If we don't have fixed sized samples we must guess some size
528 if (!m_pInput->CurrentMediaType().bFixedSizeSamples) {
529 if (pProperties->cbBuffer < 100000) {
530 // nothing more than a guess!!
531 pProperties->cbBuffer = 100000;
535 // Ask the allocator to reserve us some sample memory, NOTE the function
536 // can succeed (that is return NOERROR) but still not have allocated the
537 // memory that we requested, so we must check we got whatever we wanted
539 ALLOCATOR_PROPERTIES Actual;
540 hr = pAlloc->SetProperties(pProperties,&Actual);
545 ASSERT( Actual.cBuffers == 1 );
547 if (pProperties->cBuffers > Actual.cBuffers ||
548 pProperties->cbBuffer > Actual.cbBuffer) {
553 } // DecideBufferSize
559 // I support one type, namely the type of the input pin
560 // We must be connected to support the single output type
562 HRESULT CCamShiftF::GetMediaType(int iPosition, CMediaType *pMediaType)
564 // Is the input pin connected
566 if (m_pInput->IsConnected() == FALSE) {
570 // This should never happen
576 // Do we have more items to offer
579 return VFW_S_NO_MORE_ITEMS;
583 *pMediaType = m_pInput->CurrentMediaType();
593 // This is the sole member of ISpecifyPropertyPages
594 // Returns the clsid's of the property pages we support
596 STDMETHODIMP CCamShiftF::GetPages(CAUUID *pPages)
599 pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
600 if (pPages->pElems == NULL) {
601 return E_OUTOFMEMORY;
603 *(pPages->pElems) = CLSID_CamShiftPropertyPage;
609 STDMETHODIMP CCamShiftF::GetParams( CvCamShiftParams* params )
619 STDMETHODIMP CCamShiftF::SetParams( CvCamShiftParams* params )
621 CAutoLock cAutoLock(&m_CamShiftLock);
631 STDMETHODIMP CCamShiftF::StartTracking()
633 CAutoLock cAutoLock(&m_CamShiftLock);
639 STDMETHODIMP CCamShiftF::StopTracking()
641 CAutoLock cAutoLock(&m_CamShiftLock);
642 IsInit = IsTracking = false;
647 // CanChangeCamShiftLevel
649 // Check if this is a paletised format
651 BOOL CCamShiftF::CanChangeCamShiftLevel(const CMediaType *pMediaType) const
653 if ((IsEqualGUID(*pMediaType->Type(), MEDIATYPE_Video))
654 && (IsEqualGUID(*pMediaType->Subtype(), MEDIASUBTYPE_RGB24))) {
656 // I think I can process this format (8 bit palettised)
657 // So do a quick sanity check on the palette information
659 VIDEOINFO *pvi = (VIDEOINFO *) pMediaType->Format();
660 return (pvi->bmiHeader.biBitCount == 24);
665 } // CanChangeCamShiftLevel
672 // Handle registration of this filter
674 STDAPI DllRegisterServer()
676 return AMovieDllRegisterServer2( TRUE );
678 } // DllRegisterServer
682 // DllUnregisterServer
684 STDAPI DllUnregisterServer()
686 return AMovieDllRegisterServer2( FALSE );
688 } // DllUnregisterServer