Subversion Repositories seema-scanner

Rev

Rev 36 | Rev 42 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 jakw 1
#include "SMScanner.h"
2
#include "ui_SMScanner.h"
3
 
4 jakw 4
#include <QMetaObject>
36 jakw 5
#include <QFileDialog>
4 jakw 6
 
27 jakw 7
SMScanner::SMScanner(QWidget *parent) :QMainWindow(parent), ui(new Ui::SMScanner),
8
                                        calibrationReviewMode(false), captureReviewMode(false){
1 jakw 9
    ui->setupUi(this);
4 jakw 10
 
27 jakw 11
    // Register metatypes
12
    qRegisterMetaType<cv::Mat>("cv::Mat");
13
    qRegisterMetaType< std::vector<cv::Mat> >("std::vector<cv::Mat>");
30 jakw 14
    qRegisterMetaType< std::vector<float> >("std::vector<float>");
27 jakw 15
    qRegisterMetaType<SMCalibrationSet>("SMCalibrationSet");
16
    qRegisterMetaType<SMCalibrationParameters>("SMCalibrationParameters");
17
    qRegisterMetaTypeStreamOperators<SMCalibrationParameters>("SMCalibrationParameters");
18
    qRegisterMetaType< std::vector<SMCalibrationSet> >("std::vector<SMCalibrationSet>");
19
    qRegisterMetaType<SMFrameSequence>("SMFrameSequence");
41 jakw 20
    qRegisterMetaType<pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr>("pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr");
27 jakw 21
 
4 jakw 22
    // Restore geometry
23
    this->restoreGeometry(settings.value("geometry/mainwindow").toByteArray());
24
    this->restoreState(settings.value("state/mainwindow").toByteArray());
25
 
26
    // Set up threads
27
    captureWorker = new SMCaptureWorker;
28
    captureWorkerThread = new QThread(this);
29
    captureWorkerThread->setObjectName("captureWorkerThread");
30
    captureWorker->moveToThread(captureWorkerThread);
31
    captureWorkerThread->start();
32
 
33
    // Connections
23 jakw 34
    connect(captureWorker, SIGNAL(newFrame(unsigned int, cv::Mat)), this, SLOT(onReceiveFrame(unsigned int, cv::Mat)));
27 jakw 35
    connect(captureWorker, SIGNAL(newCalibrationSet(SMCalibrationSet)), this, SLOT(onReceiveCalibrationSet(SMCalibrationSet)));
36
    connect(captureWorker, SIGNAL(newFrameSequence(SMFrameSequence)), this, SLOT(onReceiveFrameSequence(SMFrameSequence)));
30 jakw 37
    connect(captureWorker, SIGNAL(rotatedTo(float)), this, SLOT(onReceiveRotatedTo(float)));
4 jakw 38
 
39
    // Start capturing
40
    QMetaObject::invokeMethod(captureWorker, "setup");
41
    QMetaObject::invokeMethod(captureWorker, "doWork");
42
 
1 jakw 43
}
44
 
23 jakw 45
void SMScanner::onReceiveFrame(unsigned int camId, cv::Mat frame){
4 jakw 46
 
23 jakw 47
    if(camId == 0){
25 jakw 48
        if(!calibrationReviewMode)
49
            ui->calibrationCamera0Widget->showImageCV(frame);
27 jakw 50
        if(!captureReviewMode)
51
            ui->captureCamera0Widget->showImageCV(frame);
23 jakw 52
    } else if(camId == 1){
25 jakw 53
        if(!calibrationReviewMode)
54
            ui->calibrationCamera1Widget->showImageCV(frame);
27 jakw 55
        if(!captureReviewMode)
56
            ui->captureCamera1Widget->showImageCV(frame);
23 jakw 57
    }
58
}
4 jakw 59
 
23 jakw 60
void SMScanner::on_actionPreferences_triggered(){
4 jakw 61
 
62
    preferenceDialog.show();
63
}
64
 
