Rev Author Line No. Line
178 kaklik 1 #include <QtGui/QFileDialog>
2 #include <QtGui/QMessageBox>
3 #include "image.h"
4 #include "image_op.h"
5 #include "rgba.h"
6 #include "calibrateWidget.hh"
7 #include "crossWidget.hh"
8 #include "mandoWizard.hh"
9 #include "selectRectWidget.hh"
10 #include "tools.hh"
11 #include "videoWidget.hh"
12 #include "image_funcs.h"
13  
14 #define CALIBDELAY 900
15  
16 using namespace mimas;
17 using namespace std;
18  
19 MandoWizard::MandoWizard( QWidget *parent, Qt::WFlags f ):
20 QDialog( parent, f ), videoTimer(0), calibrateWidget(NULL), calibTimer(0),
21 segmentationTimer(0), pointerTimer(0)
22 {
23 ui.setupUi( this );
24  
25 // Finalise GUI.
26 videoWidget = new VideoWidget;
27 ui.videoDisplay->setWidget( videoWidget );
28 searchPatternWidget = new VideoWidget;
29 ui.searchPatternDisplay->setWidget( searchPatternWidget );
30 projectedPatternWidget = new VideoWidget;
31 ui.projectedPatternDisplay->setWidget( projectedPatternWidget );
32 calibFrameWidget = new CrossWidget;
33 ui.calibFrameDisplay->setWidget( calibFrameWidget );
34 referenceImageWidget = new SelectRectWidget;
35 ui.referenceImageDisplay->setWidget( referenceImageWidget );
36 segmentedWidget = new CrossWidget;
37 ui.segmentedDisplay->setWidget( segmentedWidget );
38  
39 // Connect signals and slots.
40 connect( ui.brightnessSlider, SIGNAL(valueChanged(int)),
41 this, SLOT(setCameraParameters()) );
42 connect( ui.hueSlider, SIGNAL(valueChanged(int)),
43 this, SLOT(setCameraParameters()) );
44 connect( ui.colourSlider, SIGNAL(valueChanged(int)),
45 this, SLOT(setCameraParameters()) );
46 connect( ui.contrastSlider, SIGNAL(valueChanged(int)),
47 this, SLOT(setCameraParameters()) );
48 connect( ui.shutterSlider, SIGNAL(valueChanged(int)),
49 this, SLOT(setCameraParameters()) );
50 connect( ui.gainSlider, SIGNAL(valueChanged(int)),
51 this, SLOT(setCameraParameters()) );
52 connect( ui.balanceSlider, SIGNAL(valueChanged(int)),
53 this, SLOT(setCameraParameters()) );
54 connect( ui.searchPatternButton, SIGNAL(clicked()),
55 this, SLOT(loadSearchPattern()) );
56 connect( ui.projectedPatternButton, SIGNAL(clicked()),
57 this, SLOT(loadProjectedPattern()) );
58 connect( ui.previousButton, SIGNAL(clicked()),
59 this, SLOT(previousPage()) );
60 connect( ui.nextButton, SIGNAL(clicked()),
61 this, SLOT(nextPage()) );
62 connect( ui.cancelButton, SIGNAL(clicked()),
63 this, SLOT(reject()) );
64 connect( ui.finishButton, SIGNAL(clicked()),
65 this, SLOT(accept()) );
66 connect( ui.reconnectButton, SIGNAL(clicked()),
67 this, SLOT(reconnectCamera()) );
68 connect( ui.calibrateButton, SIGNAL(clicked()),
69 this, SLOT(calibrate()) );
70 connect( ui.calibrateSlider, SIGNAL(valueChanged(int)),
71 this, SLOT(displayCalibFrame(int)) );
72 connect( ui.differenceCheckBox, SIGNAL(toggled(bool)),
73 this, SLOT(displayDifference(bool)) );
74 connect( ui.grabButton, SIGNAL(clicked()),
75 this, SLOT(grabReferenceImage()) );
76 connect( referenceImageWidget, SIGNAL(rectDefined(bool)),
77 this, SLOT(updateEnabled()) );
78 connect( ui.thresholdSlider, SIGNAL(valueChanged(int)),
79 this, SLOT(setThreshold(int)) );
80 connect( ui.sigmaSpinBox, SIGNAL(valueChanged(double)),
81 this, SLOT(setSigma(double)) );
82 connect( ui.rangeSlider, SIGNAL(valueChanged(int)),
83 this, SLOT(setRange(int)) );
84  
85 // Load default patterns.
86 searchPatternWidget->setImage
87 ( qImageToMimasImage
88 ( QImage( ":/images/searchPattern.png" ) ) );
89 projectedPatternWidget->setImage
90 ( qImageToMimasImage
91 ( QImage( ":/images/projectedPattern.png" ) ) );
92  
93 showPage( 0 );
94 }
95  
96 void MandoWizard::previousPage()
97 {
98 showPage( ui.stackedWidget->currentIndex() - 1 );
99 }
100  
101 void MandoWizard::nextPage()
102 {
103 showPage( ui.stackedWidget->currentIndex() + 1 );
104 }
105  
106 void MandoWizard::showPage( int index )
107 {
108 // Check index.
109 assert( index >= 0 );
110 assert( index < ui.stackedWidget->count() );
111  
112 // Update title.
113 switch ( index ) {
114 case 0:
115 ui.titleLabel->setText( "Adjust camera position" );
116 break;
117 case 1:
118 ui.titleLabel->setText( "Select calibration patterns" );
119 break;
120 case 2:
121 ui.titleLabel->setText( "Perform calibration" );
122 break;
123 case 3:
124 ui.titleLabel->setText( "Capture image and select reference image for "
125 "colour segmentation and select" );
126 break;
127 case 4:
128 ui.titleLabel->setText( "Set parameters for pointer recognition" );
129 break;
130 case 5:
131 ui.titleLabel->setText( "Set parameters for mouse-clicks" );
132 break;
133 default:
134 assert( false );
135 };
136  
137 // Show page.
138 ui.stackedWidget->setCurrentIndex( index );
139  
140 // Enable/disable controls.
141 updateEnabled();
142  
143 // Set up video display.
144 setupVideo();
145 }
146  
147 void MandoWizard::setupVideo(void)
148 {
149 int index = ui.stackedWidget->currentIndex();
150 if ( index == 0 ) {
151 if ( videoTimer == 0 )
152 videoTimer = startTimer( 0 );
153 } else
154 if ( videoTimer != 0 ) {
155 killTimer( videoTimer );
156 videoTimer = 0;
157 };
158 if ( index == 4 ) {
159 if ( segmentationTimer == 0 )
160 segmentationTimer = startTimer( 0 );
161 } else
162 if ( segmentationTimer != 0 ) {
163 killTimer( segmentationTimer );
164 segmentationTimer = 0;
165 };
166 if ( index == 5 ) {
167 if ( pointerTimer == 0 )
168 pointerTimer = startTimer( 0 );
169 } else
170 if ( pointerTimer != 0 ) {
171 killTimer( pointerTimer );
172 pointerTimer = 0;
173 };
174 }
175  
176 void MandoWizard::updateEnabled(void)
177 {
178 // Enable/disable controls.
179 int index = ui.stackedWidget->currentIndex();
180 ui.previousButton->setEnabled( index > 0 );
181 ui.finishButton->setEnabled( index == 5 );
182 ui.brightnessSlider->setEnabled( (bool)v4lInput );
183 ui.hueSlider->setEnabled( (bool)v4lInput );
184 ui.colourSlider->setEnabled( (bool)v4lInput );
185 ui.contrastSlider->setEnabled( (bool)v4lInput );
186 ui.shutterSlider->setEnabled( (bool)dc1394Input );
187 ui.gainSlider->setEnabled( (bool)dc1394Input );
188 ui.balanceSlider->setEnabled( (bool)dc1394Input );
189  
190 switch ( index ) {
191 case 0:
192 ui.nextButton->setEnabled( (bool)input );
193 break;
194 case 1:
195 ui.nextButton->setEnabled
196 ( searchPatternWidget->getImage().initialised() &&
197 projectedPatternWidget->getImage().initialised() );
198 break;
199 case 2: {
200 bool calibFinished;
201 if ( cameraProjectorCalibration )
202 calibFinished = cameraProjectorCalibration->getNumCalibFrames() >= 5;
203 else
204 calibFinished = false;
205 ui.nextButton->setEnabled( calibFinished );
206 ui.selectImageLabel->setEnabled( calibFinished );
207 ui.calibrateSlider->setEnabled( calibFinished );
208 ui.differenceCheckBox->setEnabled( calibFinished );
209 break;}
210 case 3:
211 ui.nextButton->setEnabled( referenceImageWidget->isRectDefined() );
212 if ( !referenceImageWidget->isRectDefined() )
213 pointerRecognition.reset();
214 break;
215 case 4:
216 ui.nextButton->setEnabled( true );
217 break;
218 case 5:
219 ui.nextButton->setEnabled( false );
220 break;
221 default:
222 assert( false );
223 };
224 }
225  
226 void MandoWizard::loadSearchPattern()
227 {
228 image< rgba< unsigned char > > img;
229 if ( loadImage( "Load search pattern", img ) ) {
230 searchPatternWidget->setImage( img );
231 cameraProjectorCalibration.reset();
232 pointerRecognition.reset();
233 updateEnabled();
234 };
235 }
236  
237 void MandoWizard::loadProjectedPattern()
238 {
239 image< rgba< unsigned char > > img;
240 if ( loadImage( "Load projected pattern", img ) ) {
241 projectedPatternWidget->setImage( img );
242 cameraProjectorCalibration.reset();
243 pointerRecognition.reset();
244 updateEnabled();
245 };
246 }
247  
248 void MandoWizard::reconnectCamera()
249 {
250 input.reset();
251 v4lInput.reset();
252 dc1394Input.reset();
253 cameraProjectorCalibration.reset();
254 pointerRecognition.reset();
255 referenceImageWidget->clearSelection();
256 assert( ui.stackedWidget->currentIndex() == 0 );
257 setupVideo();
258 }
259  
260 void MandoWizard::displayCalibFrame( int index )
261 {
262 displayCalibResult( index, ui.differenceCheckBox->isChecked() );
263 }
264  
265 void MandoWizard::displayDifference( bool diff )
266 {
267 displayCalibResult( ui.calibrateSlider->value(), diff );
268 }
269  
270 void MandoWizard::grabReferenceImage()
271 {
272 referenceImageWidget->setImage( grabColourFrame() );
273 updateEnabled();
274 }
275  
276 void MandoWizard::setThreshold( int _value )
277 {
278 assert( pointerRecognition );
279 assert( ui.thresholdSlider->minimum() == 0 );
280 pointerRecognition->setThreshold
281 ( 0.25 * _value / ui.thresholdSlider->maximum() );
282 }
283  
284 void MandoWizard::setRange( int _value )
285 {
286 assert( pointerRecognition );
287 pointerRecognition->setTrackingRange( _value );
288 }
289  
290 void MandoWizard::setSigma( double _value )
291 {
292 pointerRecognition->setSigma( _value );
293 }
294  
295 void MandoWizard::displayCalibResult( int index, bool diff )
296 {
297 assert( cameraProjectorCalibration );
298 assert( index >= 0 &&
299 index < cameraProjectorCalibration->getNumCalibFrames() + 1 );
300 if ( index == 0 ) {
301 calibFrameWidget->setImage
302 ( cameraProjectorCalibration->getBackgroundFrame() );
303 calibFrameWidget->clearCross();
304 } else {
305 if ( diff )
306 calibFrameWidget->setImage
307 ( normalise( image< int >( cameraProjectorCalibration->
308 getCalibFrame( index - 1 ) ) -
309 image< int >( cameraProjectorCalibration->
310 getBackgroundFrame() ), 0, 255 ) );
311 else
312 calibFrameWidget->setImage
313 ( cameraProjectorCalibration->getCalibFrame( index - 1 ) );
314 calibFrameWidget->setCross
315 ( cameraProjectorCalibration->getCalibPointPair( index - 1 ).second );
316 };
317 }
318  
319 bool MandoWizard::loadImage( const char *title,
320 image< rgba< unsigned char > > &img )
321 {
322 bool retVal = false;
323 try {
324 QString s = QFileDialog::getOpenFileName( this, title,
325 ".",
326 "Images (*.png *.jpg);;"
327 "All Files (*)" );
328 if ( s != QString::null ) {
329 img = qImageToMimasImage( QImage( s ) );
330 MMERROR( img.initialised(), mimasexception, ,
331 "Error loading file \"" << (const char *)s.toLatin1()
332 << "\"." );
333 retVal = true;
334 };
335 } catch ( exception &e ) {
336 QMessageBox::critical( this, "Error loading image", e.what() );
337 };
338 return retVal;
339 }
340  
341 void MandoWizard::timerEvent( QTimerEvent *e )
342 {
343 if ( e->timerId() == videoTimer ) {
344 try {
345 videoWidget->setImage( grabColourFrame( false ) );
346 assert( ui.stackedWidget->currentIndex() == 0 );
347 } catch ( exception &e ) {
348 assert( videoTimer != 0 );
349 killTimer( videoTimer );
350 videoTimer = 0;
351 videoWidget->setImage( image< rgba< unsigned char > >() );
352 input.reset();
353 v4lInput.reset();
354 dc1394Input.reset();
355 ui.errorLabel->setText( e.what() );
356 updateEnabled();
357 };
358 } else if ( e->timerId() == calibTimer ) {
359 assert( calibrateWidget != NULL );
360 killTimer( calibTimer );
361 calibTimer = 0;
362 if ( !calibrateWidget->isVisible() ) {
363 delete calibrateWidget;
364 calibrateWidget = NULL;
365 cameraProjectorCalibration.reset();
366 pointerRecognition.reset();
367 } else {
368 switch ( calibState ) {
369 case Init:
370 calibrateWidget->setPattern( 0 );
371 calibState = First;
372 break;
373 case First:
374 cameraProjectorCalibration->setBackgroundFrame( grabFrame() );
375 calibrateWidget->setPattern( 1 );
376 calibState = Second;
377 break;
378 case Second:
379 cameraProjectorCalibration->addCalibFrame
380 ( grabFrame(), calibrateWidget->getPos( 1 ) );
381 calibrateWidget->setPattern( 2 );
382 calibState = Third;
383 break;
384 case Third:
385 cameraProjectorCalibration->addCalibFrame
386 ( grabFrame(), calibrateWidget->getPos( 2 ) );
387 calibrateWidget->setPattern( 3 );
388 calibState = Fourth;
389 break;
390 case Fourth:
391 cameraProjectorCalibration->addCalibFrame
392 ( grabFrame(), calibrateWidget->getPos( 3 ) );
393 calibrateWidget->setPattern( 4 );
394 calibState = Fifth;
395 break;
396 case Fifth:
397 cameraProjectorCalibration->addCalibFrame
398 ( grabFrame(), calibrateWidget->getPos( 4 ) );
399 calibrateWidget->setPattern( 5 );
400 calibState = Closing;
401 break;
402 case Closing:
403 cameraProjectorCalibration->addCalibFrame
404 ( grabFrame(), calibrateWidget->getPos( 5 ) );
405 calibrateWidget->setPattern( 0 );
406 calibState = Finished;
407 break;
408 default:
409 calibState = Init;
410 displayCalibFrame( ui.calibrateSlider->value() );
411 // Get size of screen.
412 // This is only done at this point, because directly after
413 // initialisation of calibrateWidget, calibrateWidget->width() and
414 // ..->height() will not have the correct valuies.
415 screenW = calibrateWidget->width();
416 screenH = calibrateWidget->height();
417 delete calibrateWidget;
418 calibrateWidget = NULL;
419 updateEnabled();
420 };
421 if ( calibState != Init )
422 calibTimer=startTimer( CALIBDELAY );
423 };
424 } else if ( e->timerId() == segmentationTimer ) {
425 if ( !pointerRecognition ) {
426 assert( cameraProjectorCalibration );
427 pointerRecognition =
428 PointerRecognitionPtr
429 ( new PointerRecognition( cameraProjectorCalibration,
430 referenceImageWidget->
431 selectedImage() ) );
432 setThreshold( ui.thresholdSlider->value() );
433 setSigma( ui.sigmaSpinBox->value() );
434 setRange( ui.rangeSlider->value() );
435 pointerRecognition->setClip( 0, 0, screenW, screenH );
436 };
437 Vector camPos( 3 ), pos( 3 );
438 image< rgba< unsigned char > > frame( grabColourFrame() );
439 if ( pointerRecognition->findPointer( frame, camPos, pos ) )
440 segmentedWidget->setCross( camPos );
441 else
442 segmentedWidget->clearCross();
443 segmentedWidget->setImage
444 ( pointerRecognition->getMinX(),
445 pointerRecognition->getMinY(),
446 frame.getWidth(),
447 frame.getHeight(),
448 pointerRecognition->getSegmentedImage() );
449 } else if ( e->timerId() == pointerTimer ) {
450 Vector camPos( 3 ), pos( 3 );
451 image< rgba< unsigned char > > frame( grabColourFrame() );
452 if ( pointerRecognition->findPointer( frame, camPos, pos ) ) {
453 // Display *d = XOpenDisplay( NULL );
454 // XTestFakeMotionEvent( d, DefaultScreen( d ),
455 // (int)pos[0], (int)pos[1], 0 );
456 // XCloseDisplay( d );
457 ui.mouseXLCD->setSegmentStyle( QLCDNumber::Flat );
458 ui.mouseYLCD->setSegmentStyle( QLCDNumber::Flat );
459 ui.mouseXLCD->display( (int)pos[0] );
460 ui.mouseYLCD->display( (int)pos[1] );
461 } else {
462 ui.mouseXLCD->setSegmentStyle( QLCDNumber::Outline );
463 ui.mouseYLCD->setSegmentStyle( QLCDNumber::Outline );
464 };
465 } else
466 QDialog::timerEvent( e );
467 }
468  
469 MandoWizard::VideoPtr MandoWizard::camera(void)
470 throw (mimas::mimasexception)
471 {
472 if ( !input ) {
473 if ( ui.cameraStack->currentIndex() == 0 ) {
474 __u16 norm;
475 switch ( ui.modeBox->currentIndex() ) {
476 case 0:
477 norm = VIDEO_MODE_PAL;
478 break;
479 case 1:
480 norm = VIDEO_MODE_NTSC;
481 break;
482 case 2:
483 norm = VIDEO_MODE_SECAM;
484 break;
485 case 3:
486 norm = VIDEO_MODE_AUTO;
487 break;
488 default:
489 norm = VIDEO_MODE_PAL;
490 };
491 v4lInput =
492 V4LInputPtr( new V4LInput( (const char *)ui.v4lDeviceEdit->
493 text().toLatin1(),
494 ui.v4lChannelSpinBox->value(),
495 -1, -1, norm ) );
496 input = v4lInput;
497 setCameraParameters();
498 ui.errorLabel->setText( "" );
499 updateEnabled();
500 } else {
501 dc1394Input =
502 DC1394InputPtr( new DC1394Input( (const char *)ui.dc1394DeviceEdit->
503 text().toLatin1(),
504 ui.dc1394NodeSpinBox->value(),
505 ui.dc1394ChannelSpinBox->value() ) );
506 input = dc1394Input;
507 dc1394_feature_info shutter = dc1394Input->
508 get_feature( FEATURE_SHUTTER );
509 ui.shutterSlider->setMinimum( shutter.min );
510 ui.shutterSlider->setMaximum( shutter.max );
511 ui.shutterSlider->setValue( shutter.value );
512 dc1394_feature_info gain = dc1394Input->
513 get_feature( FEATURE_GAIN );
514 ui.gainSlider->setMinimum( gain.min );
515 ui.gainSlider->setMaximum( gain.max );
516 ui.gainSlider->setValue( gain.value );
517 dc1394_feature_info balance = dc1394Input->
518 get_feature( FEATURE_WHITE_BALANCE );
519 ui.balanceSlider->setMinimum( balance.min );
520 ui.balanceSlider->setMaximum( balance.max );
521 ui.balanceSlider->setValue( ( balance.min + balance.max ) / 2 );
522 setCameraParameters();
523 ui.errorLabel->setText( "" );
524 updateEnabled();
525 };
526 };
527 return input;
528 }
529  
530 void MandoWizard::setCameraParameters(void)
531 {
532 if ( v4lInput )
533 v4lInput->setSensivity( ui.brightnessSlider->value(),
534 ui.hueSlider->value(),
535 ui.colourSlider->value(),
536 ui.contrastSlider->value() );
537 if ( dc1394Input ) {
538 dc1394Input->set_feature_value( FEATURE_SHUTTER,
539 ui.shutterSlider->value() );
540 dc1394Input->set_feature_value( FEATURE_GAIN,
541 ui.gainSlider->value() );
542 dc1394Input->set_feature_value( FEATURE_WHITE_BALANCE,
543 ui.balanceSlider->value() );
544 };
545 }
546  
547 image< unsigned char > MandoWizard::grabFrame(void)
548 throw (mimasexception)
549 {
550 return image< unsigned char >( grabColourFrame() );
551 }
552  
553 image< rgba< unsigned char > > MandoWizard::grabColourFrame( bool twice )
554 throw (mimasexception)
555 {
556 image< rgba< unsigned char > > retVal;
557 // discard old frame.
558 if ( twice ) (*camera()) >> retVal;
559 (*camera()) >> retVal;
560 return retVal;
561 }
562  
563 void MandoWizard::calibrate()
564 {
565 if ( calibrateWidget != NULL ) {
566 delete calibrateWidget;
567 calibrateWidget = NULL;
568 };
569 assert( projectedPatternWidget->getImage().initialised() );
570 calibrateWidget = new CalibrateWidget
571 ( image< unsigned char >( projectedPatternWidget->getImage() ),
572 this );
573  
574 assert( searchPatternWidget->getImage().initialised() );
575 cameraProjectorCalibration =
576 CameraProjectorCalibrationPtr
577 ( new CameraProjectorCalibration( searchPatternWidget->getImage() ) );
578 pointerRecognition.reset();
579  
580 calibrateWidget->setWindowFlags( Qt::Dialog );
581 // calibrateWidget->setWindowModality( Qt::WindowModal );
582 calibrateWidget->showFullScreen();
583  
584 updateEnabled();
585  
586 if ( calibTimer != 0 ) {
587 killTimer( calibTimer );
588 calibTimer = 0;
589 };
590 calibState = Init;
591 calibTimer = startTimer( CALIBDELAY );
592 }
593  
594 void MandoWizard::startDrag()
595 {
596 ui.statusLabel->setText( "<b>button pressed</b>" );
597 }
598  
599 void MandoWizard::stopDrag()
600 {
601 ui.statusLabel->setText( "button released" );
602 }