Subversion Repositories seema-scanner

Rev

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

Rev Author Line No. Line
22 jakw 1
#include "MVCalibrationDialog.h"
2
#include "ui_MVCalibrationDialog.h"
3
 
4
#include <QListWidgetItem>
5
#include <QSettings>
6
#include <QCloseEvent>
7
 
8
 
9
MVCalibrationDialog::MVCalibrationDialog(QWidget *parent) : QDialog(parent), ui(new Ui::MVCalibrationDialog), reviewMode(false){
10
    ui->setupUi(this);
11
 
12
 
13
    // Set up capture worker on separate thread
14
    captureWorker = new MVCaptureWorker();
15
    captureWorkerThread = new QThread(this);
16
    captureWorkerThread->setObjectName("captureWorkerThread");
17
 
18
    captureWorker->moveToThread(captureWorkerThread);
19
    captureWorkerThread->start();
20
 
21
 
22
    // Connect program logic
23
    qRegisterMetaType<cv::Mat>("cv::Mat");
24
    qRegisterMetaType< std::vector<cv::Mat> >("std::vector<cv::Mat>");
25
 
26
    connect(captureWorker, SIGNAL(newFrameSet(std::vector<cv::Mat>)), this, SLOT(receiveNewFrameSet(std::vector<cv::Mat>)));
27
 
28
    // Start capturing
29
    QMetaObject::invokeMethod(captureWorker, "setup", Q_ARG(bool, false));
30
    QMetaObject::invokeMethod(captureWorker, "doWork");
31
 
32
}
33
 
34
void MVCalibrationDialog::receiveNewFrameSet(std::vector<cv::Mat> frameSet){
35
    ui->videoWidget0->showImageCV(frameSet[0]);
36
    ui->videoWidget1->showImageCV(frameSet[1]);
37
}
38
 
39
void MVCalibrationDialog::addFrameSetToCalibration(std::vector<cv::Mat> frameSet){
40
 
41
    // Disconnect from further frame sets
42
    disconnect(captureWorker, SIGNAL(newFrameSet(std::vector<cv::Mat>)), this, SLOT(addFrameSetToCalibration(std::vector<cv::Mat>)));
43
 
44
    calibrationSets.push_back(frameSet);
45
 
46
    // Add identifier to list
47
    QListWidgetItem* item = new QListWidgetItem(QString("Set %1").arg(ui->listWidget->count()), ui->listWidget);
48
    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
49
    item->setCheckState(Qt::Checked);
50
 
51
    // Enable calibration
52
    if(calibrationSets.size() >= 2)
53
        ui->calibrateButton->setEnabled(true);
54
 
55
}
56
 
57
void MVCalibrationDialog::on_snapButton_clicked(){
58
 
59
    if(reviewMode){
60
        ui->snapButton->setText("Snap");
61
        connect(captureWorker, SIGNAL(newFrameSet(std::vector<cv::Mat>)), this, SLOT(receiveNewFrameSet(std::vector<cv::Mat>)));
62
        reviewMode = false;
63
        return;
64
    }
65
 
66
    // Redirect one frame set into calibration
67
    connect(captureWorker, SIGNAL(newFrameSet(std::vector<cv::Mat>)), this, SLOT(addFrameSetToCalibration(std::vector<cv::Mat>)));
68
 
69
}
70
 
71
void MVCalibrationDialog::on_listWidget_clicked(const QModelIndex &index){
72
 
73
 
74
 
75
}
76
 
77
void MVCalibrationDialog::on_calibrateButton_clicked(){
78
 
79
    reviewMode = true;
80
    ui->snapButton->setText("Capture");
81
    QCoreApplication::processEvents();
82
 
83
    // Disconnect form live feed for review mode
84
    disconnect(captureWorker, SIGNAL(newFrameSet(std::vector<cv::Mat>)), this, SLOT(receiveNewFrameSet(std::vector<cv::Mat>)));
85
 
86
    // Number of saddle points on calibration pattern
87
    cv::Size patternSize(10, 9);
88
 
89
    int nSets = calibrationSets.size();
90
 
91
    std::vector< std::vector< std::vector<cv::Point2f> > > qc(2);
92
 
93
    calibrationResults = calibrationSets;
94
 
95
    // Loop through calibration sets
96
    for(int i=0; i<nSets; i++){
97
 
98
        if(ui->listWidget->item(i)->checkState() != Qt::Checked){
99
            continue;
100
        }
101
 
102
        std::vector<cv::Mat> calibrationSetI = calibrationSets[i];
103
        std::vector< std::vector<cv::Point2f> > qci;
104
 
105
        // Loop through cameras
106
        for(unsigned int j=0; j<calibrationSetI.size(); j++){
107
            std::vector<cv::Point2f> qcij;
108
            // Extract checker corners
109
            bool success = cv::findChessboardCorners(calibrationSetI[j], patternSize, qcij, cv::CALIB_CB_ADAPTIVE_THRESH);
110
            if(success){
111
                cv::cornerSubPix(calibrationSetI[j], qcij, cv::Size(5, 5), cv::Size(-1, -1),cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 100, 0.001));
112
                // Draw colored chessboard
113
                cv::Mat calibrationSetIJColor;
114
                cv::cvtColor(calibrationSetI[j], calibrationSetIJColor, CV_GRAY2RGB);
115
                cv::drawChessboardCorners(calibrationSetIJColor, patternSize, qcij, success);
116
                calibrationResults[i][j] = calibrationSetIJColor;
117
            } else {
118
                ui->listWidget->item(i)->setCheckState(Qt::Unchecked);
119
            }
120
            qci.push_back(qcij);
121
        }
122
 
123
        // Add to whole set
124
        if(!qci[0].empty() && !qci[1].empty() ){
125
            qc[0].push_back(qci[0]);
126
            qc[1].push_back(qci[1]);
127
        }
128
 
129
        // Show results
130
        ui->listWidget->setCurrentRow(i);
131
        QCoreApplication::processEvents();
132
    }