65
void SMScanner::closeEvent(QCloseEvent *event){
66
 
23 jakw 67
    // Stop capturing thread
68
    connect(captureWorker, SIGNAL(finished()), captureWorker, SLOT(deleteLater()));
69
    connect(captureWorker, SIGNAL(finished()), captureWorkerThread, SLOT(quit()));
70
    QMetaObject::invokeMethod(captureWorker, "stopWork");
71
    captureWorkerThread->quit();
72
    captureWorkerThread->wait();
73
 
4 jakw 74
    // Save window geometry
75
    settings.setValue("geometry/mainwindow", this->saveGeometry());
76
    settings.setValue("state/mainwindow", this->saveState());
77
 
78
    event->accept();
79
 
80
}
81
 
2 jakw 82
SMScanner::~SMScanner(){
1 jakw 83
    delete ui;
84
}
4 jakw 85
 
23 jakw 86
void SMScanner::on_singleCalibrationButton_clicked(){
87
 
25 jakw 88
    // If in review mode, go back to aquisition mode
89
    if(calibrationReviewMode){
26 jakw 90
        ui->calibrationListWidget->clearSelection();
25 jakw 91
        ui->singleCalibrationButton->setText("Single Aquisition");
92
        ui->batchCalibrationButton->setText("Batch Aquisition");
93
        calibrationReviewMode = false;
94
        return;
95
    }
96
 
27 jakw 97
    QMetaObject::invokeMethod(captureWorker, "acquireCalibrationSet", Q_ARG(float, -1.0));
23 jakw 98
 
99
}
100
 
30 jakw 101
 
102
void SMScanner::on_batchCalibrationButton_clicked(){
103
 
104
    // If in review mode, go back to aquisition mode
105
    if(calibrationReviewMode){
106
        ui->calibrationListWidget->clearSelection();
107
        ui->singleCalibrationButton->setText("Single Aquisition");
108
        ui->batchCalibrationButton->setText("Batch Aquisition");
109
        calibrationReviewMode = false;
110
        return;
111
    }
112
 
113
    // Construct vector of angles
114
    int angleStart = ui->calibrationBatchStartSpinBox->value();
115
    int angleEnd = ui->calibrationBatchEndSpinBox->value();
116
    int angleStep = ui->calibrationBatchStepSpinBox->value();
117
 
118
    if(angleStart > angleEnd)
119
        angleEnd += 360;
120
 
121
    std::vector<float> angles;
122
    for(int i=angleStart; i<=angleEnd; i+=angleStep)
123
        angles.push_back(i % 360);
124
 
125
    QMetaObject::invokeMethod(captureWorker, "acquireCalibrationSets", Q_ARG(std::vector<float>, angles));
126
 
127
    std::cout << "Aquiring sets at ";
128
    for(int i=0; i<angles.size(); i++)
129
        std::cout << angles[i] << " ";
130
    std::cout << " degrees" <<std::endl;
131
}
132
 
133
 
23 jakw 134
void SMScanner::on_calibrationRotationDial_sliderReleased(){
27 jakw 135
 
23 jakw 136
    float angle = ui->calibrationRotationDial->value();
137
    std::cout << "Rotation stage target: " << angle << std::endl;
138
    QMetaObject::invokeMethod(captureWorker, "rotateTo", Q_ARG(float, angle));
27 jakw 139
 
140
    ui->captureRotationDial->setValue(ui->calibrationRotationDial->value());
23 jakw 141
}
24 jakw 142
 
27 jakw 143
void SMScanner::onReceiveCalibrationSet(SMCalibrationSet calibrationSet){
23 jakw 144
    calibrationData.push_back(calibrationSet);
25 jakw 145
 
146
    // Add identifier to list
29 jakw 147
    QListWidgetItem* item = new QListWidgetItem(QString("Calibration Set %1 -- %2 deg").arg(ui->calibrationListWidget->count()).arg(calibrationSet.rotationAngle), ui->calibrationListWidget);
25 jakw 148
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
149
    item->setCheckState(Qt::Checked);
150
    ui->calibrationListWidget->addItem(item);
151
 
152
    // Set enabled checkmark
153
    if(calibrationData.size() >= 2)
154
        ui->calibrateButton->setEnabled(true);
23 jakw 155
}
25 jakw 156
 
