commit 5cd3f32da1fa95c40e87922e9c47cde14e49c271
parent 47eabcc66a3a515515e474ccd60c624bb2e9eb88
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 28 Jul 2021 14:13:17 +0200
Add the thin-lens camera model
Add the lens-radius, focal-dst, and focal-length options to the '-C'
option that defines a camera. By default the camera is a pinhole until
the 'lens-radius' is set to a value greater than 0. With a thin-lens
camera, the 'focal-dst' control the distance to focus and 'focal-length'
is another way to define its field of view.
Diffstat:
5 files changed, 149 insertions(+), 7 deletions(-)
diff --git a/cmake/core/CMakeLists.txt b/cmake/core/CMakeLists.txt
@@ -26,6 +26,7 @@ find_package(MruMtl 0.0 REQUIRED)
find_package(RCMake 0.3 REQUIRED)
find_package(RSys 0.11 REQUIRED)
find_package(Star3D 0.8 REQUIRED)
+find_package(StarCamera 0.0 REQUIRED)
find_package(StarSF 0.6 REQUIRED)
find_package(StarSP 0.10 REQUIRED)
find_package(OpenMP 1.2 REQUIRED)
@@ -42,6 +43,7 @@ include_directories(
${MruMtl_INCLUDE_DIR}
${RSys_INCLUDE_DIR}
${Star3D_INCLUDE_DIR}
+ ${StarCamera_INCLUDE_DIR}
${StarSF_INCLUDE_DIR}
${StarSP_INCLUDE_DIR}
${StarVX_INCLUDE_DIR}
@@ -57,6 +59,8 @@ set(HTRDR_ARGS_DEFAULT_CAMERA_POS "0,0,0" CACHE INTERNAL "")
set(HTRDR_ARGS_DEFAULT_CAMERA_TGT "0,1,0" CACHE INTERNAL "")
set(HTRDR_ARGS_DEFAULT_CAMERA_UP "0,0,1" CACHE INTERNAL "")
set(HTRDR_ARGS_DEFAULT_CAMERA_FOV "70" CACHE INTERNAL "")
+set(HTRDR_ARGS_DEFAULT_CAMERA_LENS_RADIUS "0" CACHE INTERNAL "")
+set(HTRDR_ARGS_DEFAULT_CAMERA_FOCAL_DST "1" CACHE INTERNAL "")
set(HTRDR_ARGS_DEFAULT_RECTANGLE_POS "0,0,0" CACHE INTERNAL "")
set(HTRDR_ARGS_DEFAULT_RECTANGLE_TGT "0,0,1" CACHE INTERNAL "")
set(HTRDR_ARGS_DEFAULT_RECTANGLE_UP "0,1,0" CACHE INTERNAL "")
@@ -116,7 +120,7 @@ add_library(htrdr-core SHARED
${HTRDR_CORE_FILES_SRC}
${HTRDR_CORE_FILES_INC}
${HTRDR_CORE_FILES_INC2})
-target_link_libraries(htrdr-core AW MruMtl RSys Star3D StarSF StarSP)
+target_link_libraries(htrdr-core AW MruMtl RSys Star3D StarCamera StarSF StarSP)
if(CMAKE_COMPILER_IS_GNUCC)
target_link_libraries(htrdr-core m)
diff --git a/src/atmosphere/htrdr_atmosphere.c b/src/atmosphere/htrdr_atmosphere.c
@@ -179,6 +179,8 @@ setup_sensor
d3_set(cam_args.up, args->sensor.camera.up);
cam_args.aspect_ratio = proj_ratio;
cam_args.field_of_view = MDEG2RAD(args->sensor.camera.fov_y);
+ cam_args.lens_radius = args->sensor.camera.lens_radius;
+ cam_args.focal_distance = args->sensor.camera.focal_dst;
res = scam_create_perspective
(htrdr_get_logger(cmd->htrdr),
htrdr_get_allocator(cmd->htrdr),
diff --git a/src/combustion/htrdr_combustion.c b/src/combustion/htrdr_combustion.c
@@ -176,6 +176,8 @@ setup_camera
(double)args->image.definition[0]
/ (double)args->image.definition[1];
cam_args.field_of_view = MDEG2RAD(args->camera.fov_y);
+ cam_args.lens_radius = args->camera.lens_radius;
+ cam_args.focal_distance = args->camera.focal_dst;
return scam_create_perspective
(htrdr_get_logger(cmd->htrdr),
diff --git a/src/core/htrdr_args.c b/src/core/htrdr_args.c
@@ -21,12 +21,17 @@
#include "core/htrdr_args.h"
#include "core/htrdr_version.h"
+#include <star/scam.h>
+
#include <rsys/cstr.h>
#include <rsys/double3.h>
#include <rsys/str.h>
#include <string.h>
+#define FOV_EXCLUSIVE_MIN 0.0 /* In degrees */
+#define FOV_EXCLUSIVE_MAX 180.0 /* In degrees */
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -66,8 +71,9 @@ parse_fov(const char* str, double* out_fov)
fprintf(stderr, "Invalid field of view `%s'.\n", str);
return RES_BAD_ARG;
}
- if(fov <= 0 || fov >= 180) {
- fprintf(stderr, "The field of view %g is not in [30, 120].\n", fov);
+ if(fov <= FOV_EXCLUSIVE_MIN || fov >= FOV_EXCLUSIVE_MAX) {
+ fprintf(stderr, "The field of view %g is not in ]%g, %g[.\n",
+ fov, FOV_EXCLUSIVE_MIN, FOV_EXCLUSIVE_MAX);
return RES_BAD_ARG;
}
*out_fov = fov;
@@ -75,6 +81,66 @@ parse_fov(const char* str, double* out_fov)
}
static res_T
+parse_focal_length(const char* str, double* out_length)
+{
+ double length;
+ res_T res = RES_OK;
+ ASSERT(str && out_length);
+
+ res = cstr_to_double(str, &length);
+ if(res != RES_OK) {
+ fprintf(stderr, "Invalid focal length `%s'.\n", str);
+ return RES_BAD_ARG;
+ }
+ if(length <= 0) {
+ fprintf(stderr, "Invalid negative or null focal length %g.\n", length);
+ return RES_BAD_ARG;
+ }
+ *out_length = length;
+ return RES_OK;
+}
+
+static res_T
+parse_lens_radius(const char* str, double* out_radius)
+{
+ double radius;
+ res_T res = RES_OK;
+ ASSERT(str && out_radius);
+
+ res = cstr_to_double(str, &radius);
+ if(res != RES_OK) {
+ fprintf(stderr, "Invalid lens radius `%s'.\n", str);
+ return RES_BAD_ARG;
+ }
+ if(radius < 0) {
+ fprintf(stderr, "Invalid negative lens radius %g.\n", radius);
+ return RES_BAD_ARG;
+ }
+ *out_radius = radius;
+ return RES_OK;
+}
+
+static res_T
+parse_focal_dst(const char* str, double* out_dst)
+{
+ double dst;
+ res_T res = RES_OK;
+ ASSERT(str && out_dst);
+
+ res = cstr_to_double(str, &dst);
+ if(res != RES_OK) {
+ fprintf(stderr, "Invalid focal distance `%s'.\n", str);
+ return RES_BAD_ARG;
+ }
+ if(dst <= 0) {
+ fprintf(stderr, "Invalid negative or null focal disrtance %g.\n", dst);
+ return RES_BAD_ARG;
+ }
+ *out_dst = dst;
+ return RES_OK;
+}
+
+static res_T
parse_image_parameter(const char* str, void* args)
{
char buf[128];
@@ -178,6 +244,14 @@ parse_camera_parameter(const char* str, void* args)
PARSE("up vector", parse_doubleX(val, cam->up, 3));
} else if(!strcmp(key, "fov")) {
PARSE("field-of-view", parse_fov(val, &cam->fov_y));
+ cam->focal_length = -1; /* Overwrite the focal_length */
+ } else if(!strcmp(key, "focal-length")) {
+ PARSE("focal-length", parse_focal_length(val, &cam->focal_length));
+ cam->fov_y = -1; /* Overwrite the fov */
+ } else if(!strcmp(key, "lens-radius")) {
+ PARSE("lens radius", parse_lens_radius(val, &cam->lens_radius));
+ } else if(!strcmp(key, "focal-dst")) {
+ PARSE("focal distance", parse_focal_dst(val, &cam->focal_dst));
} else {
fprintf(stderr, "Invalid camera parameter `%s'.\n", key);
res = RES_BAD_ARG;
@@ -394,9 +468,63 @@ error:
res_T
htrdr_args_camera_parse(struct htrdr_args_camera* cam, const char* str)
{
- if(!cam || !str) return RES_BAD_ARG;
- return cstr_parse_list(str, ':', parse_camera_parameter, cam);
-}
+ res_T res = RES_OK;
+
+ if(!cam || !str) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_parse_list(str, ':', parse_camera_parameter, cam);
+ if(res != RES_OK) goto error;
+
+ if(cam->focal_length < 0) {
+ ASSERT(cam->fov_y > 0);
+ res = scam_field_of_view_to_focal_length
+ (cam->lens_radius, MDEG2RAD(cam->fov_y), &cam->focal_length);
+ if(res != RES_OK) {
+ fprintf(stderr,
+ "Cannot compute the focal length from the lens radius %g "
+ "and the field of view %g -- %s.\n",
+ cam->lens_radius,
+ cam->fov_y,
+ res_to_cstr(res));
+ goto error;
+ }
+
+ } else if(cam->fov_y < 0) {
+ ASSERT(cam->focal_length > 0);
+ res = scam_focal_length_to_field_of_view
+ (cam->lens_radius, cam->focal_length, &cam->fov_y);
+ if(res != RES_OK) {
+ fprintf(stderr,
+ "Cannot compute the field of view from the lens radius %g "
+ "and the focal length %g -- %s.\n",
+ cam->lens_radius,
+ cam->focal_length,
+ res_to_cstr(res));
+ goto error;
+ }
+ cam->fov_y = MRAD2DEG(cam->fov_y);
+ if(cam->fov_y <= FOV_EXCLUSIVE_MIN || cam->fov_y >= FOV_EXCLUSIVE_MAX) {
+ fprintf(stderr,
+ "Invalid focal length %g regarding the lens radius %g. "
+ "The corresponding field of view %g is not in ]%g, %g[ degrees.\n",
+ cam->focal_length,
+ cam->lens_radius,
+ cam->fov_y,
+ FOV_EXCLUSIVE_MIN,
+ FOV_EXCLUSIVE_MAX);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
res_T
htrdr_args_rectangle_parse(struct htrdr_args_rectangle* rect, const char* str)
diff --git a/src/core/htrdr_args.h.in b/src/core/htrdr_args.h.in
@@ -25,16 +25,22 @@
/* Arguments of a pinhole camera sensor */
struct htrdr_args_camera {
- double position[3]; /* Focal point */
+ double position[3]; /* Lens position */
double target[3]; /* Targeted position */
double up[3]; /* Up vector of the camera */
double fov_y; /* Vertical field of view of the camera, in degrees */
+ double lens_radius; /* Radius of the lens. 0 means for pinhole */
+ double focal_dst; /* Distance to focus on */
+ double focal_length; /* Computed from fov_y and lens_radius. <0 => not used */
};
#define HTRDR_ARGS_CAMERA_DEFAULT__ { \
{@HTRDR_ARGS_DEFAULT_CAMERA_POS@}, /* position */ \
{@HTRDR_ARGS_DEFAULT_CAMERA_TGT@}, /* target */ \
{@HTRDR_ARGS_DEFAULT_CAMERA_UP@}, /* Camera up */ \
@HTRDR_ARGS_DEFAULT_CAMERA_FOV@, /* Vertical field of view */ \
+ @HTRDR_ARGS_DEFAULT_CAMERA_LENS_RADIUS@, /* Radius of the lens */ \
+ @HTRDR_ARGS_DEFAULT_CAMERA_FOCAL_DST@, /* Distance to focus on */ \
+ -1 /* Focal length. <0 <=> not used */ \
}
static const struct htrdr_args_camera HTRDR_ARGS_CAMERA_DEFAULT =
HTRDR_ARGS_CAMERA_DEFAULT__;