Added projection to perspective and OpenMP support.
This commit is contained in:
parent
80c4a9c0a1
commit
bd6948ecdc
5 changed files with 157 additions and 19 deletions
|
|
@ -1,6 +1,7 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -std=c++17 -Wall -Wextra -pedantic -g
|
||||
INCLUDES = -I./include -ID:/Users/Jerome/Documents/Ingenierie/Programmation/eigen-3.4.0 -I./stb-master
|
||||
LDFLAGS = -fopenmp
|
||||
|
||||
SRC_DIR = src
|
||||
OBJ_DIR = obj
|
||||
|
|
@ -14,10 +15,10 @@ EXEC = $(OBJ_DIR)/360_to_perspective
|
|||
all: $(EXEC)
|
||||
|
||||
$(EXEC): $(OBJS)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $<
|
||||
$(CXX) $(CXXFLAGS) $(INCLUDES) $(LDFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJ_DIR):
|
||||
mkdir -p $@
|
||||
|
|
|
|||
|
|
@ -31,19 +31,24 @@ class Image {
|
|||
/// @param width_ Width of the image.
|
||||
/// @param height_ Height of the image.
|
||||
/// @param depth_ Depth of the image.
|
||||
Image(int width_, int height_, int depth_ = 1);
|
||||
Image(int width_ = 1, int height_ = 1, int depth_ = 1);
|
||||
|
||||
/// @brief Copies another image. Performs a deep copy.
|
||||
/// @param other The image to copy.
|
||||
Image(Image const& other);
|
||||
|
||||
/// @brief Frees the allocated memory of the image.
|
||||
~Image();
|
||||
|
||||
/// @brief Loads an image from a file.
|
||||
/// @param filename Path to the image file.
|
||||
Image(std::string const& filename);
|
||||
|
||||
/// @brief Frees the allocated memory of the image.
|
||||
~Image();
|
||||
|
||||
/// @brief Copies the other image into this one. Performs a deep copy.
|
||||
/// @param other Image to copy.
|
||||
/// @return A reference to this image.
|
||||
Image & operator=(Image const& other);
|
||||
|
||||
/// @brief Saves the image to a file.
|
||||
/// Supports the following formats : PNG, BMP, TGA, JPG. The format is determined from the file extension.
|
||||
/// @param filename Path to save the image to.
|
||||
|
|
|
|||
|
|
@ -4,21 +4,71 @@
|
|||
#include <Camera.hpp>
|
||||
#include <Image.hpp>
|
||||
|
||||
/// @brief This class encapsulates the algorithms to convert a 360-degree image to a perspective image.
|
||||
/// @brief This class encapsulates the algorithms to convert a 360-degree image to perspective images.
|
||||
/// @details The 360-degree image is converted to perspective images by projecting the pixels of the 360-degree image using perspective projection and virtual cameras.
|
||||
/// The virtual cameras are added to the slicer using the AddCamera() method.
|
||||
/// The output images are saved in the folder specified by the SetOutputFolder() method.
|
||||
/// By default, the ProjectToCameras and ProjectToAllCameras are parallelized using OpenMP.
|
||||
/// If the DO_NOT_USE_OPENMP macro is defined, the OpenMP parallization is disabled and the computation is sequential regardless of the value of "parallel".
|
||||
class Slicer360ToPerspective {
|
||||
public:
|
||||
Slicer360ToPerspective();
|
||||
/// @brief Builds a Slicer360ToPerspective object using a 360-degree image.
|
||||
/// @param panorama_image The 360-degree image to be used as an input.
|
||||
Slicer360ToPerspective(Image const& panorama_image_ = Image(1,1,3));
|
||||
|
||||
/// @brief Sets the width of the output images.
|
||||
/// @param width Width of the output images in pixels.
|
||||
/// @param height Height of the output images in pixels. By default = -1. If < 0, the height is set to the width to yield a square image.
|
||||
/// @return A reference to the current object.
|
||||
Slicer360ToPerspective & SetOutputImageSize(int width, int height = -1);
|
||||
|
||||
/// @brief Sets the interpolation method used to project the 360-degree image to perspective images. See Image::InterpMethod.
|
||||
/// @param interpolation_method_ Interpolation method used to project the 360-degree image to perspective images.
|
||||
/// @return A reference to the current object.
|
||||
Slicer360ToPerspective & SetInterpolationMethod(Image::InterpMethod const& interpolation_method_);
|
||||
|
||||
/// @brief Sets the folder where the output images are saved. By default, the output images are saved in the current folder.
|
||||
/// @param folder Folder where the output images are saved.
|
||||
/// @return A reference to the current object.
|
||||
Slicer360ToPerspective & SetOutputFolder(std::string const& folder);
|
||||
|
||||
/// @brief Computes the coverage of the 360-degree image by the cameras added to the slicer.
|
||||
/// @param width Width of the generated 360-degree image containing the results of the analysis.
|
||||
/// @param raw If true, the output is the number of cameras that see the pixel of the 360 image (8-bit monochrome image). If false, the output is a colored RGB image.
|
||||
/// @return The coverage of the 360-degree image.
|
||||
Image ComputeCoverage(int width, bool raw = false);
|
||||
Image ComputeCoverage(int width, bool raw = false) const;
|
||||
|
||||
/// @brief Projects the 360-degree image to a perspective image using the specified camera.
|
||||
/// @param camera The camera used to project the 360-degree image.
|
||||
/// @return The generated perspective image.
|
||||
Image ProjectToCamera(Camera const& camera, bool parallel = true) const;
|
||||
|
||||
/// @brief Projects the 360-degree image to perspective images using the specified cameras.
|
||||
/// @param cameras A vector of cameras used to project the 360-degree image.
|
||||
/// @param parallel If true, the projection is done in parallel using all the available cores.
|
||||
/// @return A vector of generated perspective images.
|
||||
std::vector<Image> ProjectToCameras(std::vector<Camera> const& cameras_, bool parallel = true) const;
|
||||
|
||||
/// @brief Projects the 360-degree image to perspective images using all the cameras added to the slicer.
|
||||
/// @param parallel If true, the projection is done in parallel using all the available cores.
|
||||
/// @return A vector of generated perspective images.
|
||||
std::vector<Image> ProjectToAllCameras(bool parallel = true) const;
|
||||
|
||||
std::vector<Camera> cameras;//!< A vector of cameras that are used to convert the 360-degree image to perspective images.
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Computes the projection of the 360-degree image to a perspective image using the specified camera on a single pixel of the output image.
|
||||
/// @param camera The camera used to project the 360-degree image.
|
||||
/// @param i The y-coordinate of the pixel of the output image (row).
|
||||
/// @param j The x-coordinate of the pixel of the output image (column).
|
||||
/// @return The color of the pixel of the output image.
|
||||
Eigen::Vector3i ProjectToCameraPixel(Camera const& camera, int i, int j) const;
|
||||
|
||||
Image panorama_image; //!< The 360-degree input image.
|
||||
int output_image_width; //!< Width of the output images in pixels.
|
||||
int output_image_height; //!< Height of the output images in pixels.
|
||||
Image::InterpMethod interpolation_method; //!< Interpolation method used to project the 360-degree image to perspective images.
|
||||
std::string output_folder; //!< Folder where the output images are saved.
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -9,10 +9,6 @@ Image::Image(Image const& other) : width(other.width), height(other.height), dep
|
|||
std::memcpy(data, other.data, width * height * depth);
|
||||
}
|
||||
|
||||
Image::~Image() {
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
Image::Image(std::string const& filename) {
|
||||
// Load image data using stb_image.h
|
||||
unsigned char* image_data = stbi_load(filename.c_str(), &width, &height, &depth, 0);
|
||||
|
|
@ -31,6 +27,25 @@ Image::Image(std::string const& filename) {
|
|||
}
|
||||
}
|
||||
|
||||
Image::~Image() {
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
Image & Image::operator=(Image const& other) {
|
||||
// Delete current data
|
||||
delete[] data;
|
||||
|
||||
// Copy image attributes
|
||||
width = other.width;
|
||||
height = other.height;
|
||||
depth = other.depth;
|
||||
|
||||
// Allocate new data and copy the data from other.data.
|
||||
data = new unsigned char[width * height * depth];
|
||||
std::memcpy(data, other.data, width * height * depth);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int Image::Save(std::string const& filename) const {
|
||||
if(filename.size() > 4 && filename.substr(filename.size() - 4) == ".png")
|
||||
return stbi_write_png(filename.c_str(), width, height, depth, (const void *)data, 0);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,30 @@
|
|||
#include <Slicer360ToPerspective.hpp>
|
||||
#include <frame_conversions.hpp>
|
||||
|
||||
Slicer360ToPerspective::Slicer360ToPerspective()
|
||||
{
|
||||
|
||||
#ifndef DO_NOT_USE_OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
Slicer360ToPerspective::Slicer360ToPerspective(Image const& panorama_image_) : panorama_image(panorama_image_), output_image_width(2), interpolation_method(Image::InterpMethod::BILINEAR), output_folder(".")
|
||||
{}
|
||||
|
||||
Slicer360ToPerspective & Slicer360ToPerspective::SetOutputImageSize(int width, int height) {
|
||||
output_image_width = (width > 0) ? width : 1024;
|
||||
output_image_height = (height > 0) ? height : output_image_width;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Image Slicer360ToPerspective::ComputeCoverage(int width, bool raw)
|
||||
{
|
||||
Slicer360ToPerspective & Slicer360ToPerspective::SetInterpolationMethod(Image::InterpMethod const& interpolation_method_) {
|
||||
interpolation_method = interpolation_method_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Slicer360ToPerspective & Slicer360ToPerspective::SetOutputFolder(std::string const& folder) {
|
||||
output_folder = folder;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Image Slicer360ToPerspective::ComputeCoverage(int width, bool raw) const {
|
||||
int height = width/2;
|
||||
Image coverage(width, height, 1);
|
||||
|
||||
|
|
@ -32,3 +49,53 @@ Image Slicer360ToPerspective::ComputeCoverage(int width, bool raw)
|
|||
else
|
||||
return coverage.Normalized().Colorized(Image::Colormap::PARULA);
|
||||
}
|
||||
|
||||
Eigen::Vector3i Slicer360ToPerspective::ProjectToCameraPixel(Camera const& camera, int i, int j) const {
|
||||
// Get the ray direction in inertial frame by projecting the pixel to the sphere
|
||||
// Eigen::Vector2d Camera::PixelToNormalizedCoordinates(unsigned int i, unsigned int j, unsigned int width, unsigned int height) {
|
||||
Eigen::Vector2d p_sensor = Camera::PixelToNormalizedCoordinates(i, j, output_image_width, output_image_height);
|
||||
p_sensor[0] *= -1;
|
||||
p_sensor[1] *= ((double)output_image_height)/((double)output_image_width);// Take aspect ratio into account.
|
||||
|
||||
// Compute ray direction from sensor coordinates
|
||||
Eigen::Vector3d ray_dir = camera.ComputeRayDirInInertialFrame(p_sensor);
|
||||
Eigen::Vector3d ray_dir_sph = cart2sph(ray_dir);
|
||||
Eigen::Vector2d p_equi = sph2equirectangular_d(ray_dir_sph, output_image_width, output_image_height);
|
||||
return panorama_image.GetPixelInterp(p_equi, interpolation_method);
|
||||
}
|
||||
|
||||
Image Slicer360ToPerspective::ProjectToCamera(Camera const& camera, bool parallel) const {
|
||||
Image image(output_image_width, output_image_height, 3);
|
||||
if(parallel) {
|
||||
#ifndef DO_NOT_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for(int i = 0 ; i < output_image_height ; i++)
|
||||
for(int j = 0 ; j < output_image_width ; j++)
|
||||
image.SetPixel(i, j, ProjectToCameraPixel(camera, i, j));
|
||||
} else {
|
||||
for(int i = 0 ; i < output_image_height ; i++)
|
||||
for(int j = 0 ; j < output_image_width ; j++)
|
||||
image.SetPixel(i, j, ProjectToCameraPixel(camera, i, j));
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
std::vector<Image> Slicer360ToPerspective::ProjectToCameras(std::vector<Camera> const& cameras_, bool parallel) const {
|
||||
std::vector<Image> images(cameras_.size());
|
||||
if(parallel) {
|
||||
#ifndef DO_NOT_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for(unsigned int i = 0 ; i < cameras_.size(); i++)
|
||||
images[i] = ProjectToCamera(cameras_[i], false);// Parallelization is already done at the camera level.
|
||||
} else {
|
||||
for(unsigned int i = 0 ; i < cameras_.size(); i++)
|
||||
images[i] = ProjectToCamera(cameras_[i], false);// Parallelization is already done at the camera level.
|
||||
}
|
||||
return images;
|
||||
}
|
||||
|
||||
std::vector<Image> Slicer360ToPerspective::ProjectToAllCameras(bool parallel) const {
|
||||
return ProjectToCameras(cameras, parallel);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue