Subversion Repositories seema-scanner

Rev

Rev 169 | Rev 182 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 169 Rev 170
1
#include "SMCaptureWorker.h"
1
#include "SMCaptureWorker.h"
2
 
2
 
3
#include "AlgorithmGrayCode.h"
3
#include "AlgorithmGrayCode.h"
4
#include "AlgorithmGrayCodeHorzVert.h"
4
#include "AlgorithmGrayCodeHorzVert.h"
5
#include "AlgorithmGrayCodeMax.h"
5
#include "AlgorithmGrayCodeMax.h"
6
#include "AlgorithmPhaseShiftTwoFreq.h"
6
#include "AlgorithmPhaseShiftTwoFreq.h"
7
#include "AlgorithmPhaseShiftThreeFreq.h"
7
#include "AlgorithmPhaseShiftThreeFreq.h"
8
#include "AlgorithmLineShift.h"
8
#include "AlgorithmLineShift.h"
9
 
9
 
10
#include <QCoreApplication>
10
#include <QCoreApplication>
11
#include <QTime>
11
#include <QTime>
12
#include <QSettings>
12
#include <QSettings>
13
#include <QtTest/QTest>
13
#include <QtTest/QTest>
14
 
14
 
15
#include "cvtools.h"
15
#include "cvtools.h"
16
 
16
 
