Version 1.0 : output folder is created automatically, everything is logged properly.
This commit is contained in:
parent
d550bc7f83
commit
03f635cae4
6 changed files with 84 additions and 25 deletions
|
|
@ -1,5 +1,5 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -std=c++17 -Wall -Wextra -pedantic -g
|
||||
CXXFLAGS = -std=c++17 -Wall -Wextra -pedantic -O3
|
||||
INCLUDES = -I./include -ID:/Users/Jerome/Documents/Ingenierie/Programmation/eigen-3.4.0 -I./stb-master -ID:/Users/Jerome/Documents/Ingenierie/Programmation/cmd_line_parser-master/include
|
||||
LDFLAGS = -fopenmp
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ class Camera {
|
|||
/// @brief Orients the camera according to the provided Euler angles. The position of the camera is (0,0,0).
|
||||
Camera & SetEulerAngles(double yaw, double pitch, double roll, bool radians = false);
|
||||
|
||||
/// @brief Returns the Euler angles of the camera (technically the Tait-Bryan ZYX angles).
|
||||
Eigen::Vector3d GetEulerAngles() const;
|
||||
|
||||
/// @brief Computes the ray direction in camera frame for a point (x,y) on the surface of the camera's sensor. p_norm is in normalized coordinates [-1;1].
|
||||
/// @param p_norm Normalized coordinates of the point on the sensor.
|
||||
/// @return The ray direction in camera frame, cartesian coordinates.
|
||||
|
|
|
|||
|
|
@ -159,6 +159,13 @@ class Image {
|
|||
/// @return Reference to the image.
|
||||
Image Colorized(unsigned char const* colormap) const;
|
||||
|
||||
/// @brief Resizes the image using the given interpolation method and returns the result. The original image is unchanged.
|
||||
/// @param width Width of the resized image.
|
||||
/// @param height Height of the resized image.
|
||||
/// @param interp_method Interpolation method to use.
|
||||
/// @return The resized image.
|
||||
Image Resized(int new_width, int new_height, InterpMethod const& interp_method = InterpMethod::BILINEAR) const;
|
||||
|
||||
std::tuple<unsigned char, unsigned char> ComputeMinMax() const;
|
||||
|
||||
std::tuple<unsigned char, unsigned char, double> ComputeMinMaxAvg() const;
|
||||
|
|
|
|||
|
|
@ -75,23 +75,60 @@ Camera & Camera::SetEulerAngles(double yaw, double pitch, double roll, bool radi
|
|||
roll *= DEG2RAD;
|
||||
}
|
||||
|
||||
// Calculate sin and cos values
|
||||
const double s_roll = std::sin(roll);
|
||||
const double c_roll = std::cos(roll);
|
||||
const double s_pitch = std::sin(pitch);
|
||||
const double c_pitch = std::cos(pitch);
|
||||
const double s_yaw = std::sin(yaw);
|
||||
const double c_yaw = std::cos(yaw);
|
||||
// Compute sin and cos values for the angles
|
||||
const double sy = sin(yaw);
|
||||
const double cy = cos(yaw);
|
||||
const double sp = sin(pitch);
|
||||
const double cp = cos(pitch);
|
||||
const double sr = sin(roll);
|
||||
const double cr = cos(roll);
|
||||
|
||||
// Compute the rotation matrix
|
||||
R(0,0) = cy*cp;
|
||||
R(0,1) = cy*sp*sr - sy*cr;
|
||||
R(0,2) = cy*sp*cr + sy*sr;
|
||||
R(1,0) = sy*cp;
|
||||
R(1,1) = sy*sp*sr + cy*cr;
|
||||
R(1,2) = sy*sp*cr - cy*sr;
|
||||
R(2,0) = -sp;
|
||||
R(2,1) = cp*sr;
|
||||
R(2,2) = cp*cr;
|
||||
|
||||
// Align the axes so that -Z points forward, Y points up, and X points to the right
|
||||
Eigen::Matrix3d R_Cam_Alignment; R_Cam_Alignment << 0., 0., -1.,
|
||||
-1., 0., 0.,
|
||||
0., 1., 0;
|
||||
R = R*R_Cam_Alignment;
|
||||
|
||||
// Build rotation matrix
|
||||
R << c_pitch * c_yaw, -c_pitch * s_yaw, s_pitch,
|
||||
s_roll * s_pitch * c_yaw + c_roll * s_yaw, -s_roll * s_pitch * s_yaw + c_roll * c_yaw, -s_roll * c_pitch,
|
||||
-c_roll * s_pitch * c_yaw + s_roll * s_yaw, c_roll * s_pitch * s_yaw + s_roll * c_yaw, c_roll * c_pitch;
|
||||
|
||||
R_T = R.transpose();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Eigen::Vector3d Camera::GetEulerAngles() const
|
||||
{
|
||||
// Align the axes so that -Z points forward, Y points up, and X points to the right
|
||||
Eigen::Matrix3d R_Cam_Alignment; R_Cam_Alignment << 0., 0., -1.,
|
||||
-1., 0., 0.,
|
||||
0., 1., 0;
|
||||
Eigen::Matrix3d _R = R*R_Cam_Alignment.transpose();
|
||||
|
||||
double sy = sqrt(_R(0,0)*_R(0,0) + _R(1,0)*_R(1,0));
|
||||
|
||||
double yaw, pitch, roll;
|
||||
if (sy > 1e-6) {
|
||||
yaw = atan2(_R(1,0), _R(0,0));
|
||||
pitch = atan2(-_R(2,0), sy);
|
||||
roll = atan2(_R(2,1), _R(2,2));
|
||||
}
|
||||
else {
|
||||
yaw = atan2(-_R(0,1), _R(1,1));
|
||||
pitch = atan2(-_R(2,0), sy);
|
||||
roll = 0.0;
|
||||
}
|
||||
|
||||
return Eigen::Vector3d(yaw*RAD2DEG, pitch*RAD2DEG, roll*RAD2DEG);
|
||||
}
|
||||
|
||||
Eigen::Vector3d Camera::ComputeRayDirInCameraFrame(Eigen::Vector2d const& p_norm) const {
|
||||
return Eigen::Vector3d(p_norm(0)*tanFOV2, p_norm(1)*tanFOV2, -1.0).normalized();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,6 +222,16 @@ Image Image::Colorized(unsigned char const* colormap) const {
|
|||
return colorized;
|
||||
}
|
||||
|
||||
Image Image::Resized(int new_width, int new_height, InterpMethod const& interp_method) const {
|
||||
Image resized(new_width, new_height, depth);
|
||||
double resize_factor = (double)new_width / (double)width;
|
||||
#pragma omp parallel for
|
||||
for(int i = 0 ; i < resized.GetHeight() ; i++)
|
||||
for(int j = 0 ; j < resized.GetWidth() ; j++)
|
||||
resized.SetPixel(i, j, GetPixelInterp(Eigen::Vector2d(i / resize_factor, j / resize_factor), interp_method));
|
||||
return resized;
|
||||
}
|
||||
|
||||
std::tuple<unsigned char, unsigned char> Image::ComputeMinMax() const {
|
||||
unsigned char min_val = 255, max_val = 0;
|
||||
#pragma omp parallel for reduction(min:min_val) reduction(max:max_val)
|
||||
|
|
@ -278,4 +288,4 @@ std::vector<uint64_t> Image::CumulativeHistogram(std::vector<uint64_t> const& hi
|
|||
for(unsigned int i = 1 ; i < histogram.size() ; i++)
|
||||
cumul_hist[i] = cumul_hist[i - 1] + histogram[i];
|
||||
return cumul_hist;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include <parser.hpp>
|
||||
#include <csv_parser.hpp>
|
||||
#include <filesystem>
|
||||
#include <locale>
|
||||
#include <logger.hpp>
|
||||
#include <progress_timer.hpp>
|
||||
#include <omp.h>
|
||||
|
|
@ -121,13 +120,12 @@ void configure_parser(cmd_line_parser::parser & parser) {
|
|||
parser.add("output_folder", "Output folder containing the projected images.", "-o", false);
|
||||
parser.add("size", "Size of generated images, in pixels. By default, 1000x1000 px.", "-s", false);
|
||||
parser.add("interpolation", "Interpolation mode when projecting the equirectangular (360 degree) image : 'nearest' (fast but blocky), 'bilinear' (slow but better). By default, 'bilinear'.", "--interp", false);
|
||||
parser.add("output_format", "Output format among the following : jpg, png, bmp, tga. By default, jpg.", "-o", false);
|
||||
parser.add("output_format", "Output format among the following : jpg, png, bmp, tga. By default, jpg.", "-f", false);
|
||||
parser.add("coverage", "Generate an colorized image depicting the coverage of the cameras over the whole sphere. The image produced is in equirectangular coordinates.", "--cov", false, true);
|
||||
parser.add("normalize", "If set, the images are histogram-normalized before being converted. This equalizes the utilization of all intensity values available. It might help the photogrammetry process to normalize the images.", "-n", false, true);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// std::locale::global(std::locale("en_US.utf8"));// DEBUG
|
||||
std::cout.precision(16);
|
||||
|
||||
// Default configuration
|
||||
|
|
@ -149,6 +147,12 @@ int main(int argc, char** argv) {
|
|||
// Print the configuration
|
||||
print_program_configuration(program_config);
|
||||
|
||||
// Create the output folder if it does not exist
|
||||
if(!fs::exists(program_config.output_folder)) {
|
||||
Logger::log("Creating output folder \"" + program_config.output_folder + "\"...");
|
||||
fs::create_directory(program_config.output_folder);
|
||||
}
|
||||
|
||||
// Load the cameras
|
||||
std::vector<Camera> cameras;
|
||||
{
|
||||
|
|
@ -161,11 +165,10 @@ int main(int argc, char** argv) {
|
|||
Logger::error("No cameras have been found, aborting now.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
for(unsigned int i = 0; i < cameras.size(); ++i) {
|
||||
std::cout << "Camera " << i << " :\nR =\n" << cameras[i].GetR() << "\nFOV = " << cameras[i].GetFOV() << std::endl;
|
||||
for(unsigned int i = 0; i < cameras.size(); ++i) {
|
||||
Eigen::Vector3d euler_angles = cameras[i].GetEulerAngles();
|
||||
Logger::log("Camera " + std::to_string(i) + " : Euler angles (yaw, pitch, roll) = " + std::to_string(euler_angles[0]) + " " + std::to_string(euler_angles[1]) + " " + std::to_string(euler_angles[2]) + " FOV = " + std::to_string(cameras[i].GetFOV()*RAD2DEG));
|
||||
}
|
||||
}
|
||||
|
||||
// Build the slicer
|
||||
|
|
@ -183,8 +186,7 @@ int main(int argc, char** argv) {
|
|||
auto [min_cov, max_cov, avg_cov] = coverage_image.ComputeMinMaxAvg();
|
||||
Logger::log("Coverage statistics (per pixel) :\tmin = " + std::to_string(int(min_cov)) + "\tmax = " + std::to_string(int(max_cov)) + "\tavg = " + std::to_string(avg_cov));
|
||||
Logger::log("Exporting coverage image...");
|
||||
coverage_image.Normalized().Colorized(Image::Colormap::PARULA);
|
||||
coverage_image.Save(program_config.output_folder + "/coverage." + program_config.output_format);
|
||||
coverage_image.Normalized().Colorized(Image::Colormap::PARULA).Save(program_config.output_folder + "/coverage." + program_config.output_format);
|
||||
}
|
||||
|
||||
// Generate the perspective images
|
||||
|
|
@ -215,7 +217,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
Logger::log(progress_timer.increment());
|
||||
}
|
||||
Logger::log(std::to_string(image_files.size()) + " perspective images generated.");
|
||||
Logger::log(std::to_string(image_files.size()*slicer.cameras.size()) + " perspective images generated from " + std::to_string(image_files.size()) + " input images.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue