Skip to content

Commit 23a06f1

Browse files
author
tsing
committedMar 31, 2017
Refactored reconstructor, Pending doc changes
1 parent 52fafed commit 23a06f1

9 files changed

+65
-220
lines changed
 

‎src/app/App.cpp

+17-12
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,32 @@ int main(int argc, char** argv)
3737
std::string suffix = p.get<std::string>("format");
3838

3939
// Initialize two file readers to load images from file
40-
SLS::ImageFileProcessor rightCam("rightCam");
41-
SLS::ImageFileProcessor leftCam("rightCam");
40+
SLS::ImageFileProcessor rightCamProcessor("rightCamProcessor");
41+
SLS::ImageFileProcessor leftCamProcessor("rightCamProcessor");
4242

4343
// Load images
4444
// void loadImages( const std::string &folder, std::string prefix, size_t numDigits, size_t startIdx, std::string suffix )
45-
rightCam.loadImages(rightCameraFolder, "", 4, 0,suffix);
46-
leftCam.loadImages(leftCameraFolder, "", 4, 0, suffix);
45+
rightCamProcessor.loadImages(rightCameraFolder, "", 4, 0,suffix);
46+
leftCamProcessor.loadImages(leftCameraFolder, "", 4, 0, suffix);
4747

4848
// Load configurations, mainly calibration parameters
49-
rightCam.loadConfig(rightConfigFile);
50-
leftCam.loadConfig(leftConfigFile);
49+
rightCamProcessor.loadConfig(rightConfigFile);
50+
leftCamProcessor.loadConfig(leftConfigFile);
5151

52-
// Initialize a reconstructor with the resolution of the projection to project patterns
53-
SLS::ReconstructorCPU reconstruct(p.get<size_t>("width"), p.get<size_t>("height"));
52+
SLS::Projector proj(p.get<size_t>("width"),p.get<size_t>("height"));
5453

55-
// Add cameras to reconstructor
56-
reconstruct.addImageProcessor(&rightCam);
57-
reconstruct.addImageProcessor(&leftCam);
54+
// Generate reconstruction buckets from image processors
55+
std::vector<SLS::Buckets> bucketsVec
56+
{
57+
rightCamProcessor.generateBuckets(proj.getWidth(), proj.getHeight(), proj.getRequiredNumFrames()),
58+
leftCamProcessor.generateBuckets(proj.getWidth(), proj.getHeight(), proj.getRequiredNumFrames())
59+
};
60+
61+
// Initialize a reconstruct
62+
SLS::ReconstructorCPU reconstruct;
5863

5964
// Run reconstructio and get the point cloud
60-
auto pointCloud = reconstruct.reconstruct();
65+
auto pointCloud = reconstruct.reconstruct(bucketsVec);
6166

6267
// Get extension of output file
6368
auto extension = output.substr(output.find_last_of(".")+1);

‎src/lib/core/ImageFileProcessor.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,10 @@ Ray ImageFileProcessor::getRay(const size_t &x, const size_t &y)
161161
ray.dir.w=0.0;
162162
ray.dir = camTransMat_*ray.dir;
163163
ray.dir=glm::normalize(ray.dir);
164+
ray.color = getColor(x, y);
164165
return ray;
165166
}
167+
166168
Ray ImageFileProcessor::getRay(const size_t &pixelIdx)
167169
{
168170
glm::vec2 undistorted = undistortPixel(pixelIdx);
@@ -181,7 +183,7 @@ Ray ImageFileProcessor::getRay(const size_t &pixelIdx)
181183
ray.dir.w=0.0;
182184
ray.dir = camTransMat_*ray.dir;
183185
ray.dir=glm::normalize(ray.dir);
184-
186+
ray.color = getColor(pixelIdx);
185187
return ray;
186188
}
187189

@@ -255,9 +257,7 @@ Buckets ImageFileProcessor::generateBuckets(size_t projWidth, size_t projHeight,
255257
}
256258
if (!discard) {
257259
auto vec2Idx = bits.to_uint_gray();
258-
if (projWidth > vec2Idx.x &&
259-
projHeight > vec2Idx.y)
260-
bkts[vec2Idx.x * projHeight + vec2Idx.y].push_back(i);
260+
bkts[vec2Idx.x * projHeight + vec2Idx.y].push_back(getRay(i));
261261
}
262262
}
263263
return bkts;