17
void SMCaptureWorker::setup(){
17
void SMCaptureWorker::setup(){
18
 
18
 
19
    QSettings settings;
19
    QSettings settings;
20
 
20
 
21
    // Create cameras
21
    // Create cameras
22
    int iNum0 = settings.value("camera0/interfaceNumber", -1).toInt();
22
    int iNum0 = settings.value("camera0/interfaceNumber", -1).toInt();
23
    int cNum0 = settings.value("camera0/cameraNumber", -1).toInt();
23
    int cNum0 = settings.value("camera0/cameraNumber", -1).toInt();
24
    if(iNum0 != -1)
-
 
25
        camera0 = CameraFactory::NewCamera(iNum0,cNum0,triggerModeSoftware);
24
    camera0 = CameraFactory::NewCamera(iNum0,cNum0,triggerModeSoftware);
26
 
25
 
27
    if(!camera0)
26
    if(!camera0)
28
        return;
27
        return;
29
 
28
 
30
    int iNum1 = settings.value("camera1/interfaceNumber", -1).toInt();
29
    int iNum1 = settings.value("camera1/interfaceNumber", -1).toInt();
31
    int cNum1 = settings.value("camera1/cameraNumber", -1).toInt();
30
    int cNum1 = settings.value("camera1/cameraNumber", -1).toInt();
32
    if(iNum1 != -1)
-
 
33
        camera1 = CameraFactory::NewCamera(iNum1,cNum1,triggerModeSoftware);
31
    camera1 = CameraFactory::NewCamera(iNum1,cNum1,triggerModeSoftware);
34
 
32
 
35
    if(!camera1)
33
    if(!camera1)
36
        return;
34
        return;
37
 
35
 
38
    // Set camera settings
36
    // Set camera settings
39
    CameraSettings cameraSettings;
37
    CameraSettings cameraSettings;
40
    cameraSettings.shutter = settings.value("camera/shutter", 16.666).toFloat();
38
    cameraSettings.shutter = settings.value("camera/shutter", 16.666).toFloat();
41
    cameraSettings.gain = 0.0;
39
    cameraSettings.gain = 0.0;
42
 
40
 
43
    camera0->setCameraSettings(cameraSettings);
41
    camera0->setCameraSettings(cameraSettings);
44
 
42
 
45
    camera1->setCameraSettings(cameraSettings);
43
    camera1->setCameraSettings(cameraSettings);
46
 
44
 
47
    // Start capturing
45
    // Start capturing
48
    camera0->startCapture();
46
    camera0->startCapture();
49
    camera1->startCapture();
47
    camera1->startCapture();
50
 
48
 
51
    // Create projector
49
    // Create projector
52
    //int screenNum = settings.value("projector/screenNumber", -1).toInt();
50
    //int screenNum = settings.value("projector/screenNumber", -1).toInt();
53
    int screenNum = settings.value("projector/screenNumber", 1).toInt();
51
    int screenNum = settings.value("projector/screenNumber", 1).toInt();
54
    if(screenNum != -1)
52
    if(screenNum != -1)
55
        projector = new ProjectorOpenGL(screenNum);
53
        projector = new ProjectorOpenGL(screenNum);
56
 
54
 
57
    // Create rotation stage
55
    // Create rotation stage
58
    rotationStage = new RotationStage();
56
    rotationStage = new RotationStage();
59
 
57
 
60
    // Create Algorithm
58
    // Create Algorithm
61
    unsigned int screenCols, screenRows;
59
    unsigned int screenCols, screenRows;
62
    projector->getScreenRes(&screenCols, &screenRows);
60
    projector->getScreenRes(&screenCols, &screenRows);
63
    codec = settings.value("algorithm", "GrayCode").toString();
61
    codec = settings.value("algorithm", "GrayCode").toString();
64
    if(codec == "GrayCode")
62
    if(codec == "GrayCode")
65
        algorithm = new AlgorithmGrayCode(screenCols, screenRows);
63
        algorithm = new AlgorithmGrayCode(screenCols, screenRows);
66
    else if(codec == "GrayCodeHorzVert")
64
    else if(codec == "GrayCodeHorzVert")
67
        algorithm = new AlgorithmGrayCodeHorzVert(screenCols, screenRows);
65
        algorithm = new AlgorithmGrayCodeHorzVert(screenCols, screenRows);
68
    else if(codec == "GrayCodeMax")
66
    else if(codec == "GrayCodeMax")
69
        algorithm = new AlgorithmGrayCodeMax(screenCols, screenRows);
67
        algorithm = new AlgorithmGrayCodeMax(screenCols, screenRows);
70
    else if(codec == "PhaseShiftTwoFreq")
68
    else if(codec == "PhaseShiftTwoFreq")
71
        algorithm = new AlgorithmPhaseShiftTwoFreq(screenCols, screenRows);
69
        algorithm = new AlgorithmPhaseShiftTwoFreq(screenCols, screenRows);
72
    else if(codec == "PhaseShiftThreeFreq")
70
    else if(codec == "PhaseShiftThreeFreq")
73
        algorithm = new AlgorithmPhaseShiftThreeFreq(screenCols, screenRows);
71
        algorithm = new AlgorithmPhaseShiftThreeFreq(screenCols, screenRows);
74
    else if(codec == "LineShift")
72
    else if(codec == "LineShift")
75
        algorithm = new AlgorithmLineShift(screenCols, screenRows);
73
        algorithm = new AlgorithmLineShift(screenCols, screenRows);
76
    else
74
    else
77
        std::cerr << "SMCaptureWorker: invalid codec " << codec.toStdString() << std::endl;
75
        std::cerr << "SMCaptureWorker: invalid codec " << codec.toStdString() << std::endl;
78
 
76
 
79
    // Upload patterns to projector/GPU
77
    // Upload patterns to projector/GPU
80
    for(unsigned int i=0; i<algorithm->getNPatterns(); i++){
78
    for(unsigned int i=0; i<algorithm->getNPatterns(); i++){
81
        cv::Mat pattern = algorithm->getEncodingPattern(i);
79
        cv::Mat pattern = algorithm->getEncodingPattern(i);
82
        projector->setPattern(i, pattern.ptr(), pattern.cols, pattern.rows);
80
        projector->setPattern(i, pattern.ptr(), pattern.cols, pattern.rows);
83
    }
81
    }
84
 
82
 
85
    delay = settings.value("trigger/delay", 50).toInt();
83
    delay = settings.value("trigger/delay", 50).toInt();
86
    stackingCalibration = settings.value("stacking/calibration", 1).toInt();
84
    stackingCalibration = settings.value("stacking/calibration", 1).toInt();
87
    stackingAcquisition= settings.value("stacking/acquisition", 1).toInt();
85
    stackingAcquisition= settings.value("stacking/acquisition", 1).toInt();
88
 
86
 
89
    setupSuccessful = true;
87
    setupSuccessful = true;
90
}
88
}
91
 
