Subversion Repositories seema-scanner

Rev

Rev 71 | Rev 74 | 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>
67 jakw 6
#include <QMessageBox>
4 jakw 7
 
44 jakw 8
#include <pcl/io/pcd_io.h>
9
#include <pcl/io/ascii_io.h>
10
#include <pcl/io/ply_io.h>
11
#include <pcl/io/png_io.h>
12
#include <pcl/io/vtk_io.h>
13
#include <vtkPolyDataWriter.h>
14
#include <pcl/conversions.h>
15
 
27 jakw 16
SMScanner::SMScanner(QWidget *parent) :QMainWindow(parent), ui(new Ui::SMScanner),
67 jakw 17
                                        calibrationReviewMode(false), captureReviewMode(false), lastCaptureId(-1){
4 jakw 18
 
27 jakw 19
    // Register metatypes
20
    qRegisterMetaType<cv::Mat>("cv::Mat");
21
    qRegisterMetaType< std::vector<cv::Mat> >("std::vector<cv::Mat>");
30 jakw 22
    qRegisterMetaType< std::vector<float> >("std::vector<float>");
27 jakw 23
    qRegisterMetaType<SMCalibrationSet>("SMCalibrationSet");
24
    qRegisterMetaType<SMCalibrationParameters>("SMCalibrationParameters");
25
    qRegisterMetaTypeStreamOperators<SMCalibrationParameters>("SMCalibrationParameters");
26
    qRegisterMetaType< std::vector<SMCalibrationSet> >("std::vector<SMCalibrationSet>");
27
    qRegisterMetaType<SMFrameSequence>("SMFrameSequence");
42 jakw 28
    qRegisterMetaType< std::vector<SMFrameSequence> >("std::vector<SMFrameSequence>");
45 jakw 29
    qRegisterMetaType<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>("pcl::PointCloud<pcl::PointXYZRGB>::Ptr");
42 jakw 30
    qRegisterMetaType<SMPointCloud>("SMPointCloud");
27 jakw 31
 
42 jakw 32
    // Setup ui (requires stream operators registered)
33
    ui->setupUi(this);
34
 
4 jakw 35
    // Restore geometry
36
    this->restoreGeometry(settings.value("geometry/mainwindow").toByteArray());
37
    this->restoreState(settings.value("state/mainwindow").toByteArray());
38
 
39
    // Set up threads
40
    captureWorker = new SMCaptureWorker;
41
    captureWorkerThread = new QThread(this);
42
    captureWorkerThread->setObjectName("captureWorkerThread");
43
    captureWorker->moveToThread(captureWorkerThread);
44
    captureWorkerThread->start();
45
 
46
    // Connections
23 jakw 47
    connect(captureWorker, SIGNAL(newFrame(unsigned int, cv::Mat)), this, SLOT(onReceiveFrame(unsigned int, cv::Mat)));
27 jakw 48
    connect(captureWorker, SIGNAL(newCalibrationSet(SMCalibrationSet)), this, SLOT(onReceiveCalibrationSet(SMCalibrationSet)));
49
    connect(captureWorker, SIGNAL(newFrameSequence(SMFrameSequence)), this, SLOT(onReceiveFrameSequence(SMFrameSequence)));
30 jakw 50
    connect(captureWorker, SIGNAL(rotatedTo(float)), this, SLOT(onReceiveRotatedTo(float)));
4 jakw 51
 
52
    // Start capturing
53
    QMetaObject::invokeMethod(captureWorker, "setup");
54
    QMetaObject::invokeMethod(captureWorker, "doWork");
55
 
1 jakw 56
}
57
 
23 jakw 58
void SMScanner::onReceiveFrame(unsigned int camId, cv::Mat frame){
4 jakw 59
 
23 jakw 60
    if(camId == 0){
25 jakw 61
        if(!calibrationReviewMode)
62
            ui->calibrationCamera0Widget->showImageCV(frame);
27 jakw 63
        if(!captureReviewMode)
64
            ui->captureCamera0Widget->showImageCV(frame);
23 jakw 65
    } else if(camId == 1){
25 jakw 66
        if(!calibrationReviewMode)
67
            ui->calibrationCamera1Widget->showImageCV(frame);
27 jakw 68
        if(!captureReviewMode)
69
            ui->captureCamera1Widget->showImageCV(frame);
23 jakw 70
    }
71
}
4 jakw 72
 
23 jakw 73
void SMScanner::on_actionPreferences_triggered(){
4 jakw 74
 
73 jakw 75
//    connect(&preferenceDialog, SIGNAL(accepted()), this, SLOT(onPreferencesChanged()));
76
 
4 jakw 77
    preferenceDialog.show();
78
}
79
 
73 jakw 80
void SMScanner::onPreferencesChanged(){
81
 
82
    // Stop capturing thread
83
    connect(captureWorker, SIGNAL(finished()), captureWorker, SLOT(deleteLater()));
84
    connect(captureWorker, SIGNAL(finished()), captureWorkerThread, SLOT(quit()));
85
    QMetaObject::invokeMethod(captureWorker, "stopWork");
86
    captureWorkerThread->quit();
87
    captureWorkerThread->wait();
88
 
89
    // Restart capturing thread
90
    QMetaObject::invokeMethod(captureWorker, "setup");
91
    QMetaObject::invokeMethod(captureWorker, "doWork");
92
 
93
}
94
 
4 jakw 95
void SMScanner::closeEvent(QCloseEvent *event){
96
 
23 jakw 97
    // Stop capturing thread
98
    connect(captureWorker, SIGNAL(finished()), captureWorker, SLOT(deleteLater()));
99
    connect(captureWorker, SIGNAL(finished()), captureWorkerThread, SLOT(quit()));
100
    QMetaObject::invokeMethod(captureWorker, "stopWork");
101
    captureWorkerThread->quit();
102
    captureWorkerThread->wait();
103
 
4 jakw 104
    // Save window geometry
105
    settings.setValue("geometry/mainwindow", this->saveGeometry());
106
    settings.setValue("state/mainwindow", this->saveState());
107
 
108
    event->accept();
109
 
110
}
111
 
2 jakw 112
SMScanner::~SMScanner(){
1 jakw 113
    delete ui;
114
}
4 jakw 115
 
23 jakw 116
void SMScanner::on_singleCalibrationButton_clicked(){
117
 
25 jakw 118
    // If in review mode, go back to aquisition mode
119
    if(calibrationReviewMode){
26 jakw 120
        ui->calibrationListWidget->clearSelection();
25 jakw 121
        ui->singleCalibrationButton->setText("Single Aquisition");
122
        ui->batchCalibrationButton->setText("Batch Aquisition");
123
        calibrationReviewMode = false;
124
        return;
125
    }
126
 
27 jakw 127
    QMetaObject::invokeMethod(captureWorker, "acquireCalibrationSet", Q_ARG(float, -1.0));
23 jakw 128
 
129
}
130
 
30 jakw 131
 
132
void SMScanner::on_batchCalibrationButton_clicked(){
133
 
134
    // If in review mode, go back to aquisition mode
135
    if(calibrationReviewMode){
136
        ui->calibrationListWidget->clearSelection();
137
        ui->singleCalibrationButton->setText("Single Aquisition");
138
        ui->batchCalibrationButton->setText("Batch Aquisition");
139
        calibrationReviewMode = false;
140
        return;
141
    }
142
 
143
    // Construct vector of angles
144
    int angleStart = ui->calibrationBatchStartSpinBox->value();
145
    int angleEnd = ui->calibrationBatchEndSpinBox->value();
146
    int angleStep = ui->calibrationBatchStepSpinBox->value();
147
 
148
    if(angleStart > angleEnd)
149
        angleEnd += 360;
150
 
151
    std::vector<float> angles;
152
    for(int i=angleStart; i<=angleEnd; i+=angleStep)
153
        angles.push_back(i % 360);
154
 
155
    QMetaObject::invokeMethod(captureWorker, "acquireCalibrationSets", Q_ARG(std::vector<float>, angles));
156
 
157
    std::cout << "Aquiring sets at ";
158
    for(int i=0; i<angles.size(); i++)
159
        std::cout << angles[i] << " ";
160
    std::cout << " degrees" <<std::endl;
161
}
162
 
163
 
23 jakw 164
void SMScanner::on_calibrationRotationDial_sliderReleased(){
27 jakw 165
 
23 jakw 166
    float angle = ui->calibrationRotationDial->value();
167
    std::cout << "Rotation stage target: " << angle << std::endl;
168
    QMetaObject::invokeMethod(captureWorker, "rotateTo", Q_ARG(float, angle));
27 jakw 169
 
170
    ui->captureRotationDial->setValue(ui->calibrationRotationDial->value());
23 jakw 171
}
24 jakw 172
 
27 jakw 173
void SMScanner::onReceiveCalibrationSet(SMCalibrationSet calibrationSet){
23 jakw 174
    calibrationData.push_back(calibrationSet);
25 jakw 175
 
176
    // Add identifier to list
29 jakw 177
    QListWidgetItem* item = new QListWidgetItem(QString("Calibration Set %1 -- %2 deg").arg(ui->calibrationListWidget->count()).arg(calibrationSet.rotationAngle), ui->calibrationListWidget);
25 jakw 178
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
179
    item->setCheckState(Qt::Checked);
180
    ui->calibrationListWidget->addItem(item);
181
 
182
    // Set enabled checkmark
183
    if(calibrationData.size() >= 2)
184
        ui->calibrateButton->setEnabled(true);
23 jakw 185
}
25 jakw 186
 
27 jakw 187
void SMScanner::on_calibrateButton_clicked(){
25 jakw 188
 
29 jakw 189
    // disable ui elements
190
    ui->calibrateButton->setEnabled(false);
191
    ui->calibrationFrame->setEnabled(false);
27 jakw 192
 
193
    // set checked flags
194
    for(int i=0; i<calibrationData.size(); i++){
195
        calibrationData[i].checked = (ui->calibrationListWidget->item(i)->checkState() == Qt::Checked);
196
    }
197
 
198
//    SMCalibrationWorker calibrationWorker;
199
//    calibrationWorker.performCalibration(calibrationData);
200
 
201
    // Set up calibration thread
202
    calibrationWorker = new SMCalibrationWorker;
203
    calibrationWorkerThread = new QThread(this);
204
    calibrationWorkerThread->setObjectName("calibrationWorkerThread");
205
    calibrationWorker->moveToThread(captureWorkerThread);
206
    calibrationWorkerThread->start();
207
 
208
    // Connections
28 jakw 209
    connect(calibrationWorker, SIGNAL(newSetProcessed(int)), this, SLOT(onCalibrationSetProcessed(int)));
29 jakw 210
    connect(calibrationWorker, SIGNAL(newFrameResult(int,int,bool,cv::Mat)), this, SLOT(onCalibrationFrameResult(int,int,bool,cv::Mat)));
27 jakw 211
    connect(calibrationWorker, SIGNAL(done()), this, SLOT(onCalibrationDone()));
32 jakw 212
    connect(calibrationWorker, SIGNAL(done()), ui->pointCloudWidget, SLOT(updateCalibrationParameters()));
27 jakw 213
    connect(calibrationWorker, SIGNAL(done()), calibrationWorkerThread, SLOT(quit()));
214
    connect(calibrationWorker, SIGNAL(done()), calibrationWorker, SLOT(deleteLater()));
215
 
32 jakw 216
    // Start calibration
27 jakw 217
    QMetaObject::invokeMethod(calibrationWorker, "performCalibration", Q_ARG(std::vector<SMCalibrationSet>, calibrationData));
218
 
219
}
220
 
30 jakw 221
 
222
 
27 jakw 223
void SMScanner::onCalibrationSetProcessed(int idx){
224
 
225
    ui->calibrationListWidget->setCurrentRow(idx);
226
}
227
 