‎src/lib/core/ImageFileProcessor.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ class ImageFileProcessor: public ImageProcessor
3333
size_t frameIdx_;
3434
std::array<cv::Mat, PARAM_COUNT> params_;
3535
glm::mat4 camTransMat_; //Transformation matrix for camera
36-
std::vector<Ray> rayTable;
3736
glm::vec2 undistortPixel(const glm::vec2 &distortedPixel) const;
3837
glm::vec2 undistortPixel(const size_t &distortedIdx) const
3938
{
@@ -89,7 +88,7 @@ class ImageFileProcessor: public ImageProcessor
8988
const cv::Mat& getNextFrame() override;
9089
void undistort() override;
9190
void computeShadowsAndThresholds() override;
92-
void setResolution (const size_t &x, const size_t &y) override {resX_ = x; resY_ = y; rayTable.resize(resX_*resY_);}
91+
void setResolution (const size_t &x, const size_t &y) override {resX_ = x; resY_ = y;}
9392
unsigned char getWhiteThreshold(size_t i) const { return thresholds_[i];}
9493
Buckets generateBuckets(size_t projWidth, size_t projHeight, size_t requiredNumFrames) override;
9594
};

‎src/lib/core/ImageProcessor.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ namespace SLS {
5454
*
5555
*/
5656

57-
using Buckets = std::vector<std::vector<size_t>>;
57+
using Bucket = std::vector<Ray>;
58+
using Buckets = std::vector<Bucket>;
5859

5960
class ImageProcessor {
6061
protected:
@@ -70,8 +71,7 @@ class ImageProcessor {
7071
cv::Mat litImage_; //!< An all lit image contains color information of
7172
//!reconstruction object
7273

73-
uchar
74-
whiteThreshold_; //!< Thresholds are used to filter out invalid pixel.
74+
uchar whiteThreshold_; //!< Thresholds are used to filter out invalid pixel.
7575

7676
// If the contrast of a pixel between lit and unlit is smaller than the
7777
// dark threshold, the pixel is invalid.

‎src/lib/core/Ray.h

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct Ray
99
{
1010
vec4 origin;
1111
vec4 dir;
12+
vec3 color; // RGB Color
1213
};
1314

1415
/**

‎src/lib/core/Reconstructor.h

+2-8
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,12 @@ namespace SLS
3030
class Reconstructor
3131
{
3232
protected:
33-
std::vector<ImageProcessor*> processors_;
34-
Projector* projector_;
35-
std::vector<uint> idx_;
3633
public:
37-
Reconstructor():projector_{nullptr}{};
34+
Reconstructor(){};
3835
virtual ~Reconstructor(){}
3936

4037
//! Reconstruct, return a point cloud
41-
virtual PointCloud reconstruct()=0;
42-
43-
//! Add a camera pointer to reconstructor
44-
virtual void addImageProcessor(ImageProcessor* processor)=0;
38+
virtual PointCloud reconstruct(const std::vector<Buckets>&)=0;
4539

4640
};
4741

‎src/lib/core/ReconstructorCPU.cpp

+16-157
Original file line numberDiff line numberDiff line change
@@ -5,112 +5,21 @@
55

66
namespace SLS {
77

8-
ReconstructorCPU::~ReconstructorCPU() { delete projector_; }
9-
void ReconstructorCPU::initBuckets()
10-
{
11-
size_t x, y;
12-
projector_->getSize(x, y);
13-
buckets_.resize(processors_.size());
14-
for (auto &b : buckets_) b.resize(x * y);
15-
generateBuckets();
16-
}
17-
18-
void ReconstructorCPU::addImageProcessor(ImageProcessor *processor) { processors_.push_back(processor); }
19-
void ReconstructorCPU::generateBuckets()
20-
{
21-
// Generating reconstruction bucket for each camera
22-
for (size_t camIdx = 0; camIdx < processors_.size(); camIdx++) {
23-
const auto &cam = processors_[camIdx];
24-
LOG::writeLog("Generating reconstruction bucket for \"%s\" ... \n",
25-
cam->getName().c_str());
26-
27-
cam->computeShadowsAndThresholds();
28-
29-
size_t x = 0, y = 0, xTimesY = 0;
30-
cam->getResolution(x, y);
31-
xTimesY = x * y;
32-
33-
// For each camera pixel
34-
for (size_t i = 0; i < xTimesY; i++) {
35-
if (!cam->queryMask(i)) // No need to process if in shadow
36-
continue;
37-
38-
// First two frames are lit and dark frame
39-
// not considered
40-
cam->getNextFrame();
41-
cam->getNextFrame(); // skip first two frames
42-
43-
Dynamic_Bitset bits(projector_->getRequiredNumFrames());
44-
45-
bool discard = false;
46-
47-
// for each frame
48-
for (int bitIdx = projector_->getRequiredNumFrames() - 1;
49-
bitIdx >= 0; bitIdx--) {
50-
auto frame = cam->getNextFrame();
51-
auto invFrame = cam->getNextFrame();
52-
unsigned char pixel = frame.at<uchar>(i % y, i / y);
53-
unsigned char invPixel = invFrame.at<uchar>(i % y, i / y);
54-
55-
// Not considering shadow mask. But the following test should be
56-
// more strict than shadow mask.
57-
if (invPixel > pixel &&
58-
invPixel - pixel >=
59-
((ImageFileProcessor *)cam)->getWhiteThreshold(i)) {
60-
// No need to do anything since the array is initialized as
61-
// all zeros
62-
bits.clearBit((size_t)bitIdx);
63-
continue;
64-
}
65-
else if (pixel > invPixel &&
66-
pixel - invPixel >
67-
((ImageFileProcessor *)cam)->getWhiteThreshold(i)) {
68-
bits.setBit((size_t)bitIdx);
69-
}
70-
else {
71-
cam->clearMask(i);
72-
discard = true;
73-
continue;
74-
}
75-
} // end for each frame
76-
77-
// if the pixel is valid, add to bucket.
78-
if (!discard) {
79-
auto vec2Idx = bits.to_uint_gray();
80-
if (projector_->getWidth() > vec2Idx.x &&
81-
vec2Idx.y < projector_->getHeight()) {
82-
buckets_[camIdx]
83-
[vec2Idx.x * projector_->getHeight() + vec2Idx.y]
84-
.push_back(i);
85-
}
86-
}
87-
}
88-
}
89-
}
90-
918
std::array<glm::vec3, 2> ReconstructorCPU::intersectionOfBucket_(
92-
size_t firstCameraIdx, size_t secondCameraIdx, size_t bucketIdx)
9+
const Bucket& firstBucket, const Bucket& secondBucket)
9310
{
94-
const std::vector<size_t> &firstBucket =
95-
buckets_[firstCameraIdx][bucketIdx];
96-
const std::vector<size_t> &secondBucket =
97-
buckets_[secondCameraIdx][bucketIdx];
9811
// for each camera pixels in two buckets
9912
size_t pointCount = 0;
10013
glm::vec3 averagePosition(0.0);
10114
glm::vec3 averageColor(0.0);
102-
for (const auto &cam0P : firstBucket)
103-
for (const auto &cam1P : secondBucket) {
15+
for (const auto &ray0 : firstBucket)
16+
for (const auto &ray1 : secondBucket) {
10417
float dist = -1.0f;
105-
glm::vec4 midP =
106-
midPoint(processors_[firstCameraIdx]->getRay(cam0P),
107-
processors_[secondCameraIdx]->getRay(cam1P), dist);
18+
glm::vec4 midP = midPoint(ray0, ray1, dist);
10819
if (dist > 0.0) {
10920
pointCount++;
11021
averagePosition += glm::vec3(midP);
111-
averageColor += (processors_[firstCameraIdx]->getColor(cam0P) +
112-
processors_[secondCameraIdx]->getColor(cam1P)) /
113-
2.0f;
22+
averageColor += (ray0.color + ray1.color) / 2.0f;
11423
}
11524
}
11625
if (pointCount != 0)
@@ -121,88 +30,38 @@ std::array<glm::vec3, 2> ReconstructorCPU::intersectionOfBucket_(
12130
}
12231

12332
std::array<glm::vec3, 2> ReconstructorCPU::intersectionOfBucketMinDist_(
124-
size_t firstCameraIdx, size_t secondCameraIdx, size_t bucketIdx)
33+
const Bucket &firstBucket, const Bucket &secondBucket)
12534
{
126-
const std::vector<size_t> &firstBucket =
127-
buckets_[firstCameraIdx][bucketIdx];
128-
const std::vector<size_t> &secondBucket =
129-
buckets_[secondCameraIdx][bucketIdx];
13035
// for each camera pixels in two buckets
13136
glm::vec3 minPosition(0.0);
13237
glm::vec3 minColor(0.0);
13338
float minDist = std::numeric_limits<float>::max();
134-
for (const auto &cam0P : firstBucket)
135-
for (const auto &cam1P : secondBucket) {
39+
for (const auto &ray0 : firstBucket)
40+
for (const auto &ray1 : secondBucket) {
13641
float dist = -1.0f;
137-
glm::vec4 midP =
138-
midPoint(processors_[firstCameraIdx]->getRay(cam0P),
139-
processors_[secondCameraIdx]->getRay(cam1P), dist);
42+
glm::vec4 midP = midPoint(ray0, ray1, dist);
14043
if (dist > 0.0 && dist < minDist) {
14144
minDist = dist;
14245
minPosition = glm::vec3(midP);
143-
minColor = (processors_[firstCameraIdx]->getColor(cam0P) +
144-
processors_[secondCameraIdx]->getColor(cam1P)) /
145-
2.0f;
46+
minColor = (ray0.color + ray1.color / 2.0f);
14647
}
14748
}
14849
return std::array<glm::vec3, 2>{minPosition, minColor};
14950
}
150-
PointCloud ReconstructorCPU::reconstruct()
51+
52+
PointCloud ReconstructorCPU::reconstruct(
53+
const std::vector<Buckets>& multiBuckets)
15154
{
15255
PointCloud res;
153-
size_t x, y;
154-
// Assumes all of the cameras has the same resolution
155-
processors_[0]->getResolution(x, y);
156-
initBuckets();
15756
LOG::startTimer();
158-
for (size_t i = 0; i < buckets_[0].size(); i++) {
159-
std::array<glm::vec3, 2> point = intersectionOfBucket_(0, 1, i);
57+
for (size_t i = 0; i < multiBuckets[0].size(); i++) {
58+
std::array<glm::vec3, 2> point =
59+
intersectionOfBucket_(multiBuckets[0][i], multiBuckets[1][i]);
16060
if (glm::all(glm::equal(point[0], glm::vec3(0.0))) &&
16161
glm::all(glm::equal(point[1], glm::vec3(0.0))))
16262
continue;
16363
else
16464
res.pushPoint(point[0], point[1]);
165-
166-
/*
167-
const auto &cam0bucket = buckets_[0][i];
168-
const auto &cam1bucket = buckets_[1][i];
169-
size_t minCam0Idx = 0;
170-
size_t minCam1Idx = 0;
171-
172-
// When non of the buckets are empty
173-
if ((!cam0bucket.empty()) && (!cam1bucket.empty())) {
174-
float minDist = std::numeric_limits<float>::max();
175-
glm::vec4 minMidP(0.0f);
176-
177-
float ptCount = 0.0;
178-
glm::vec4 midPointAvg(0.0f);
179-
180-
for (const auto &cam0P : cam0bucket)
181-
for (const auto &cam1P : cam1bucket) {
182-
float dist = -1.0f;
183-
184-
auto midP = midPoint(processors_[0]->getRay(cam0P),
185-
processors_[1]->getRay(cam1P), dist);
186-
if (dist > 0.0) // if dist is valid
187-
{
188-
ptCount += 1.0;
189-
midPointAvg += midP;
190-
if (dist < minDist) {
191-
minDist = dist;
192-
minMidP = midP;
193-
minCam0Idx = cam0P;
194-
minCam1Idx = cam1P;
195-
}
196-
}
197-
}
198-
midPointAvg = midPointAvg / ptCount;
199-
{
200-
auto color0 = processors_[0]->getColor(minCam0Idx);
201-
auto color1 = processors_[1]->getColor(minCam1Idx);
202-
res.pushPoint(glm::vec3(midPointAvg), (color0 + color1) / 2.0f);
203-
}
204-
}
205-
*/
20665
}
20766
LOG::endTimer("Finished reconstruction in ");
20867
return res;

‎src/lib/core/ReconstructorCPU.h

+5-24
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ namespace SLS {
3232
*/
3333
class ReconstructorCPU : public Reconstructor {
3434
private:
35-
std::vector<std::vector<std::vector<size_t>>>
36-
buckets_; //!< Buckets [camIdx][ProjPixelIdx][camPixelIdx]
37-
void initBuckets();
38-
void generateBuckets();
3935

4036
//! Find intersection of two projector pixel
4137
/*! Each projector pixel contains multiple camera pixels.
@@ -50,37 +46,22 @@ class ReconstructorCPU : public Reconstructor {
5046
* \param bucket1 Another bucket
5147
* \return midpoint and color
5248
*/
53-
std::array<glm::vec3, 2> intersectionOfBucket_(size_t firstCameraIdx,
54-
size_t secondCameraIdx,
55-
size_t bucketIdx);
49+
std::array<glm::vec3, 2> intersectionOfBucket_(const Bucket& firstBucket,
50+
const Bucket& secondBucket);
5651

5752
/*! Similar to intersectionOfBucket_(), this function finds pair of rays
5853
* with minimu distance to reconstruct the depth.
5954
*
6055
* This function is not used for now since the average method yield more
6156
* structural result.
6257
*/
63-
std::array<glm::vec3, 2> intersectionOfBucketMinDist_(size_t firstCameraIdx,
64-
size_t secondCameraIdx,
65-
size_t bucketIdx);
58+
std::array<glm::vec3, 2> intersectionOfBucketMinDist_(
59+
const Bucket& firstBucket, const Bucket& secondBucket);
6660

6761
public:
68-
/*! Create a reconstructor with given projector size
69-
*/
70-
ReconstructorCPU(const size_t projX, const size_t projY) : Reconstructor()
71-
{
72-
projector_ = new Projector(projX, projY);
73-
}
74-
~ReconstructorCPU() override;
7562

7663
// Interfaces
7764
//! Reconstruct point cloud.
78-
PointCloud reconstruct() override;
79-
80-
/*! Add a camera to reconstructor\
81-
*
82-
* Accepts two camera now.
83-
*/
84-
void addImageProcessor(ImageProcessor *processor) override;
65+
PointCloud reconstruct(const std::vector<Buckets>& multiBuckets) override;
8566
};
8667
} // namespace SLS

‎test/RunTest.cpp

+16-10
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,14 @@ TEST( RunCPUTest, Arch)
8686
LC.loadImages(L_IMGS, "", 4, 0, SUFFIX);
8787
LC.loadConfig(L_CFG);
8888

89-
SLS::ReconstructorCPU rec(W, H);
90-
rec.addImageProcessor(&LC);
91-
rec.addImageProcessor(&RC);
92-
auto pc = rec.reconstruct();
89+
SLS::Projector proj(W, H);
90+
SLS::ReconstructorCPU rec;
91+
auto pc = rec.reconstruct(std::vector<SLS::Buckets>{
92+
LC.generateBuckets(proj.getWidth(), proj.getHeight(),
93+
proj.getRequiredNumFrames()),
94+
RC.generateBuckets(proj.getWidth(), proj.getHeight(),
95+
proj.getRequiredNumFrames()),
96+
});
9397

9498
pc.exportPointCloud( O_PLY, "ply");
9599
pc.exportPointCloud( O_OBJ, "obj");
@@ -109,6 +113,7 @@ TEST( RunCPUTest, Alexander)
109113
const std::string TEST_OBJ = std::string(TEST_REF_PATH) + "/alexander.obj";
110114
const std::string O_PLY="alexander.ply", O_OBJ="alexander.obj";
111115

116+
SLS::Projector proj(W, H);
112117
auto RC = SLS::ImageFileProcessor("RightCamera");
113118
RC.loadImages(R_IMGS, "", 4, 0, SUFFIX);
114119
RC.loadConfig(R_CFG);
@@ -117,15 +122,16 @@ TEST( RunCPUTest, Alexander)
117122
LC.loadImages(L_IMGS, "", 4, 0, SUFFIX);
118123
LC.loadConfig(L_CFG);
119124

120-
SLS::ReconstructorCPU rec(W, H);
121-
rec.addImageProcessor(&LC);
122-
rec.addImageProcessor(&RC);
123-
auto pc = rec.reconstruct();
125+
SLS::ReconstructorCPU rec;
126+
auto pc = rec.reconstruct(std::vector<SLS::Buckets>{
127+
LC.generateBuckets(proj.getWidth(), proj.getHeight(),
128+
proj.getRequiredNumFrames()),
129+
RC.generateBuckets(proj.getWidth(), proj.getHeight(),
130+
proj.getRequiredNumFrames()),
131+
});
124132

125133
pc.exportPointCloud( O_PLY, "ply");
126134
pc.exportPointCloud( O_OBJ, "obj");
127135
EXPECT_TRUE(compareObjFiles(TEST_OBJ, O_OBJ));
128136
EXPECT_TRUE(comparePlyFiles(TEST_PLY, TEST_PLY));
129137
}
130-
131-

0 commit comments

Comments
 (0)
Please sign in to comment.