89
 
92
 
90
 
93
void SMCaptureWorker::doWork(){
91
void SMCaptureWorker::doWork(){
94
 
92
 
95
    if(!setupSuccessful)
93
    if(!setupSuccessful)
96
        return;
94
        return;
97
 
95
 
98
    working = true;
96
    working = true;
99
 
97
 
100
    // Processing loop
98
    // Processing loop
101
//    QTime time;
99
//    QTime time;
102
//    time.start();
100
//    time.start();
103
    while(working){
101
    while(working){
104
 
102
 
105
        projector->displayWhite();
103
        projector->displayWhite();
106
 
104
 
107
        // prevent image acquisition timeout
105
        // prevent image acquisition timeout
108
        QTest::qSleep(10);
106
        QTest::qSleep(10);
109
 
107
 
110
        CameraFrame frame;
108
        CameraFrame frame;
111
 
109
 
112
        // trigger cameras
110
        // trigger cameras
113
        camera0->trigger();
111
        camera0->trigger();
114
        camera1->trigger();
112
        camera1->trigger();
115
 
113
 
116
        // retrieve raw frames
114
        // retrieve raw frames
117
        frame = camera0->getFrame();
115
        frame = camera0->getFrame();
118
        cv::Mat frameCV;
116
        cv::Mat frameCV;
119
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
117
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
120
        frameCV = frameCV.clone();
118
        frameCV = frameCV.clone();
121
//        cvtools::rshift(frameCV, 8);
119
//        cvtools::rshift(frameCV, 8);
122
//        frameCV.convertTo(frameCV, CV_8UC1);
120
//        frameCV.convertTo(frameCV, CV_8UC1);
123
        emit newFrame(0, frameCV);
121
        emit newFrame(0, frameCV);
124
 
122
 
125
        frame = camera1->getFrame();
123
        frame = camera1->getFrame();
126
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
124
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
127
        frameCV = frameCV.clone();
125
        frameCV = frameCV.clone();
128
//        cvtools::rshift(frameCV, 8);
126
//        cvtools::rshift(frameCV, 8);
129
//        frameCV.convertTo(frameCV, CV_8UC1);
127
//        frameCV.convertTo(frameCV, CV_8UC1);
130
        emit newFrame(1, frameCV);
128
        emit newFrame(1, frameCV);
131
 
129
 
132
        //std::cout << "SMCaptureWorker idle " << time.restart() << "ms" << std::endl;
130
        //std::cout << "SMCaptureWorker idle " << time.restart() << "ms" << std::endl;
133
 
131
 
134
        // Process events e.g. perform a task
132
        // Process events e.g. perform a task
135
        QCoreApplication::processEvents();
133
        QCoreApplication::processEvents();
136
    }
134
    }
137
 
135
 
138
    emit finished();
136
    emit finished();
139
}
137
}
140
 
138
 
141
void SMCaptureWorker::rotateTo(float angle){
139
void SMCaptureWorker::rotateTo(float angle){
142
 
140
 
143
    if(!setupSuccessful)
141
    if(!setupSuccessful)
144
        return;
142
        return;
145
 
143
 
146
    rotationStage->moveAbsolute(angle);
144
    rotationStage->moveAbsolute(angle);
147
 
145
 
148
    while(rotationStage->isMoving()){
146
    while(rotationStage->isMoving()){
149
 
147
 
150
        // prevent grab timeout in flycapture
148
        // prevent grab timeout in flycapture
151
        QTest::qSleep(10);
149
        QTest::qSleep(10);
152
 
150
 
153
        // trigger cameras
151
        // trigger cameras
154
        camera0->trigger();
152
        camera0->trigger();
155
        camera1->trigger();
153
        camera1->trigger();
156
 
154
 
157
        // retrieve frames
155
        // retrieve frames
158
        CameraFrame frame;
156
        CameraFrame frame;
159
        frame = camera0->getFrame();
157
        frame = camera0->getFrame();
160
        cv::Mat frameCV;
158
        cv::Mat frameCV;
161
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
159
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
162
        frameCV = frameCV.clone();
160
        frameCV = frameCV.clone();
163
        emit newFrame(0, frameCV);
161
        emit newFrame(0, frameCV);
164
        frame = camera1->getFrame();
162
        frame = camera1->getFrame();
165
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
163
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
166
        frameCV = frameCV.clone();
164
        frameCV = frameCV.clone();
167
        emit newFrame(1, frameCV);
165
        emit newFrame(1, frameCV);
168
    }
166
    }
169
 
167
 
170
    emit rotatedTo(angle);
168
    emit rotatedTo(angle);
171
}
169
}
172
 