228
void SMScanner::onCalibrationDone(){
229
 
230
    std::cout << "Calibration done!" << std::endl;
29 jakw 231
    ui->calibrateButton->setEnabled(true);
232
    ui->calibrationFrame->setEnabled(true);
27 jakw 233
 
234
}
235
 
236
void SMScanner::on_calibrationListWidget_itemSelectionChanged(){
237
 
238
    // if selection is just cleared
239
    if(ui->calibrationListWidget->selectedItems().empty())
240
        return;
241
 
242
    int currentRow = ui->calibrationListWidget->currentRow();
243
 
25 jakw 244
    calibrationReviewMode = true;
245
    ui->singleCalibrationButton->setText("Live View");
246
    ui->batchCalibrationButton->setText("Live View");
247
 
248
    if(!calibrationData[currentRow].frame0Result.empty())
249
        ui->calibrationCamera0Widget->showImageCV(calibrationData[currentRow].frame0Result);
250
    else
251
        ui->calibrationCamera0Widget->showImageCV(calibrationData[currentRow].frame0);
252
 
253
    if(!calibrationData[currentRow].frame1Result.empty())
254
        ui->calibrationCamera1Widget->showImageCV(calibrationData[currentRow].frame1Result);
255
    else
256
        ui->calibrationCamera1Widget->showImageCV(calibrationData[currentRow].frame1);
27 jakw 257
 
258
//     std::cout << "on_calibrationListWidget_itemSelectionChanged" << std::endl;
25 jakw 259
}
260
 
29 jakw 261
void SMScanner::onCalibrationFrameResult(int idx, int camID, bool success, cv::Mat result){
25 jakw 262
 
29 jakw 263
//    std::cout << "onCalibrationFrameResult " << idx << camID << std::endl;
27 jakw 264
 
29 jakw 265
    if(!success)
266
        ui->calibrationListWidget->item(idx)->setCheckState(Qt::Unchecked);
267
    else {
268
        if(camID == 0)
269
            calibrationData[idx].frame0Result = result;
270
        else if(camID == 1)
271
            calibrationData[idx].frame1Result = result;
272
    }
27 jakw 273
 
274
}
275
 
276
void SMScanner::on_singleCaptureButton_clicked(){
277
 
278
    // If in review mode, go back to aquisition mode
279
    if(captureReviewMode){
280
        ui->captureTreeWidget->clearSelection();
281
        ui->singleCaptureButton->setText("Single Aquisition");
282
        ui->batchCaptureButton->setText("Batch Aquisition");
283
        captureReviewMode = false;
284
        return;
25 jakw 285
    }
286
 
27 jakw 287
    QMetaObject::invokeMethod(captureWorker, "acquireFrameSequence", Q_ARG(float, -1.0));
25 jakw 288
 
289
}
26 jakw 290
 
27 jakw 291
 
30 jakw 292
void SMScanner::on_batchCaptureButton_clicked(){
293
 
294
    // If in review mode, go back to aquisition mode
295
    if(captureReviewMode){
296
        ui->captureTreeWidget->clearSelection();
297
        ui->singleCaptureButton->setText("Single Aquisition");
298
        ui->batchCaptureButton->setText("Batch Aquisition");
299
        captureReviewMode = false;
300
        return;
301
    }
302
 
303
    // Construct vector of angles
304
    int angleStart = ui->captureBatchStartSpinBox->value();
305
    int angleEnd = ui->captureBatchEndSpinBox->value();
306
    int angleStep = ui->captureBatchStepSpinBox->value();
307
 
308
    if(angleStart > angleEnd)
309
        angleEnd += 360;
310
 
311
    std::vector<float> angles;
312
    for(int i=angleStart; i<=angleEnd; i+=angleStep)
313
        angles.push_back(i % 360);
314
 
315
    std::cout << "Aquiring sequences at ";
316
    for(int i=0; i<angles.size(); i++)
317
        std::cout << angles[i] << " ";
318
    std::cout << " degrees" <<std::endl;
319
 
320
    QMetaObject::invokeMethod(captureWorker, "acquireFrameSequences", Q_ARG(std::vector<float>, angles));
321
}
322
 