133
 
134
    int nValidSets = qc[0].size();
135
    if(nValidSets <= 2){
136
        std::cerr << "Not enough valid calibration sequences!" << std::endl;
137
        return;
138
    }
139
 
140
    // Generate world object coordinates [mm]
141
    std::vector<cv::Point3f> Qi;
142
    for (int h=0; h<patternSize.height; h++)
143
        for (int w=0; w<patternSize.width; w++)
144
            Qi.push_back(cv::Point3f(5 * w, 5* h, 0.0)); // 5mm chess field size
145
    std::vector< std::vector<cv::Point3f> > Q;
146
    for(int i=0; i<qc[0].size(); i++)
147
        Q.push_back(Qi);
148
 
149
    // calibrate the cameras
150
//    cv::Size frameSize(calibrationSets[0][0].cols, calibrationSets[0][0].rows);
151
    cv::Size frameSize(640, 480);
152
    int flags = 0; //cv::CALIB_FIX_K3 + cv::CALIB_FIX_INTRINSIC;
153
 
154
    std::vector< std::vector<cv::Point2f> > qc0 = qc[0];
155
    std::vector< std::vector<cv::Point2f> > qc1 = qc[1];
156
 
157
    std::vector<cv::Mat> cam_rvecs0, cam_tvecs0;
158
    cal.cam0_error = cv::calibrateCamera(Q, qc0, frameSize, cal.K0, cal.k0, cam_rvecs0, cam_tvecs0);
159
 
160
    std::vector<cv::Mat> cam_rvecs1, cam_tvecs1;
161
    cal.cam1_error = cv::calibrateCamera(Q, qc1, frameSize, cal.K1, cal.k1, cam_rvecs1, cam_tvecs1);
162
 
163
    // stereo calibration (don't change K0, K1, k0, k1)
164
    int flags_stereo = flags + cv::CALIB_FIX_INTRINSIC;
165
    cv::Mat E, F, R1, T1;
166
    cal.stereo_error = cv::stereoCalibrate(Q, qc[0], qc[1], cal.K0, cal.k0, cal.K1, cal.k1,
167
                                              frameSize, R1, T1, E, F,
168
                                              cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 50, DBL_EPSILON),
169
                                              flags_stereo);
170
 
171
    cal.R1 = R1;
172
    cal.T1 = T1;
173
    cal.E = E;
174
    cal.F = F;
175
 
176
    cal.print(std::cout);
177
 
178
    ui->saveButton->setEnabled(true);
179
 
180
}
181
 
182
 
183
void MVCalibrationDialog::on_listWidget_currentRowChanged(int currentRow){
184
 
185
    reviewMode = true;
186
    ui->snapButton->setText("Capture");
187
 
188
    // Disconnect form live feed for review mode
189
    disconnect(captureWorker, SIGNAL(newFrameSet(std::vector<cv::Mat>)), this, SLOT(receiveNewFrameSet(std::vector<cv::Mat>)));
190
 
191
    unsigned int idx = ui->listWidget->currentRow();
192
 
193
    // Show result if available, otherwise captured image
194
    if(!calibrationResults[idx][0].empty())
195
        ui->videoWidget0->showImageCV(calibrationResults[idx][0]);
196
    else
197
        ui->videoWidget0->showImageCV(calibrationSets[idx][0]);
198
 
199
    if(!calibrationResults[idx][1].empty())
200
        ui->videoWidget1->showImageCV(calibrationResults[idx][1]);
201
    else
202
        ui->videoWidget1->showImageCV(calibrationSets[idx][1]);
203
}
204
 
205
void MVCalibrationDialog::closeEvent(QCloseEvent *event){
206
 
207
    connect(captureWorker, SIGNAL(finished()), captureWorker, SLOT(deleteLater()));
208
    QMetaObject::invokeMethod(captureWorker, "stopWorking");
209
    captureWorkerThread->quit();
210
    captureWorkerThread->wait();
211
//this->deleteLater();
212
    event->accept();
213
}
214
 
215
MVCalibrationDialog::~MVCalibrationDialog(){
216
 
217
//    QMetaObject::invokeMethod(captureWorker, "stopWorking");
218
//    captureWorkerThread->quit();
219
//    captureWorkerThread->wait();
220
 
221
//    delete captureWorker;
222
    delete captureWorkerThread;
223
    delete ui;
224
}
225
 
226
 
227
void MVCalibrationDialog::on_saveButton_clicked(){
228
 
229
//     Register as meta type and stream operators for use in QSettings
230
//    qRegisterMetaTypeStreamOperators<MVCalibrationData>("MVCalibrationData");
231
//    QSettings settings;
232
//    settings.setValue("Calibration", QVariant::fromValue<MVCalibrationData>(cal));
233
 
234
    cal.save("calibration.xml");
235
 
236
    this->close();
237
}