Move the sources to trunk
[opencv] / filters / Condens / Condens.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
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.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
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.
25 //
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.
28 //
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.
39 //
40 //M*/
41 #include <windows.h>
42 #include <cvstreams.h>
43 #include <initguid.h>
44 #include <olectl.h>
45 #if (1100 > _MSC_VER)
46 #include <olectlid.h>
47 #endif
48 #include "iCondens.h"
49 #include "Condensprop.h"
50 #include "Condens.h"
51 #include "Condensuids.h"
52 #include <math.h>
53
54 // setup data
55 const AMOVIESETUP_MEDIATYPE sudPinTypes =
56 {
57     &MEDIATYPE_Video,       // Major type
58     &MEDIASUBTYPE_NULL      // Minor type
59 };
60
61 const AMOVIESETUP_PIN psudPins[] =
62 {
63     {
64         L"Input",           // String pin name
65         FALSE,              // Is it rendered
66         FALSE,              // Is it an output
67         FALSE,              // Allowed none
68         FALSE,              // Allowed many
69         &CLSID_NULL,        // Connects to filter
70         L"Output",          // Connects to pin
71         1,                  // Number of types
72         &sudPinTypes },     // The pin details
73       { L"Output",          // String pin name
74         FALSE,              // Is it rendered
75         TRUE,               // Is it an output
76         FALSE,              // Allowed none
77         FALSE,              // Allowed many
78         &CLSID_NULL,        // Connects to filter
79         L"Input",           // Connects to pin
80         1,                  // Number of types
81         &sudPinTypes        // The pin details
82     }
83 };
84
85
86 const AMOVIESETUP_FILTER sudCCondens =
87 {
88     &CLSID_CCondens,        // Filter CLSID
89     L"Condens",                    // Filter name
90     MERIT_DO_NOT_USE,               // Its merit
91     2,                              // Number of pins
92     psudPins                        // Pin details
93 };
94
95
96 // List of class IDs and creator functions for the class factory. This
97 // provides the link between the OLE entry point in the DLL and an object
98 // being created. The class factory will call the static CreateInstance
99
100 CFactoryTemplate g_Templates[2] = {
101
102     { L"Condens"
103     , &CLSID_CCondens
104     , CCondens::CreateInstance
105     , NULL
106     , &sudCCondens }
107   ,
108     { L"Condens Property Page"
109     , &CLSID_CCondensPropertyPage
110     , CCondensProperties::CreateInstance }
111 };
112 int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
113
114
115
116 //
117 // Constructor
118 //
119 CCondens::CCondens(TCHAR *tszName,LPUNKNOWN punk,HRESULT *phr) :
120     CTransInPlaceFilter(tszName, punk, CLSID_CCondens,phr)    
121    
122 {
123     m_params.nSamples = 64;
124     m_params.x = 0.4f; 
125     m_params.y = 0.3f;
126     m_params.width = 0.2f;
127     m_params.height = 0.3f;
128
129     m_params.Smin = 20;
130     m_params.Vmin = 40;
131     m_params.view = 0;
132
133     m_Indicat1.x = 0; 
134     m_Indicat1.y = 0;
135     m_Indicat1.width = 100;
136     m_Indicat1.height = 60;
137     IsTracking = false;
138     IsInit =false;
139     ConDens=cvCreateConDensation(4,4,m_params.nSamples);
140     CvMat Dyn = cvMat(4,4,CV_MAT4x4_32F,ConDens->DynamMatr);
141     cvmSetIdentity(&Dyn);
142     cvmSet(&Dyn,0,1,0.9);
143     cvmSet(&Dyn,2,3,0.9);
144     ASSERT(tszName);
145     ASSERT(phr);
146 } // CCondens
147 CCondens::~CCondens()
148 {
149     cvReleaseConDensation(&ConDens);
150 } // ~CCondens
151
152
153 //
154 // CreateInstance
155 //
156 // Provide the way for COM to create a CCondens object
157 //
158 CUnknown * WINAPI CCondens::CreateInstance(LPUNKNOWN punk, HRESULT *phr) {
159
160     CCondens *pNewObject = new CCondens(NAME("Condens"), punk, phr);
161     if (pNewObject == NULL) {
162         *phr = E_OUTOFMEMORY;
163     }
164     return pNewObject;
165
166 } // CreateInstance
167
168
169 //
170 // NonDelegatingQueryInterface
171 //
172 // Reveals ICCondens and ISpecifyPropertyPages
173 //
174 STDMETHODIMP CCondens::NonDelegatingQueryInterface(REFIID riid, void **ppv)
175 {
176     CheckPointer(ppv,E_POINTER);
177
178     if (riid == IID_ICCondens) {
179         return GetInterface((ICCondens *) this, ppv);
180     } else if (riid == IID_ISpecifyPropertyPages) {
181         return GetInterface((ISpecifyPropertyPages *) this, ppv);
182     } else {
183         return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);
184     }
185
186 } // NonDelegatingQueryInterface
187
188
189
190 void  CCondens::ApplyCamShift( CvImage* image, bool initialize )
191 {
192     CvSize size;
193     int bins = 20;
194
195     m_cCamShift.set_hist_dims( 1, &bins );
196     m_cCamShift.set_hist_bin_range( 0, 1, 180 );
197     m_cCamShift.set_min_ch_val( 1, m_params.Smin );
198     m_cCamShift.set_max_ch_val( 1, 255 );
199     m_cCamShift.set_min_ch_val( 2, m_params.Vmin );
200     m_cCamShift.set_max_ch_val( 2, 255 );
201     
202     cvGetImageRawData( image, 0, 0, &size );
203     
204     if( m_object.x > size.width - m_object.width - 1 )
205         m_object.x = size.width - m_object.width - 1;
206     if( m_object.x < 0 ) m_object.x = 0;
207     
208     if( m_object.y > size.height - m_object.height - 1 )
209         m_object.y = size.height - m_object.height - 1;
210     if( m_object.y < 0 ) m_object.y = 0;
211     m_cCamShift.set_window(m_object);
212     
213     if( initialize )
214     {
215         m_cCamShift.reset_histogram();
216         m_cCamShift.update_histogram( image );
217     }
218
219     m_cCamShift.track_object( image );
220     m_object = m_cCamShift.get_window();
221
222     LBound[0] = (float)m_object.x;
223     LBound[1] = (float)-m_object.width*0.5f;
224     LBound[2] = (float)m_object.y;
225     LBound[3] = (float)- m_object.height*0.5f;
226     UBound[0] = (float)m_object.x + m_object.width;
227     UBound[1] = (float)m_object.width*0.5f;
228     UBound[2] = (float)m_object.y + m_object.height;
229     UBound[3] = (float)m_object.height*0.5f;
230     Measurement[0] = (float)m_object.x+m_object.width*0.5f;
231     Measurement[1] = initialize ? 0 : (float)(Measurement[0] - m_Old.x);
232     Measurement[2] = (float)m_object.y+m_object.height*0.5f;
233     Measurement[3] = initialize ? 0 : (float)(Measurement[2] - m_Old.y);
234     m_Old.x = cvRound( Measurement[0] );
235     m_Old.y = cvRound( Measurement[2] );
236     if( initialize )
237     {
238         CvMat LB = cvMat(4,1,CV_MAT4x1_32F,LBound);
239         CvMat UB = cvMat(4,1,CV_MAT4x1_32F,UBound);
240         cvConDensInitSampleSet(ConDens,&LB,&UB);
241     }
242     XCor = 1.5f/m_object.width;
243     VXCor = 3.0f/m_object.width;
244     YCor = 1.5f/m_object.height;
245     VYCor = 3.0f/m_object.height;
246     CondProbDens(ConDens,Measurement);
247
248     m_Old.x = cvRound( Measurement[0] );
249     m_Old.y = cvRound( Measurement[2] );
250 }
251
252
253 void  CCondens::CheckBackProject( CvImage* image )
254 {
255     if( m_params.view != 0 )
256     {
257         IplImage* src = m_cCamShift.get_back_project();
258         if( src && src->imageData && image )
259         {
260             cvCvtColor( src, image, CV_GRAY2BGR );
261         }
262     }
263 }
264
265
266 //
267 // Transform
268 // Transform the  sample 'in place'
269 //
270 HRESULT CCondens::Transform(IMediaSample *pSample)
271 {
272     BYTE*   pData;
273     CvImage image;
274
275     IplImage* image2;    //ianni  <======
276
277     pSample->GetPointer(&pData);
278
279     AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType();
280     VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat;
281
282     // Get the image properties from the BITMAPINFOHEADER
283     CvSize size = cvSize( pvi->bmiHeader.biWidth, pvi->bmiHeader.biHeight );
284     int stride = (size.width * 3 + 3) & -4;
285
286     image2=cvCreateImage(cvSize(100,100),IPL_DEPTH_8U, 3);  //ianni <========
287     cvReleaseImage(&image2); //ianni <===========
288         
289     cvInitImageHeader( &image, size, IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );
290     cvSetImageData( &image, pData,stride );
291
292     if(IsTracking == false)
293     {
294         if(IsInit == false)
295         {
296             CvPoint p1, p2;
297             // Draw box
298             p1.x = cvRound( size.width * m_params.x );
299             p1.y = cvRound( size.height * m_params.y );
300
301             p2.x = cvRound( size.width * (m_params.x + m_params.width));
302             p2.y = cvRound( size.height * (m_params.y + m_params.height));
303
304             CheckBackProject( &image );
305
306             cvRectangle( &image, p1, p2, -1, 1 );
307         }
308         else
309         {
310             m_object.x = cvRound( size.width * m_params.x );
311             m_object.y = cvRound( size.height * m_params.y );
312             m_object.width = cvRound( size.width * m_params.width );
313             m_object.height = cvRound( size.height * m_params.height );
314             ApplyCamShift( &image, true );
315
316             CheckBackProject( &image );
317
318             IsTracking = true;
319         }
320     }
321     else
322     {
323         cvConDensUpdateByTime(ConDens);
324         m_object.x = cvRound( ConDens->State[0]-m_object.width*0.5);
325         m_object.y = cvRound( ConDens->State[2]-m_object.height*0.5 );
326         
327         ApplyCamShift( &image, false );
328
329         CheckBackProject( &image );
330
331         cvRectangle( &image,
332                      cvPoint( m_object.x, m_object.y ),
333                      cvPoint( m_object.x + m_object.width, m_object.y + m_object.height ),
334                      -1, 1 );
335         
336         Rectang(&image,m_Indicat1,-1);
337         m_X.x = 10;
338         m_X.y = 10;
339         m_X.width=50*m_Old.x/size.width;
340         m_X.height =10;
341         Rectang(&image,m_X,CV_RGB(0,0,255));
342         m_Y.x = 10;
343         m_Y.y = 10;
344         m_Y.width=10;
345         m_Y.height = 50*m_Old.y/size.height;
346         Rectang(&image,m_Y,CV_RGB(255,0,0));
347         m_Indicat2.x = 0; 
348         m_Indicat2.y = size.height-50;
349         m_Indicat2.width = 50;
350         m_Indicat2.height = 50;
351         Rectang(&image,m_Indicat2,-1);
352         float Norm = cvSqrt(Measurement[1]*Measurement[1]+Measurement[3]*Measurement[3]);
353         int VXNorm = (fabs(Measurement[1])>5)?(int)(12*Measurement[1]/Norm):0;
354         int VYNorm = (fabs(Measurement[3])>5)?(int)(12*Measurement[3]/Norm):0;
355         CvPoint pp1 = {25,size.height-25};
356         CvPoint pp2 = {25+VXNorm,size.height-25+VYNorm};
357         cvLine(&image,pp1,pp2,CV_RGB(0,0,0),3);
358     }
359
360     cvSetImageData( &image, 0, 0 );
361     return NOERROR;
362 }
363
364
365 //
366 // CheckInputType
367 //
368 // Check the input type is OK, return an error otherwise
369 //
370 HRESULT CCondens::CheckInputType(const CMediaType *mtIn)
371 {
372     // Check this is a VIDEOINFO type
373
374     if (*mtIn->FormatType() != FORMAT_VideoInfo)
375     {
376         
377     }
378     if ((IsEqualGUID(*mtIn->Type(), MEDIATYPE_Video))
379         && (IsEqualGUID(*mtIn->Subtype(), MEDIASUBTYPE_RGB24)))return NOERROR;
380     return E_INVALIDARG;
381
382
383 } // CheckInputType
384
385
386
387 // CheckTransform
388 //
389 // To be able to transform the formats must be identical
390 //
391
392 HRESULT CCondens::CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut)
393 {
394     HRESULT hr;
395     if (FAILED(hr = CheckInputType(mtIn))) {
396     return hr;
397     }
398
399     // format must be a VIDEOINFOHEADER
400     if (*mtOut->FormatType() != FORMAT_VideoInfo) {
401     return E_INVALIDARG;
402     }
403     
404     // formats must be big enough 
405     if (mtIn->FormatLength() < sizeof(VIDEOINFOHEADER) ||
406     mtOut->FormatLength() < sizeof(VIDEOINFOHEADER))
407     return E_INVALIDARG;
408     
409     VIDEOINFO *pInput = (VIDEOINFO *) mtIn->Format();
410     VIDEOINFO *pOutput = (VIDEOINFO *) mtOut->Format();
411     if (memcmp(&pInput->bmiHeader,&pOutput->bmiHeader,sizeof(BITMAPINFOHEADER)) == 0) {
412     return NOERROR;
413     }
414
415     return E_INVALIDARG;
416 } // CheckTransform
417
418
419 //
420 // DecideBufferSize
421 //
422 // Tell the output pin's allocator what size buffers we
423 // require. Can only do this when the input is connected
424 //
425 HRESULT CCondens::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties)
426 {
427     // Is the input pin connected
428
429     if (m_pInput->IsConnected() == FALSE) {
430         return E_UNEXPECTED;
431     }
432
433     ASSERT(pAlloc);
434     ASSERT(pProperties);
435     return NOERROR;
436
437 } // DecideBufferSize
438
439
440 //
441 // GetMediaType
442 //
443 // I support one type, namely the type of the input pin
444 // We must be connected to support the single output type
445 //
446 HRESULT CCondens::GetMediaType(int iPosition, CMediaType *pMediaType)
447 {
448     // Is the input pin connected
449
450     if (m_pInput->IsConnected() == FALSE) {
451         return E_UNEXPECTED;
452     }
453
454     // This should never happen
455
456     if (iPosition < 0) {
457         return E_INVALIDARG;
458     }
459
460     // Do we have more items to offer
461
462     if (iPosition > 0) {
463         return VFW_S_NO_MORE_ITEMS;
464     }
465
466     *pMediaType = m_pInput->CurrentMediaType();
467     return NOERROR;
468
469 } // GetMediaType
470
471
472 STDMETHODIMP CCondens::GetParams( CvCondensParams* params )
473 {
474     if( params )
475     {
476         *params = m_params;
477     }
478     return NOERROR;
479 }
480
481
482 STDMETHODIMP CCondens::SetParams( CvCondensParams* params )
483 {
484     CAutoLock cAutoLock(&m_CCondensLock);
485     if( params )
486     {
487         m_params = *params;
488     }
489     return NOERROR;
490 }
491
492
493 STDMETHODIMP CCondens::GetState(bool* State)
494 {
495     *State = IsTracking;    
496     return NOERROR;
497 }
498
499
500 STDMETHODIMP CCondens::StartTracking()
501 {
502     CAutoLock cAutoLock(&m_CCondensLock);
503     IsInit = true;
504     IsTracking = false;
505     return NOERROR;
506 }
507
508 STDMETHODIMP CCondens::StopTracking()
509 {
510     CAutoLock cAutoLock(&m_CCondensLock);
511     IsInit = IsTracking = false;
512     return NOERROR;
513 }
514
515 CCondens::Rectang(IplImage* img, CvRect Rect, int color)
516 {
517     
518     for( int j = 0; j < Rect.height; j++ )
519     {
520         CvPoint p1={Rect.x,Rect.y+j};
521         CvPoint p2={Rect.x+Rect.width,Rect.y+j};
522         cvLine(img,p1,p2,color);
523     }
524         
525 }
526 //
527 // GetPages
528 //
529 CCondens::CondProbDens(CvConDensation* CD,  float* Measurement)
530 {
531     float Prob = 1;
532     for(int i = 0; i < CD->SamplesNum;i++)
533     {
534         
535         Prob =1;
536         Prob*=(float)exp(-XCor*XCor*(Measurement[0] - CD->flSamples[i][0])*(Measurement[0]-CD->flSamples[i][0]));
537         Prob*=(float)exp(-VXCor*VXCor*(Measurement[1] - CD->flSamples[i][1])*(Measurement[1]-CD->flSamples[i][1]));
538         Prob*=(float)exp(-YCor*YCor*(Measurement[2] - CD->flSamples[i][2])*(Measurement[2]-CD->flSamples[i][2]));
539         Prob*=(float)exp(-VYCor*VYCor*(Measurement[3] - CD->flSamples[i][3])*(Measurement[3]-CD->flSamples[i][3]));
540         CD->flConfidence[i] = Prob;
541     }
542 }
543 // This is the sole member of ISpecifyPropertyPages
544 // Returns the clsid's of the property pages we support
545 //
546
547 STDMETHODIMP CCondens::GetPages(CAUUID *pPages)
548 {
549     pPages->cElems = 1;
550     pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
551     if (pPages->pElems == NULL) {
552         return E_OUTOFMEMORY;
553     }
554     *(pPages->pElems) = CLSID_CCondensPropertyPage;
555     return NOERROR;
556
557 } // GetPages
558
559 //
560 // DllRegisterServer
561 //
562 // Handle registration of this filter
563 //
564 STDAPI DllRegisterServer()
565 {
566     return AMovieDllRegisterServer2( TRUE );
567
568 } // DllRegisterServer
569
570
571 //
572 // DllUnregisterServer
573 //
574 STDAPI DllUnregisterServer()
575 {
576    return AMovieDllRegisterServer2( FALSE );
577
578 } // DllUnregisterServer