/* ipm.cc
*
* Copyright (C) 2013 VisLab
*
* This file is part of lib3dv; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*/
#include "lib3dv/image.h"
#include "lib3dv/ipm.h"
#include
#include
#include
lib3dv::inverse_perspective_mapping::inverse_perspective_mapping(const calibration::camera_intrinsics& intrinsics, float baseline) :
m_intrinsics(intrinsics),
m_baseline(baseline),
m_transformation_matrix(NULL)
{}
lib3dv::inverse_perspective_mapping::inverse_perspective_mapping(const calibration::camera_intrinsics& intrinsics, const calibration::position& position, const calibration::orientation& orientation, float baseline) :
m_intrinsics(intrinsics),
m_baseline(baseline)
{
m_transformation_matrix = new float[12];
const float u0 = intrinsics.m_u0;
const float v0 = intrinsics.m_v0;
const float ku = intrinsics.m_ku;
const float kv = intrinsics.m_kv;
const float x = position.m_x;
const float y = position.m_y;
const float z = position.m_z;
const float yaw = orientation.m_yaw;
const float pitch = orientation.m_pitch;
const float roll = orientation.m_roll;
m_transformation_matrix[0] = cos(pitch) * cos(yaw);
m_transformation_matrix[1] = sin(roll) * sin(pitch) * cos(yaw) - cos(roll) * sin(yaw);
m_transformation_matrix[2] = cos(roll) * sin(pitch) * cos(yaw) + sin(roll) * sin(yaw);
m_transformation_matrix[4] = cos(pitch) * sin(yaw);
m_transformation_matrix[5] = sin(roll) * sin(pitch) * sin(yaw) + cos(roll) * cos(yaw);
m_transformation_matrix[6] = cos(roll) * sin(pitch) * sin(yaw) - sin(roll) * cos(yaw);
m_transformation_matrix[8] = -sin(pitch);
m_transformation_matrix[9] = sin(roll) * cos(pitch);
m_transformation_matrix[10] = cos(roll) * cos(pitch);
m_transformation_matrix[3] = x;
m_transformation_matrix[7] = y;
m_transformation_matrix[11] = z;
m_transformation_matrix[0] *= ku * baseline;
m_transformation_matrix[1] *= -baseline;
m_transformation_matrix[2] *= -baseline * ku / kv;
m_transformation_matrix[4] *= ku * baseline;
m_transformation_matrix[5] *= -baseline;
m_transformation_matrix[6] *= -baseline * ku / kv;
m_transformation_matrix[8] *= ku * baseline;
m_transformation_matrix[9] *= -baseline;
m_transformation_matrix[10] *= -baseline * ku / kv;
}
lib3dv::inverse_perspective_mapping::~inverse_perspective_mapping()
{
delete[] m_transformation_matrix;
}
bool lib3dv::inverse_perspective_mapping::operator()(boost::shared_ptr dsi, std::vector& world_points)
{
if(dsi->m_type != lib3dv::image::type::DSI || dsi->m_format != lib3dv::image::format::MONO16 || dsi->m_bpp != 16 || dsi->m_channels != 1)
{
std::cerr << "[EE] lib3dv : invalid DSI supplied" << std::endl;
return false;
}
world_points.reserve(world_points.size() + dsi->m_width * dsi->m_height);
const uint16_t* buffer = reinterpret_cast(dsi->m_buffer.data());
if(!m_transformation_matrix)
{
const float u0 = m_intrinsics.m_u0;
const float v0 = m_intrinsics.m_v0;
const float ku = m_intrinsics.m_ku;
const float kv = m_intrinsics.m_kv;
const float ku_b = ku * m_baseline;
const float inv_kv = 1.0f / kv;
const float ku_b_inv_kv = ku_b * inv_kv;
for(unsigned int i = 0; i < dsi->m_height; ++i)
{
const float iv0_ku_b_inv_kv = (i - v0) * ku_b_inv_kv;
for(unsigned int j = 0; j < dsi->m_width; ++j)
{
const uint16_t raw_disparity = buffer[i * dsi->m_width + j];
lib3dv::point3 point;
if(raw_disparity != 0xFFFF)
{
const float inv_disparity = 256.0f / raw_disparity;
point.m_x = (j - u0) * m_baseline * inv_disparity;
point.m_y = iv0_ku_b_inv_kv * inv_disparity;
point.m_z = ku_b * inv_disparity;
}
else
{
point.m_x = 0;
point.m_y = 0;
point.m_z = std::numeric_limits::max();
}
world_points.push_back(point);
}
}
}
else
{
for(unsigned int i = 0; i < dsi->m_height; ++i)
{
for(unsigned int j = 0; j < dsi->m_width; ++j)
{
const uint16_t raw_disparity = buffer[i * dsi->m_width + j];
point3 point;
if(raw_disparity != 0xFFFF)
{
const float inv_disparity = 256.0f / raw_disparity;
const float x = inv_disparity;
const float y = (j - m_intrinsics.m_u0) * inv_disparity;
const float z = (i - m_intrinsics.m_v0) * inv_disparity;
point.m_x = m_transformation_matrix[0] * x + m_transformation_matrix[1] * y + m_transformation_matrix[2] * z + m_transformation_matrix[3];
point.m_y = m_transformation_matrix[4] * x + m_transformation_matrix[5] * y + m_transformation_matrix[6] * z + m_transformation_matrix[7];
point.m_z = m_transformation_matrix[8] * x + m_transformation_matrix[9] * y + m_transformation_matrix[10] * z + m_transformation_matrix[11];
}
else
{
point.m_x = std::numeric_limits::max();
point.m_y = 0;
point.m_z = 0;
}
world_points.push_back(point);
}
}
}
return true;
}