27 jakw 157
void SMScanner::on_calibrateButton_clicked(){
25 jakw 158
 
29 jakw 159
    // disable ui elements
160
    ui->calibrateButton->setEnabled(false);
161
    ui->calibrationFrame->setEnabled(false);
27 jakw 162
 
163
    // set checked flags
164
    for(int i=0; i<calibrationData.size(); i++){
165
        calibrationData[i].checked = (ui->calibrationListWidget->item(i)->checkState() == Qt::Checked);
166
    }
167
 
168
//    SMCalibrationWorker calibrationWorker;
169
//    calibrationWorker.performCalibration(calibrationData);
170
 
171
    // Set up calibration thread
172
    calibrationWorker = new SMCalibrationWorker;
173
    calibrationWorkerThread = new QThread(this);
174
    calibrationWorkerThread->setObjectName("calibrationWorkerThread");
175
    calibrationWorker->moveToThread(captureWorkerThread);
176
    calibrationWorkerThread->start();
177
 
178
    // Connections
28 jakw 179
    connect(calibrationWorker, SIGNAL(newSetProcessed(int)), this, SLOT(onCalibrationSetProcessed(int)));
29 jakw 180
    connect(calibrationWorker, SIGNAL(newFrameResult(int,int,bool,cv::Mat)), this, SLOT(onCalibrationFrameResult(int,int,bool,cv::Mat)));
27 jakw 181
    connect(calibrationWorker, SIGNAL(done()), this, SLOT(onCalibrationDone()));
32 jakw 182
    connect(calibrationWorker, SIGNAL(done()), ui->pointCloudWidget, SLOT(updateCalibrationParameters()));
27 jakw 183
    connect(calibrationWorker, SIGNAL(done()), calibrationWorkerThread, SLOT(quit()));
184
    connect(calibrationWorker, SIGNAL(done()), calibrationWorker, SLOT(deleteLater()));
185
 
32 jakw 186
    // Start calibration
27 jakw 187
    QMetaObject::invokeMethod(calibrationWorker, "performCalibration", Q_ARG(std::vector<SMCalibrationSet>, calibrationData));
188
 
189
}
190
 
30 jakw 191
 
192
 
27 jakw 193
void SMScanner::onCalibrationSetProcessed(int idx){
194
 
195
    ui->calibrationListWidget->setCurrentRow(idx);
196
}
197
 
198
void SMScanner::onCalibrationDone(){
199
 
200
    std::cout << "Calibration done!" << std::endl;
29 jakw 201
    ui->calibrateButton->setEnabled(true);
202
    ui->calibrationFrame->setEnabled(true);
27 jakw 203
 
204
}
205
 
206
void SMScanner::on_calibrationListWidget_itemSelectionChanged(){
207
 
208
    // if selection is just cleared
209
    if(ui->calibrationListWidget->selectedItems().empty())
210
        return;
211
 
212
    int currentRow = ui->calibrationListWidget->currentRow();
213
 
25 jakw 214
    calibrationReviewMode = true;
215
    ui->singleCalibrationButton->setText("Live View");
216
    ui->batchCalibrationButton->setText("Live View");
217
 
218
    if(!calibrationData[currentRow].frame0Result.empty())
219
        ui->calibrationCamera0Widget->showImageCV(calibrationData[currentRow].frame0Result);
220
    else
221
        ui->calibrationCamera0Widget->showImageCV(calibrationData[currentRow].frame0);
222
 
223
    if(!calibrationData[currentRow].frame1Result.empty())
224
        ui->calibrationCamera1Widget->showImageCV(calibrationData[currentRow].frame1Result);
225
    else
226
        ui->calibrationCamera1Widget->showImageCV(calibrationData[currentRow].frame1);
27 jakw 227
 
228
//     std::cout << "on_calibrationListWidget_itemSelectionChanged" << std::endl;
25 jakw 229
}
230
 
29 jakw 231
void SMScanner::onCalibrationFrameResult(int idx, int camID, bool success, cv::Mat result){
25 jakw 232
 
29 jakw 233
//    std::cout << "onCalibrationFrameResult " << idx << camID << std::endl;
27 jakw 234
 
29 jakw 235
    if(!success)
236
        ui->calibrationListWidget->item(idx)->setCheckState(Qt::Unchecked);
237
    else {
238
        if(camID == 0)
239
            calibrationData[idx].frame0Result = result;
240
        else if(camID == 1)
241
            calibrationData[idx].frame1Result = result;
242
    }
27 jakw 243
 
244
}
245
 