27 jakw 323
void SMScanner::on_captureRotationDial_sliderReleased(){
324
 
325
    float angle = ui->captureRotationDial->value();
326
    std::cout << "Rotation stage target: " << angle << std::endl;
327
    QMetaObject::invokeMethod(captureWorker, "rotateTo", Q_ARG(float, angle));
328
 
329
    ui->calibrationRotationDial->setValue(ui->captureRotationDial->value());
26 jakw 330
}
27 jakw 331
 
332
void SMScanner::onReceiveFrameSequence(SMFrameSequence frameSequence){
333
 
67 jakw 334
    int id = lastCaptureId + 1;
335
    lastCaptureId += 1;
336
 
45 jakw 337
    frameSequence.id = id;
338
 
27 jakw 339
    captureData.push_back(frameSequence);
340
 
341
    // Add identifier to list
342
    QTreeWidgetItem* item = new QTreeWidgetItem(ui->captureTreeWidget);
45 jakw 343
    item->setText(0, QString("Frame Sequence %1 -- %2 deg").arg(id).arg(frameSequence.rotationAngle));
27 jakw 344
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
67 jakw 345
    item->setData(0, Qt::UserRole, QPoint(captureData.size()-1, -1));
27 jakw 346
    item->setCheckState(0, Qt::Checked);
347
    //ui->captureTreeWidget->addItem(item);
348
 
349
    for(int i=0; i<frameSequence.frames0.size(); i++){
350
        QTreeWidgetItem* subItem = new QTreeWidgetItem(item);
351
        subItem->setText(0, QString("frames %1").arg(i));
45 jakw 352
        subItem->setData(0, Qt::UserRole, QPoint(id, i));
27 jakw 353
    }
41 jakw 354
 
355
    ui->reconstructButton->setEnabled(true);
27 jakw 356
}
357
 
358
void SMScanner::on_captureTreeWidget_itemSelectionChanged(){
359
 
360
    // if selection is just cleared
361
    if(ui->captureTreeWidget->selectedItems().empty())
362
        return;
363
 
364
    QTreeWidgetItem *item = ui->captureTreeWidget->currentItem();
365
 
366
    captureReviewMode = true;
367
 
368
    ui->singleCaptureButton->setText("Live View");
369
    ui->batchCaptureButton->setText("Live View");
370
 
371
    QPoint idx = item->data(0, Qt::UserRole).toPoint();
372
 
373
    if(idx.y() != -1){
374
        ui->captureCamera0Widget->showImageCV(captureData[idx.x()].frames0[idx.y()]);
375
        ui->captureCamera1Widget->showImageCV(captureData[idx.x()].frames1[idx.y()]);
376
    }
377
 
378
//     std::cout << "on_captureTreeWidget_itemSelectionChanged" << std::endl;
379
}
30 jakw 380
 
381
 
382
void SMScanner::onReceiveRotatedTo(float angle){
383
 
384
    // update ui with new position
385
    ui->calibrationRotationDial->setValue(angle);
386
    ui->captureRotationDial->setValue(angle);
387
 
388
}
36 jakw 389
 
390
void SMScanner::on_actionExport_Sets_triggered(){
391
 
392
    QString dirName = QFileDialog::getExistingDirectory(this, "Export calibration sets", QString());
393
    for(int i=0; i<calibrationData.size(); i++){
394
        QString fileName = QString("%1/frame0_%2.png").arg(dirName).arg(i);
395
        cv::Mat frameBGR;
396
        cv::cvtColor(calibrationData[i].frame0, frameBGR, CV_RGB2BGR);
397
        cv::imwrite(fileName.toStdString(), frameBGR);
398
        fileName = QString("%1/frame1_%2.png").arg(dirName).arg(i);
399
        cv::cvtColor(calibrationData[i].frame1, frameBGR, CV_RGB2BGR);
400
        cv::imwrite(fileName.toStdString(), frameBGR);
401
    }
402
 
403
}
404
 