170
 
173
void SMCaptureWorker::acquireCalibrationSet(float angle){
171
void SMCaptureWorker::acquireCalibrationSet(float angle){
174
 
172
 
175
    if(!setupSuccessful)
173
    if(!setupSuccessful)
176
        return;
174
        return;
177
 
175
 
178
    if(angle != -1.0)
176
    if(angle != -1.0)
179
        rotateTo(angle);
177
        rotateTo(angle);
180
 
178
 
181
    // just for safe measures
179
    // just for safe measures
182
    QTest::qSleep(500);
180
    QTest::qSleep(500);
183
 
181
 
184
    CameraFrame frame;
182
    CameraFrame frame;
185
    SMCalibrationSet calibrationSet;
183
    SMCalibrationSet calibrationSet;
186
    cv::Mat frameCVStacked0(camera0->getFrameHeight(), camera0->getFrameWidth(), CV_32SC1, cv::Scalar(0));
184
    cv::Mat frameCVStacked0(camera0->getFrameHeight(), camera0->getFrameWidth(), CV_32SC1, cv::Scalar(0));
187
    cv::Mat frameCVStacked1(camera1->getFrameHeight(), camera1->getFrameWidth(), CV_32SC1, cv::Scalar(0));
185
    cv::Mat frameCVStacked1(camera1->getFrameHeight(), camera1->getFrameWidth(), CV_32SC1, cv::Scalar(0));
188
 
186
 
189
    for(int i=0; i<stackingCalibration; i++){
187
    for(int i=0; i<stackingCalibration; i++){
190
        // trigger cameras
188
        // trigger cameras
191
        camera0->trigger();
189
        camera0->trigger();
192
        camera1->trigger();
190
        camera1->trigger();
193
 
191
 
194
        // retrieve frames
192
        // retrieve frames
195
        frame = camera0->getFrame();
193
        frame = camera0->getFrame();
196
        cv::Mat frameCV;
194
        cv::Mat frameCV;
197
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
195
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
198
        frameCV = frameCV.clone();
196
        frameCV = frameCV.clone();
199
        cv::add(frameCV, frameCVStacked0, frameCVStacked0, cv::noArray(), CV_32SC1);
197
        cv::add(frameCV, frameCVStacked0, frameCVStacked0, cv::noArray(), CV_32SC1);
200
//cvtools::writeMat(frameCV, "frameCV.mat", "frameCV");
198
//cvtools::writeMat(frameCV, "frameCV.mat", "frameCV");
201
//cvtools::writeMat(frameCVStacked0, "frameCVStacked0.mat", "frameCVStacked0");
199
//cvtools::writeMat(frameCVStacked0, "frameCVStacked0.mat", "frameCVStacked0");
202
        emit newFrame(0, frameCV);
200
        emit newFrame(0, frameCV);
203
 
201
 
204
        frame = camera1->getFrame();
202
        frame = camera1->getFrame();
205
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
203
        frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
206
        frameCV = frameCV.clone();
204
        frameCV = frameCV.clone();
207
        cv::add(frameCV, frameCVStacked1, frameCVStacked1, cv::noArray(), CV_32SC1);
205
        cv::add(frameCV, frameCVStacked1, frameCVStacked1, cv::noArray(), CV_32SC1);
208
 
206
 
209
        emit newFrame(1, frameCV);
207
        emit newFrame(1, frameCV);
210
 
208
 
211
    }
209
    }
212
 
210
 
213
    frameCVStacked0.convertTo(frameCVStacked0, CV_8UC1, 1.0/stackingCalibration);
211
    frameCVStacked0.convertTo(frameCVStacked0, CV_8UC1, 1.0/stackingCalibration);
214
//cvtools::writeMat(frameCVStacked0, "frameCVStacked0a.mat", "frameCVStacked0a");
212
//cvtools::writeMat(frameCVStacked0, "frameCVStacked0a.mat", "frameCVStacked0a");
215
    frameCVStacked1.convertTo(frameCVStacked1, CV_8UC1, 1.0/stackingCalibration);
213
    frameCVStacked1.convertTo(frameCVStacked1, CV_8UC1, 1.0/stackingCalibration);
216
 
214
 
217
    calibrationSet.frame0 = frameCVStacked0;
215
    calibrationSet.frame0 = frameCVStacked0;
218
    calibrationSet.frame1 = frameCVStacked1;
216
    calibrationSet.frame1 = frameCVStacked1;
219
 
217
 
220
    calibrationSet.rotationAngle = rotationStage->getAngle();
218
    calibrationSet.rotationAngle = rotationStage->getAngle();
221
 
219
 
222
    emit newCalibrationSet(calibrationSet);
220
    emit newCalibrationSet(calibrationSet);
223
}
221
}
224
 