246
void SMScanner::on_singleCaptureButton_clicked(){
247
 
248
    // If in review mode, go back to aquisition mode
249
    if(captureReviewMode){
250
        ui->captureTreeWidget->clearSelection();
251
        ui->singleCaptureButton->setText("Single Aquisition");
252
        ui->batchCaptureButton->setText("Batch Aquisition");
253
        captureReviewMode = false;
254
        return;
25 jakw 255
    }
256
 
27 jakw 257
    QMetaObject::invokeMethod(captureWorker, "acquireFrameSequence", Q_ARG(float, -1.0));
25 jakw 258
 
259
}
26 jakw 260
 
27 jakw 261
 
30 jakw 262
void SMScanner::on_batchCaptureButton_clicked(){
263
 
264
    // If in review mode, go back to aquisition mode
265
    if(captureReviewMode){
266
        ui->captureTreeWidget->clearSelection();
267
        ui->singleCaptureButton->setText("Single Aquisition");
268
        ui->batchCaptureButton->setText("Batch Aquisition");
269
        captureReviewMode = false;
270
        return;
271
    }
272
 
273
    // Construct vector of angles
274
    int angleStart = ui->captureBatchStartSpinBox->value();
275
    int angleEnd = ui->captureBatchEndSpinBox->value();
276
    int angleStep = ui->captureBatchStepSpinBox->value();
277
 
278
    if(angleStart > angleEnd)
279
        angleEnd += 360;
280
 
281
    std::vector<float> angles;
282
    for(int i=angleStart; i<=angleEnd; i+=angleStep)
283
        angles.push_back(i % 360);
284
 
285
    std::cout << "Aquiring sequences at ";
286
    for(int i=0; i<angles.size(); i++)
287
        std::cout << angles[i] << " ";
288
    std::cout << " degrees" <<std::endl;
289
 
290
    QMetaObject::invokeMethod(captureWorker, "acquireFrameSequences", Q_ARG(std::vector<float>, angles));
291
}
292
 
27 jakw 293
void SMScanner::on_captureRotationDial_sliderReleased(){
294
 
295
    float angle = ui->captureRotationDial->value();
296
    std::cout << "Rotation stage target: " << angle << std::endl;
297
    QMetaObject::invokeMethod(captureWorker, "rotateTo", Q_ARG(float, angle));
298
 
299
    ui->calibrationRotationDial->setValue(ui->captureRotationDial->value());
26 jakw 300
}
27 jakw 301
 
302
void SMScanner::onReceiveFrameSequence(SMFrameSequence frameSequence){
303
 
304
    captureData.push_back(frameSequence);
305
 
306
    int idx = captureData.size()-1;
307
 
308
    // Add identifier to list
309
    QTreeWidgetItem* item = new QTreeWidgetItem(ui->captureTreeWidget);
310
    item->setText(0, QString("Frame Sequence %1 -- %2 deg").arg(idx).arg(frameSequence.rotationAngle));
311
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
312
    item->setData(0, Qt::UserRole, QPoint(idx, -1));
313
    item->setCheckState(0, Qt::Checked);
314
    //ui->captureTreeWidget->addItem(item);
315
 
316
    for(int i=0; i<frameSequence.frames0.size(); i++){
317
        QTreeWidgetItem* subItem = new QTreeWidgetItem(item);
318
        subItem->setText(0, QString("frames %1").arg(i));
319
        subItem->setData(0, Qt::UserRole, QPoint(idx, i));
320
    }
41 jakw 321
 
322
    ui->reconstructButton->setEnabled(true);
27 jakw 323
}
324
 
325
void SMScanner::on_captureTreeWidget_itemSelectionChanged(){
326
 
327
    // if selection is just cleared
328
    if(ui->captureTreeWidget->selectedItems().empty())
329
        return;
330
 
331
    QTreeWidgetItem *item = ui->captureTreeWidget->currentItem();
332
 
333
    captureReviewMode = true;
334
 
335
    ui->singleCaptureButton->setText("Live View");
336
    ui->batchCaptureButton->setText("Live View");
337
 
338
    QPoint idx = item->data(0, Qt::UserRole).toPoint();
339
 
340
    if(idx.y() != -1){
341
        ui->captureCamera0Widget->showImageCV(captureData[idx.x()].frames0[idx.y()]);
342
        ui->captureCamera1Widget->showImageCV(captureData[idx.x()].frames1[idx.y()]);
343
    }
344
 
345
//     std::cout << "on_captureTreeWidget_itemSelectionChanged" << std::endl;
346
}
30 jakw 347
 