405
void SMScanner::on_actionExport_Sequences_triggered(){
406
 
407
    QString dirName = QFileDialog::getExistingDirectory(this, "Export frame sequences", QString());
408
 
409
    for(int i=0; i<captureData.size(); i++){
410
        QString seqDirName = QString("%1/sequence_%2").arg(dirName).arg(i);
411
        if(!QDir().mkdir(seqDirName))
412
            std::cerr << "Could not create directory " << seqDirName.toStdString() << std::endl;
413
        for(int j=0; j<captureData[i].frames0.size(); j++){
414
            QString fileName = QString("%1/frames0_%2.png").arg(seqDirName).arg(j);
415
            cv::Mat frameBGR;
416
            cv::cvtColor(captureData[i].frames0[j], frameBGR, CV_RGB2BGR);
417
            cv::imwrite(fileName.toStdString(), frameBGR);
418
        }
419
        for(int j=0; j<captureData[i].frames1.size(); j++){
420
            QString fileName = QString("%1/frames1_%2.png").arg(seqDirName).arg(j);
421
            cv::Mat frameBGR;
422
            cv::cvtColor(captureData[i].frames1[j], frameBGR, CV_RGB2BGR);
423
            cv::imwrite(fileName.toStdString(), frameBGR);
424
        }
425
    }
426
}
41 jakw 427
 
428
void SMScanner::on_reconstructButton_clicked(){
429
 
430
    // Set up reconstruction thread
431
    reconstructionWorker = new SMReconstructionWorker;
432
    reconstructionWorkerThread = new QThread(this);
433
    reconstructionWorkerThread->setObjectName("reconstructionWorkerThread");
434
    reconstructionWorker->moveToThread(reconstructionWorkerThread);
435
    reconstructionWorkerThread->start();
436
 
437
    // Connections
42 jakw 438
    connect(reconstructionWorker, SIGNAL(newPointCloud(SMPointCloud)), this, SLOT(onNewPointCloud(SMPointCloud)));
41 jakw 439
    connect(reconstructionWorker, SIGNAL(done()), reconstructionWorkerThread, SLOT(quit()));
440
    connect(reconstructionWorker, SIGNAL(done()), reconstructionWorker, SLOT(deleteLater()));
441
 
442
    // Start reconstructing
42 jakw 443
    QMetaObject::invokeMethod(reconstructionWorker, "setup");
41 jakw 444
 
45 jakw 445
    for(int i=0; i<captureData.size(); i++){
47 jakw 446
        if(!captureData[i].reconstructed & ui->captureTreeWidget->topLevelItem(i)->checkState(0) == Qt::Checked)
45 jakw 447
            QMetaObject::invokeMethod(reconstructionWorker, "reconstructPointCloud", Q_ARG(SMFrameSequence, captureData[i]));
448
    }
449
 
41 jakw 450
}
451
 
42 jakw 452
void SMScanner::onNewPointCloud(SMPointCloud smCloud){
41 jakw 453
 
45 jakw 454
    int id = smCloud.id;
455
    captureData[id].reconstructed = true;
456
 
41 jakw 457
    pointCloudData.push_back(smCloud);
458
 
42 jakw 459
    // Add identifier to list
43 jakw 460
    QListWidgetItem* item = new QListWidgetItem(QString("Point Cloud %1 -- %2 deg").arg(id).arg(smCloud.rotationAngle), ui->pointCloudsListWidget);
42 jakw 461
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
44 jakw 462
    item->setData(Qt::UserRole, QVariant(id));
42 jakw 463
    item->setCheckState(Qt::Checked);
44 jakw 464
 
42 jakw 465
    ui->pointCloudsListWidget->addItem(item);
466
 
71 jakw 467
//    ui->pointCloudWidget->addPointCloud(smCloud, id);
41 jakw 468
}
42 jakw 469
 
