15 #include "reconstruct3d.h" 16 #include "visiontransfer/alignedallocator.h" 26 #include <immintrin.h> 28 #include <emmintrin.h> 35 class Reconstruct3D::Pimpl {
39 float* createPointMap(
const unsigned short* dispMap,
int width,
int height,
40 int rowStride,
const float* q,
unsigned short minDisparity);
42 float* createPointMap(
const ImagePair& imagePair,
unsigned short minDisparity);
44 void projectSinglePoint(
int imageX,
int imageY,
unsigned short disparity,
const float* q,
45 float& pointX,
float& pointY,
float& pointZ);
47 void writePlyFile(
const char* file,
const unsigned short* dispMap,
48 const unsigned char* image,
int width,
int height,
bool isRgb,
49 int dispRowStride,
int imageRowStride,
const float* q,
50 double maxZ,
bool binary);
52 void writePlyFile(
const char* file,
const ImagePair& imagePair,
53 double maxZ,
bool binary);
56 std::vector<float, AlignedAllocator<float> > pointMap;
58 float* createPointMapFallback(
const unsigned short* dispMap,
int width,
int height,
59 int rowStride,
const float* q,
unsigned short minDisparity);
61 float* createPointMapSSE2(
const unsigned short* dispMap,
int width,
int height,
62 int rowStride,
const float* q,
unsigned short minDisparity);
64 float* createPointMapAVX2(
const unsigned short* dispMap,
int width,
int height,
65 int rowStride,
const float* q,
unsigned short minDisparity);
74 Reconstruct3D::~Reconstruct3D() {
79 int rowStride,
const float* q,
unsigned short minDisparity) {
80 return pimpl->createPointMap(dispMap, width, height, rowStride, q, minDisparity);
84 return pimpl->createPointMap(imagePair, minDisparity);
88 const float* q,
float& pointX,
float& pointY,
float& pointZ) {
89 pimpl->projectSinglePoint(imageX, imageY, disparity, q, pointX, pointY, pointZ);
93 const unsigned char* image,
int width,
int height,
bool isRgb,
int dispRowStride,
94 int imageRowStride,
const float* q,
double maxZ,
bool binary) {
95 pimpl->writePlyFile(file, dispMap, image, width, height, isRgb, dispRowStride,
96 imageRowStride, q, maxZ, binary);
100 double maxZ,
bool binary) {
101 pimpl->writePlyFile(file, imagePair, maxZ, binary);
106 Reconstruct3D::Pimpl::Pimpl() {
109 float* Reconstruct3D::Pimpl::createPointMap(
const unsigned short* dispMap,
int width,
110 int height,
int rowStride,
const float* q,
unsigned short minDisparity) {
113 if(pointMap.size() !=
static_cast<unsigned int>(4*width*height)) {
114 pointMap.resize(4*width*height);
118 return createPointMapAVX2(dispMap, width, height, rowStride, q, minDisparity);
120 return createPointMapSSE2(dispMap, width, height, rowStride, q, minDisparity);
122 return createPointMapFallback(dispMap, width, height, rowStride, q, minDisparity);
126 float* Reconstruct3D::Pimpl::createPointMap(
const ImagePair& imagePair,
unsigned short minDisparity) {
128 throw std::runtime_error(
"Disparity map must have 12-bit pixel format!");
135 float* Reconstruct3D::Pimpl::createPointMapFallback(
const unsigned short* dispMap,
int width,
136 int height,
int rowStride,
const float* q,
unsigned short minDisparity) {
138 float* outputPtr = &pointMap[0];
139 int stride = rowStride / 2;
141 for(
int y = 0; y < height; y++) {
142 double qx = q[1]*y + q[3];
143 double qy = q[5]*y + q[7];
144 double qz = q[9]*y + q[11];
145 double qw = q[13]*y + q[15];
147 for(
int x = 0; x < width; x++) {
148 unsigned short intDisp = std::max(minDisparity, dispMap[y*stride + x]);
149 if(intDisp >= 0xFFF) {
150 intDisp = minDisparity;
153 double d = intDisp / 16.0;
154 double w = qw + q[14]*d;
156 *outputPtr =
static_cast<float>((qx + q[2]*d)/w);
159 *outputPtr =
static_cast<float>((qy + q[6]*d)/w);
162 *outputPtr =
static_cast<float>((qz + q[10]*d)/w);
174 void Reconstruct3D::Pimpl::projectSinglePoint(
int imageX,
int imageY,
unsigned short disparity,
175 const float* q,
float& pointX,
float& pointY,
float& pointZ) {
177 double qx = q[1]*imageY + q[3];
178 double qy = q[5]*imageY + q[7];
179 double qz = q[9]*imageY + q[11];
180 double qw = q[13]*imageY + q[15];
182 double d = disparity / 16.0;
183 double w = qw + q[14]*d;
185 pointX =
static_cast<float>((qx + q[2]*d)/w);
186 pointY =
static_cast<float>((qy + q[6]*d)/w);
187 pointZ =
static_cast<float>((qz + q[10]*d)/w);
191 float* Reconstruct3D::Pimpl::createPointMapAVX2(
const unsigned short* dispMap,
int width,
192 int height,
int rowStride,
const float* q,
unsigned short minDisparity) {
195 const __m256 qCol0 = _mm256_setr_ps(q[0], q[4], q[8], q[12], q[0], q[4], q[8], q[12]);
196 const __m256 qCol1 = _mm256_setr_ps(q[1], q[5], q[9], q[13], q[1], q[5], q[9], q[13]);
197 const __m256 qCol2 = _mm256_setr_ps(q[2], q[6], q[10], q[14], q[2], q[6], q[10], q[14]);
198 const __m256 qCol3 = _mm256_setr_ps(q[3], q[7], q[11], q[15], q[3], q[7], q[11], q[15]);
201 const __m256i minDispVector = _mm256_set1_epi16(minDisparity);
202 const __m256i maxDispVector = _mm256_set1_epi16(0xFFF);
203 const __m256 scaleVector = _mm256_set1_ps(1.0/16.0);
204 const __m256i zeroVector = _mm256_set1_epi16(0);
206 float* outputPtr = &pointMap[0];
208 for(
int y = 0; y < height; y++) {
209 const unsigned char* rowStart = &
reinterpret_cast<const unsigned char*
>(dispMap)[y*rowStride];
210 const unsigned char* rowEnd = &
reinterpret_cast<const unsigned char*
>(dispMap)[y*rowStride + 2*width];
213 for(
const unsigned char* ptr = rowStart; ptr != rowEnd; ptr += 32) {
214 __m256i disparities = _mm256_load_si256(reinterpret_cast<const __m256i*>(ptr));
217 __m256i validMask = _mm256_cmpgt_epi16(maxDispVector, disparities);
218 disparities = _mm256_and_si256(validMask, disparities);
221 disparities = _mm256_max_epi16(disparities, minDispVector);
224 __m256i disparitiesMixup = _mm256_permute4x64_epi64(disparities, 0xd8);
227 __m256 floatDisp = _mm256_cvtepi32_ps(_mm256_unpacklo_epi16(disparitiesMixup, zeroVector));
228 __m256 dispScaled = _mm256_mul_ps(floatDisp, scaleVector);
232 __declspec(align(32))
float dispArray[16];
234 float dispArray[16]__attribute__((aligned(32)));
236 _mm256_store_ps(&dispArray[0], dispScaled);
239 floatDisp = _mm256_cvtepi32_ps(_mm256_unpackhi_epi16(disparitiesMixup, zeroVector));
240 dispScaled = _mm256_mul_ps(floatDisp, scaleVector);
241 _mm256_store_ps(&dispArray[8], dispScaled);
244 for(
int i=0; i<16; i+=2) {
246 __m256 vec = _mm256_setr_ps(x, y, dispArray[i], 1.0,
247 x+1, y, dispArray[i+1], 1.0);
250 __m256 u1 = _mm256_shuffle_ps(vec,vec, _MM_SHUFFLE(0,0,0,0));
251 __m256 u2 = _mm256_shuffle_ps(vec,vec, _MM_SHUFFLE(1,1,1,1));
252 __m256 u3 = _mm256_shuffle_ps(vec,vec, _MM_SHUFFLE(2,2,2,2));
253 __m256 u4 = _mm256_shuffle_ps(vec,vec, _MM_SHUFFLE(3,3,3,3));
255 __m256 prod1 = _mm256_mul_ps(u1, qCol0);
256 __m256 prod2 = _mm256_mul_ps(u2, qCol1);
257 __m256 prod3 = _mm256_mul_ps(u3, qCol2);
258 __m256 prod4 = _mm256_mul_ps(u4, qCol3);
260 __m256 multResult = _mm256_add_ps(_mm256_add_ps(prod1, prod2), _mm256_add_ps(prod3, prod4));
263 __m256 point = _mm256_div_ps(multResult,
264 _mm256_shuffle_ps(multResult,multResult, _MM_SHUFFLE(3,3,3,3)));
267 _mm256_store_ps(outputPtr, point);
280 float* Reconstruct3D::Pimpl::createPointMapSSE2(
const unsigned short* dispMap,
int width,
281 int height,
int rowStride,
const float* q,
unsigned short minDisparity) {
284 const __m128 qCol0 = _mm_setr_ps(q[0], q[4], q[8], q[12]);
285 const __m128 qCol1 = _mm_setr_ps(q[1], q[5], q[9], q[13]);
286 const __m128 qCol2 = _mm_setr_ps(q[2], q[6], q[10], q[14]);
287 const __m128 qCol3 = _mm_setr_ps(q[3], q[7], q[11], q[15]);
290 const __m128i minDispVector = _mm_set1_epi16(minDisparity);
291 const __m128i maxDispVector = _mm_set1_epi16(0xFFF);
292 const __m128 scaleVector = _mm_set1_ps(1.0/16.0);
293 const __m128i zeroVector = _mm_set1_epi16(0);
295 float* outputPtr = &pointMap[0];
297 for(
int y = 0; y < height; y++) {
298 const unsigned char* rowStart = &
reinterpret_cast<const unsigned char*
>(dispMap)[y*rowStride];
299 const unsigned char* rowEnd = &
reinterpret_cast<const unsigned char*
>(dispMap)[y*rowStride + 2*width];
302 for(
const unsigned char* ptr = rowStart; ptr != rowEnd; ptr += 16) {
303 __m128i disparities = _mm_load_si128(reinterpret_cast<const __m128i*>(ptr));
306 __m128i validMask = _mm_cmplt_epi16(disparities, maxDispVector);
307 disparities = _mm_and_si128(validMask, disparities);
310 disparities = _mm_max_epi16(disparities, minDispVector);
313 __m128 floatDisp = _mm_cvtepi32_ps(_mm_unpacklo_epi16(disparities, zeroVector));
314 __m128 dispScaled = _mm_mul_ps(floatDisp, scaleVector);
318 __declspec(align(16))
float dispArray[8];
320 float dispArray[8]__attribute__((aligned(16)));
322 _mm_store_ps(&dispArray[0], dispScaled);
325 floatDisp = _mm_cvtepi32_ps(_mm_unpackhi_epi16(disparities, zeroVector));
326 dispScaled = _mm_mul_ps(floatDisp, scaleVector);
327 _mm_store_ps(&dispArray[4], dispScaled);
330 for(
int i=0; i<8; i++) {
332 __m128 vec = _mm_setr_ps(static_cast<float>(x), static_cast<float>(y), dispArray[i], 1.0);
335 __m128 u1 = _mm_shuffle_ps(vec,vec, _MM_SHUFFLE(0,0,0,0));
336 __m128 u2 = _mm_shuffle_ps(vec,vec, _MM_SHUFFLE(1,1,1,1));
337 __m128 u3 = _mm_shuffle_ps(vec,vec, _MM_SHUFFLE(2,2,2,2));
338 __m128 u4 = _mm_shuffle_ps(vec,vec, _MM_SHUFFLE(3,3,3,3));
340 __m128 prod1 = _mm_mul_ps(u1, qCol0);
341 __m128 prod2 = _mm_mul_ps(u2, qCol1);
342 __m128 prod3 = _mm_mul_ps(u3, qCol2);
343 __m128 prod4 = _mm_mul_ps(u4, qCol3);
345 __m128 multResult = _mm_add_ps(_mm_add_ps(prod1, prod2), _mm_add_ps(prod3, prod4));
348 __m128 point = _mm_div_ps(multResult,
349 _mm_shuffle_ps(multResult,multResult, _MM_SHUFFLE(3,3,3,3)));
352 _mm_store_ps(outputPtr, point);
364 void Reconstruct3D::Pimpl::writePlyFile(
const char* file,
const unsigned short* dispMap,
365 const unsigned char* image,
int width,
int height,
bool isRgb,
int dispRowStride,
366 int imageRowStride,
const float* q,
double maxZ,
bool binary) {
368 float* pointMap =
createPointMap(dispMap, width, height, dispRowStride, q, maxZ >= 0 ? 1 : 0);
373 for(
int i=0; i<width*height; i++) {
374 if(pointMap[4*i+2] <= maxZ) {
379 pointsCount = width*height;
383 fstream strm(file, binary ? (ios::out | ios::binary) : ios::out);
384 strm <<
"ply" << endl;
387 strm <<
"format binary_little_endian 1.0" << endl;
389 strm <<
"format ascii 1.0" << endl;
392 strm <<
"element vertex " << pointsCount << endl
393 <<
"property float x" << endl
394 <<
"property float y" << endl
395 <<
"property float z" << endl
396 <<
"property uchar red" << endl
397 <<
"property uchar green" << endl
398 <<
"property uchar blue" << endl
399 <<
"end_header" << endl;
402 for(
int i=0; i<width*height; i++) {
405 const unsigned char* col = &image[y*imageRowStride + x];
407 if(maxZ < 0 || pointMap[4*i+2] <= maxZ) {
410 strm.write(reinterpret_cast<char*>(&pointMap[4*i]),
sizeof(
float)*3);
412 strm.write(reinterpret_cast<const char*>(col), 3*
sizeof(*col));
414 strm.write(reinterpret_cast<const char*>(col),
sizeof(*col));
415 strm.write(reinterpret_cast<const char*>(col),
sizeof(*col));
416 strm.write(reinterpret_cast<const char*>(col),
sizeof(*col));
420 if(std::isfinite(pointMap[4*i + 2])) {
421 strm << pointMap[4*i]
422 <<
" " << pointMap[4*i + 1]
423 <<
" " << pointMap[4*i + 2];
425 strm <<
"NaN NaN NaN";
429 strm <<
" " <<
static_cast<int>(col[0])
430 <<
" " << static_cast<int>(col[1])
431 <<
" " <<
static_cast<int>(col[2]) << endl;
433 strm <<
" " <<
static_cast<int>(*col)
434 <<
" " <<
static_cast<int>(*col)
435 <<
" " <<
static_cast<int>(*col) << endl;
442 void Reconstruct3D::Pimpl::writePlyFile(
const char* file,
const ImagePair& imagePair,
443 double maxZ,
bool binary) {
446 throw std::runtime_error(
"Camera image must have 8-bit pixel format!");
449 throw std::runtime_error(
"Disparity map must have 12-bit pixel format!");
float * createPointMap(const unsigned short *dispMap, int width, int height, int rowStride, const float *q, unsigned short minDisparity=1)
Reconstructs the 3D location of each pixel in the given disparity map.
unsigned char * getPixelData(int imageNumber) const
Returns the pixel data for the given image.
const float * getQMatrix() const
Returns a pointer to the disparity-to-depth mapping matrix q.
int getWidth() const
Returns the width of each image.
Reconstruct3D()
Constructs a new object for 3D reconstructing.
void writePlyFile(const char *file, const unsigned short *dispMap, const unsigned char *image, int width, int height, bool isRgb, int dispRowStride, int imageRowStride, const float *q, double maxZ=std::numeric_limits< double >::max(), bool binary=false)
Projects the given disparity map to 3D points and exports the result to a PLY file.
A set of two images, which are usually the left camera image and the disparity map.
ImageFormat getPixelFormat(int imageNumber) const
Returns the pixel format for the given image.
int getHeight() const
Returns the height of each image.
int getRowStride(int imageNumber) const
Returns the row stride for the pixel data of one image.
void projectSinglePoint(int imageX, int imageY, unsigned short disparity, const float *q, float &pointX, float &pointY, float &pointZ)
Reconstructs the 3D location of one individual point.