348
 
349
void SMScanner::onReceiveRotatedTo(float angle){
350
 
351
    // update ui with new position
352
    ui->calibrationRotationDial->setValue(angle);
353
    ui->captureRotationDial->setValue(angle);
354
 
355
}
36 jakw 356
 
357
void SMScanner::on_actionExport_Sets_triggered(){
358
 
359
    QString dirName = QFileDialog::getExistingDirectory(this, "Export calibration sets", QString());
360
    for(int i=0; i<calibrationData.size(); i++){
361
        QString fileName = QString("%1/frame0_%2.png").arg(dirName).arg(i);
362
        cv::Mat frameBGR;
363
        cv::cvtColor(calibrationData[i].frame0, frameBGR, CV_RGB2BGR);
364
        cv::imwrite(fileName.toStdString(), frameBGR);
365
        fileName = QString("%1/frame1_%2.png").arg(dirName).arg(i);
366
        cv::cvtColor(calibrationData[i].frame1, frameBGR, CV_RGB2BGR);
367
        cv::imwrite(fileName.toStdString(), frameBGR);
368
    }
369
 
370
}
371
 
372
void SMScanner::on_actionExport_Sequences_triggered(){
373
 
374
    QString dirName = QFileDialog::getExistingDirectory(this, "Export frame sequences", QString());
375
 
376
    for(int i=0; i<captureData.size(); i++){
377
        QString seqDirName = QString("%1/sequence_%2").arg(dirName).arg(i);
378
        if(!QDir().mkdir(seqDirName))
379
            std::cerr << "Could not create directory " << seqDirName.toStdString() << std::endl;
380
        for(int j=0; j<captureData[i].frames0.size(); j++){
381
            QString fileName = QString("%1/frames0_%2.png").arg(seqDirName).arg(j);
382
            cv::Mat frameBGR;
383
            cv::cvtColor(captureData[i].frames0[j], frameBGR, CV_RGB2BGR);
384
            cv::imwrite(fileName.toStdString(), frameBGR);
385
        }
386
        for(int j=0; j<captureData[i].frames1.size(); j++){
387
            QString fileName = QString("%1/frames1_%2.png").arg(seqDirName).arg(j);
388
            cv::Mat frameBGR;
389
            cv::cvtColor(captureData[i].frames1[j], frameBGR, CV_RGB2BGR);
390
            cv::imwrite(fileName.toStdString(), frameBGR);
391
        }
392
    }
393
}
41 jakw 394
 
395
void SMScanner::on_reconstructButton_clicked(){
396
 
397
//    // set checked flags
398
//    for(int i=0; i<captureData.size(); i++){
399
//        captureData[i].checked = (ui->captureTreeWidget->item(i)->checkState() == Qt::Checked);
400
//    }
401
 
402
 
403
    // Set up reconstruction thread
404
    reconstructionWorker = new SMReconstructionWorker;
405
    reconstructionWorkerThread = new QThread(this);
406
    reconstructionWorkerThread->setObjectName("reconstructionWorkerThread");
407
    reconstructionWorker->moveToThread(reconstructionWorkerThread);
408
    reconstructionWorkerThread->start();
409
 
410
    // Connections
411
    connect(reconstructionWorker, SIGNAL(newPointCloud(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr)), this, SLOT(onNewPointCloud(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr)));
412
    connect(reconstructionWorker, SIGNAL(done()), reconstructionWorkerThread, SLOT(quit()));
413
    connect(reconstructionWorker, SIGNAL(done()), reconstructionWorker, SLOT(deleteLater()));
414
 
415
    // Start reconstructing
416
    QMetaObject::invokeMethod(reconstructionWorker, "reconstruct", Q_ARG(std::vector<SMFrameSequence>, captureData));
417
 
418
}
419
 
420
void SMScanner::onNewPointCloud(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr pc){
421
 
422
    SMPointCloud smCloud;
423
    //smCloud.pointCloud = pc;
424
    pointCloudData.push_back(smCloud);
425
 
426
    ui->pointCloudWidget->updatePointCloud(pc);
427
}