470
 
44 jakw 471
 
472
void SMScanner::on_actionExport_Point_Clouds_triggered(){
473
 
474
    QString directory = QFileDialog::getExistingDirectory(this, "Export Point Clouds", QString());
475
 
476
//    //  Non native file dialog
477
//    QFileDialog saveDirectoryDialog(this, "Export Point Clouds", QString(), "*.pcd;;*.ply;;*.vtk;;*.png;;*.txt");
478
//    saveDirectoryDialog.setDefaultSuffix("ply");
479
//    saveDirectoryDialog.setFileMode(QFileDialog::Directory);
480
//    saveDirectoryDialog.exec();
481
//    QString directory = saveDirectoryDialog.directory().path();
482
//    QString type = saveDirectoryDialog.selectedNameFilter();
483
 
484
    // save point clouds in ply format
485
    for(int i=0; i<pointCloudData.size(); i++){
486
        QString fileName = QString("%1/pointcloud_%2.ply").arg(directory).arg(i);
45 jakw 487
        pcl::PointCloud<pcl::PointXYZRGB>::Ptr pointCloudPCL(pointCloudData[i].pointCloud);
44 jakw 488
        //pcl::io::savePLYFileBinary(fileName.toStdString(), *pointCloudPCL);
489
        pcl::PLYWriter w;
490
        // Write to ply in binary without camera
45 jakw 491
        w.write<pcl::PointXYZRGB> (fileName.toStdString(), *pointCloudPCL, true, false);
44 jakw 492
    }
493
 
494
    // save meshlab aln project file
495
    std::ofstream s(QString("%1/alignment.aln").arg(directory).toLocal8Bit());
496
    s << pointCloudData.size() << std::endl;
497
    for(int i=0; i<pointCloudData.size(); i++){
498
        QString fileName = QString("pointcloud_%1.ply").arg(i);
499
        s << fileName.toStdString() << std::endl << "#" << std::endl;
500
        cv::Mat Tr = cv::Mat::eye(4, 4, CV_32F);
501
        cv::Mat(pointCloudData[i].R.t()).copyTo(Tr.colRange(0, 3).rowRange(0, 3));
502
        cv::Mat(-pointCloudData[i].R.t()*pointCloudData[i].T).copyTo(Tr.col(3).rowRange(0, 3));
503
        for(int j=0; j<Tr.rows; j++){
504
            for(int k=0; k<Tr.cols; k++){
505
                s << Tr.at<float>(j,k) << " ";
506
            }
507
            s << std::endl;
508
        }
509
    }
510
    s << "0" << std::flush;
511
    s.close();
512
}
513
 
514
void SMScanner::on_pointCloudsListWidget_itemChanged(QListWidgetItem *item){
515
 
516
    int id = item->data(Qt::UserRole).toInt();
517
 
518
    if(item->checkState() == Qt::Checked)
519
        ui->pointCloudWidget->addPointCloud(pointCloudData[id], id);
520
    else
521
        ui->pointCloudWidget->removePointCloud(id);
522
 
523
}
524
 
525
void SMScanner::on_actionExport_Parameters_triggered(){
526
 
42 jakw 527
    QString fileName = QFileDialog::getSaveFileName(this, "Export calibration parameters", QString(), "*.xml");
528
    QFileInfo info(fileName);
529
    QString type = info.suffix();
530
    if(type == ""){
531
        fileName.append(".xml");
532
    }
533
 
534
    SMCalibrationParameters calibration = settings.value("calibration/parameters").value<SMCalibrationParameters>();
535
    calibration.exportToXML(fileName);
536
}
67 jakw 537
 
538
void SMScanner::on_actionClear_Sequences_triggered(){
539
 
540
    int res = QMessageBox::question(this, "Clear Captured Sequences", "Clear all captured data?", QMessageBox::Ok, QMessageBox::Cancel);
541
 
542
    if(res == QMessageBox::Ok){
543
        captureData.clear();
544
        ui->captureTreeWidget->clear();
545
    }
546
}