222
 
225
void SMCaptureWorker::acquireCalibrationSets(std::vector<float> angles){
223
void SMCaptureWorker::acquireCalibrationSets(std::vector<float> angles){
226
 
224
 
227
    if(!setupSuccessful)
225
    if(!setupSuccessful)
228
        return;
226
        return;
229
 
227
 
230
    for(unsigned int i=0; i<angles.size(); i++)
228
    for(unsigned int i=0; i<angles.size(); i++)
231
        acquireCalibrationSet(angles[i]);
229
        acquireCalibrationSet(angles[i]);
232
}
230
}
233
 
231
 
234
void SMCaptureWorker::acquireFrameSequence(float angle){
232
void SMCaptureWorker::acquireFrameSequence(float angle){
235
 
233
 
236
    if(!setupSuccessful)
234
    if(!setupSuccessful)
237
        return;
235
        return;
238
 
236
 
239
    if(angle != -1.0)
237
    if(angle != -1.0)
240
        rotateTo(angle);
238
        rotateTo(angle);
241
 
239
 
242
    CameraFrame frame;
240
    CameraFrame frame;
243
    SMFrameSequence frameSequence;
241
    SMFrameSequence frameSequence;
244
 
242
 
245
    for(unsigned int i=0; i<algorithm->getNPatterns(); i++){
243
    for(unsigned int i=0; i<algorithm->getNPatterns(); i++){
246
 
244
 
247
        // display pattern
245
        // display pattern
248
        projector->displayPattern(i);
246
        projector->displayPattern(i);
249
 
247
 
250
        QTest::qSleep(delay);
248
        QTest::qSleep(delay);
251
 
249
 
252
        cv::Mat frameCVStacked0(camera0->getFrameHeight(), camera0->getFrameWidth(), CV_32SC1, cv::Scalar(0));
250
        cv::Mat frameCVStacked0(camera0->getFrameHeight(), camera0->getFrameWidth(), CV_32SC1, cv::Scalar(0));
253
        cv::Mat frameCVStacked1(camera1->getFrameHeight(), camera1->getFrameWidth(), CV_32SC1, cv::Scalar(0));
251
        cv::Mat frameCVStacked1(camera1->getFrameHeight(), camera1->getFrameWidth(), CV_32SC1, cv::Scalar(0));
254
        for(int i=0; i<stackingAcquisition; i++){
252
        for(int i=0; i<stackingAcquisition; i++){
255
            // trigger cameras
253
            // trigger cameras
256
            camera0->trigger();
254
            camera0->trigger();
257
            camera1->trigger();
255
            camera1->trigger();
258
 
256
 
259
            // retrieve frames
257
            // retrieve frames
260
            frame = camera0->getFrame();
258
            frame = camera0->getFrame();
261
            cv::Mat frameCV;
259
            cv::Mat frameCV;
262
            frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
260
            frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
263
            frameCV = frameCV.clone();
261
            frameCV = frameCV.clone();
264
            cv::add(frameCV, frameCVStacked0, frameCVStacked0, cv::noArray(), CV_32SC1);
262
            cv::add(frameCV, frameCVStacked0, frameCVStacked0, cv::noArray(), CV_32SC1);
265
 
263
 
266
            emit newFrame(0, frameCV);
264
            emit newFrame(0, frameCV);
267
 
265
 
268
            frame = camera1->getFrame();
266
            frame = camera1->getFrame();
269
            frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
267
            frameCV  = cv::Mat(frame.height, frame.width, CV_8UC1, frame.memory);
270
            frameCV = frameCV.clone();
268
            frameCV = frameCV.clone();
271
            cv::add(frameCV, frameCVStacked1, frameCVStacked1, cv::noArray(), CV_32SC1);
269
            cv::add(frameCV, frameCVStacked1, frameCVStacked1, cv::noArray(), CV_32SC1);
272
 
270
 
273
            emit newFrame(1, frameCV);
271
            emit newFrame(1, frameCV);
274
 
272
 
275
        }
273
        }
276
 
274
 
277
        frameCVStacked0.convertTo(frameCVStacked0, CV_8UC1, 1.0/stackingAcquisition);
275
        frameCVStacked0.convertTo(frameCVStacked0, CV_8UC1, 1.0/stackingAcquisition);
278
        frameCVStacked1.convertTo(frameCVStacked1, CV_8UC1, 1.0/stackingAcquisition);
276
        frameCVStacked1.convertTo(frameCVStacked1, CV_8UC1, 1.0/stackingAcquisition);
279
 
277
 
280
        frameSequence.frames0.push_back(frameCVStacked0);
278
        frameSequence.frames0.push_back(frameCVStacked0);
281
        frameSequence.frames1.push_back(frameCVStacked1);
279
        frameSequence.frames1.push_back(frameCVStacked1);
282
 
280
 
283
    }
281
    }
284
 
282
 
285
    frameSequence.rotationAngle = rotationStage->getAngle();
283
    frameSequence.rotationAngle = rotationStage->getAngle();
286
    frameSequence.codec = codec;
284
    frameSequence.codec = codec;
287
 
285
 
288
    emit newFrameSequence(frameSequence);
286
    emit newFrameSequence(frameSequence);
289
 
287
 
290
    projector->displayWhite();
288
    projector->displayWhite();
291
}
289
}
292
 
290
 
293
 
291
 
294
void SMCaptureWorker::acquireFrameSequences(std::vector<float> angles){
292
void SMCaptureWorker::acquireFrameSequences(std::vector<float> angles){
295
 
293
 
296
    if(!setupSuccessful)
294
    if(!setupSuccessful)
297
        return;
295
        return;
298
 
296
 
299
    for(unsigned int i=0; i<angles.size(); i++)
297
    for(unsigned int i=0; i<angles.size(); i++)
300
        acquireFrameSequence(angles[i]);
298
        acquireFrameSequence(angles[i]);
301
}
299
}
302
 
300
 
303
void SMCaptureWorker::abort(){}
301
void SMCaptureWorker::abort(){}
304
 
302
 
305
void SMCaptureWorker::stopWork(){
303
void SMCaptureWorker::stopWork(){
306
    working = false;
304
    working = false;
307
}
305
}
308
 
306
 
309
SMCaptureWorker::~SMCaptureWorker(){
307
SMCaptureWorker::~SMCaptureWorker(){
310
    delete projector;
308
    delete projector;
311
    delete camera0;
309
    delete camera0;
312
    delete camera1;
310
    delete camera1;
313
    delete rotationStage;
311
    delete rotationStage;
314
}
312
}
315
 
313