Initial commit
First (sort-of) working version of a pinhole camera model. Improvement idea: - Stretch result image to the whole size
This commit is contained in:
commit
ffbe68606b
16
.clang-format
Normal file
16
.clang-format
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
|
||||
BinPackArguments: 'false'
|
||||
BinPackParameters: 'false'
|
||||
BreakStringLiterals: 'false'
|
||||
ColumnLimit: '120'
|
||||
IndentCaseLabels: 'false'
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: '4'
|
||||
BreakBeforeBraces: 'Custom'
|
||||
BraceWrapping:
|
||||
AfterEnum: 'true'
|
||||
AfterStruct: 'true'
|
||||
AfterFunction: 'true'
|
||||
SortIncludes: 'false'
|
||||
...
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
builddir
|
||||
.cache
|
7987
3p/stb_image.h
Normal file
7987
3p/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
1724
3p/stb_image_write.h
Normal file
1724
3p/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load Diff
123
bin/defocus.c
Normal file
123
bin/defocus.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <defocus/defocus.h>
|
||||
|
||||
int pinhole_fn(int argc, char **argv);
|
||||
|
||||
static const char *_model_names[] = {"pinhole"};
|
||||
typedef int (*model_fn)(int argc, char **argv);
|
||||
|
||||
static model_fn _model_fns[] = {
|
||||
pinhole_fn,
|
||||
};
|
||||
|
||||
void usage(const char *pname)
|
||||
{
|
||||
printf("Usage: %s <model-name> [model parameters]\n", pname);
|
||||
printf("Available models:\n");
|
||||
for (int i = 0; i < DF_ARRAY_COUNT(_model_names); ++i) {
|
||||
printf(" %s\n", _model_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Missing model name!\n");
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
model_fn fn = NULL;
|
||||
const char *model = argv[1];
|
||||
for (int i = 0; i < DF_ARRAY_COUNT(_model_names); ++i) {
|
||||
if (strcmp(model, _model_names[i]) == 0) {
|
||||
fn = _model_fns[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fn) {
|
||||
fprintf(stderr, "Invalid model name!\n");
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return fn(argc - 2, &argv[2]);
|
||||
}
|
||||
|
||||
int pinhole_fn(int argc, char **argv)
|
||||
{
|
||||
const char *in_path = NULL;
|
||||
const char *out_path = "out.png";
|
||||
const char *focal_str = NULL;
|
||||
const char *in_z_str = NULL;
|
||||
const char *out_z_str = NULL;
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if ((strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--input") == 0) && i < argc - 1) {
|
||||
++i;
|
||||
in_path = argv[i];
|
||||
} else if ((strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) && i < argc - 1) {
|
||||
++i;
|
||||
out_path = argv[i];
|
||||
} else if ((strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--focal-length") == 0) && i < argc - 1) {
|
||||
++i;
|
||||
focal_str = argv[i];
|
||||
} else if ((strcmp(argv[i], "-iz") == 0 || strcmp(argv[i], "--input-z") == 0) && i < argc - 1) {
|
||||
++i;
|
||||
in_z_str = argv[i];
|
||||
} else if ((strcmp(argv[i], "-oz") == 0 || strcmp(argv[i], "--output-z") == 0) && i < argc - 1) {
|
||||
++i;
|
||||
out_z_str = argv[i];
|
||||
} else {
|
||||
in_path = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_path || !focal_str || !in_z_str || !out_z_str) {
|
||||
fprintf(stderr, "Missing model parameters!\n");
|
||||
printf("Pinhole model parameters:\n");
|
||||
printf(" -i | --input <path>\t\tPath to the input image.\n");
|
||||
printf(" -o | --output <path>\t\tPath to the output image (Default: out.png).\n");
|
||||
printf(" -iz | --input-z <number>\t\tDistance to the input image plane.\n");
|
||||
printf(" -oz | --output-z <number>\t\tDistance to the output image plane.\n");
|
||||
printf(" -f | --focal-length <number>\t\tThe focal length of the camera lens.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
float focal, in_z, out_z;
|
||||
focal = atof(focal_str);
|
||||
in_z = atof(in_z_str);
|
||||
out_z = atof(out_z_str);
|
||||
|
||||
df_image *in_image, *out_image;
|
||||
|
||||
int w, h;
|
||||
df_result res = df_load_image(in_path, &w, &h, &in_image);
|
||||
if (res != df_result_success) {
|
||||
fprintf(stderr, "Failed to load %s! (%d)\n", in_path, (int)res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = df_create_image(w, h, &out_image);
|
||||
if (res != df_result_success) {
|
||||
fprintf(stderr, "Failed to create output image (%d)\n", (int)res);
|
||||
df_release_image(in_image);
|
||||
return 1;
|
||||
}
|
||||
|
||||
df_pinhole(in_image, focal, in_z, out_z, out_image);
|
||||
|
||||
int error_code = 0;
|
||||
res = df_write_image(out_image, out_path);
|
||||
if (res != df_result_success) {
|
||||
fprintf(stderr, "Failed to write to output image %s (%d)\n", out_path, (int)res);
|
||||
error_code = 1;
|
||||
}
|
||||
|
||||
df_release_image(in_image);
|
||||
df_release_image(out_image);
|
||||
|
||||
return error_code;
|
||||
}
|
203
include/defocus/base.h
Normal file
203
include/defocus/base.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
#ifndef DEFOCUS_BASE_H
|
||||
#define DEFOCUS_BASE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
/** @file base.h
|
||||
* @brief basic utilities
|
||||
*/
|
||||
|
||||
/** @brief Result codes used throughout the codebase */
|
||||
typedef enum
|
||||
{
|
||||
/** @brief operation successfull */
|
||||
df_result_success = 0,
|
||||
|
||||
/** @brief an opengl error occured */
|
||||
df_result_gl_error = 1,
|
||||
|
||||
/** @brief memory allocation failed */
|
||||
df_result_out_of_memory = 2,
|
||||
|
||||
/** @brief file i/o error */
|
||||
df_result_io_error = 3,
|
||||
} df_result;
|
||||
|
||||
/** @brief Used to silence warnings about unused variables */
|
||||
#define DF_UNUSED(x) ((void)sizeof((x)))
|
||||
|
||||
/** @brief Evaluates to the number of elements in a static array. */
|
||||
#define DF_ARRAY_COUNT(a) (sizeof((a)) / sizeof((a)[0]))
|
||||
|
||||
/** @brief Zero a memory range */
|
||||
#define DF_ZERO_MEMORY(ptr, n) memset((ptr), 0, (n))
|
||||
|
||||
/** @brief Zero a struct */
|
||||
#define DF_ZERO_STRUCT(ptr) DF_ZERO_MEMORY(ptr, sizeof(*(ptr)))
|
||||
|
||||
/** @brief Zero an array */
|
||||
#define DF_ZERO_ARRAY(a, n) DF_ZERO_MEMORY(a, sizeof((a)[0]) * (n))
|
||||
|
||||
/* Simple logging function */
|
||||
|
||||
#ifndef DF_ENABLE_LOGGING
|
||||
#define DF_ENABLE_LOGGING 1
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
df_log_level_verbose = 0,
|
||||
df_log_level_info = 1,
|
||||
df_log_level_warn = 2,
|
||||
df_log_level_error = 3,
|
||||
};
|
||||
|
||||
#if DF_ENABLE_LOGGING
|
||||
|
||||
/** @brief The actual log implementation.
|
||||
*
|
||||
* There should be no need to call this directly.
|
||||
*
|
||||
* Instead use one of:
|
||||
* - df_log_verbose()
|
||||
* - df_log_info()
|
||||
* - df_log_warn()
|
||||
* - df_log_error()
|
||||
|
||||
* @param level the log level. Used to filter the messages.
|
||||
* @param file file name of the log location
|
||||
* @param line line number of the log location
|
||||
* @param fmt format string of the message.
|
||||
*/
|
||||
void df_log_impl(int level, const char *file, int line, const char *fmt, ...);
|
||||
|
||||
#define df_log_verbose(...) df_log_impl(df_log_level_verbose, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define df_log_info(...) df_log_impl(df_log_level_info, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define df_log_warn(...) df_log_impl(df_log_level_warn, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define df_log_error(...) df_log_impl(df_log_level_error, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
#else /* DF_ENABLE_LOGGING = 0 */
|
||||
|
||||
#define df_log_verbose(fmt, ...)
|
||||
#define df_log_info(fmt, ...)
|
||||
#define df_log_warn(fmt, ...)
|
||||
#define df_log_error(fmt, ...)
|
||||
|
||||
#endif
|
||||
|
||||
/* Basic types */
|
||||
|
||||
/** @brief RGBA color */
|
||||
typedef union {
|
||||
struct
|
||||
{
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
uint8_t e[4];
|
||||
} df_color;
|
||||
|
||||
/** @brief Linear interpolation between two colors.
|
||||
*
|
||||
* @param a first color
|
||||
* @param b second color
|
||||
* @param t interpolation factor
|
||||
* @return a + (b - a) * t
|
||||
*/
|
||||
df_color df_lerp_color(df_color a, df_color b, double t);
|
||||
|
||||
/** @brief 2d vector */
|
||||
typedef union {
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
struct
|
||||
{
|
||||
float u;
|
||||
float v;
|
||||
};
|
||||
float e[2];
|
||||
} df_v2;
|
||||
|
||||
/** @brief 3d vector */
|
||||
typedef union {
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
float e[3];
|
||||
} df_v3;
|
||||
|
||||
/** @brief Add two 3d vectors */
|
||||
df_v3 df_add_v3(df_v3 a, df_v3 b);
|
||||
|
||||
/** @brief Subtract two 3d vectors */
|
||||
df_v3 df_sub_v3(df_v3 a, df_v3 b);
|
||||
|
||||
/** @brief Calculate the dot product of 3d vectors a and b.
|
||||
*/
|
||||
float df_dot_v3(df_v3 a, df_v3 b);
|
||||
|
||||
/** @brief Multiply a 3d vector with a scalar.
|
||||
*/
|
||||
df_v3 df_mul_v3(float t, df_v3 v);
|
||||
|
||||
/** @brief Returns the normalized version of a 3d vector v
|
||||
*/
|
||||
df_v3 df_normalize_v3(df_v3 v);
|
||||
|
||||
/** @brief A plane in 3d space.
|
||||
*
|
||||
* Expressed as the set of all points p for which
|
||||
* dot((p - base), normal) = 0
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
df_v3 base;
|
||||
df_v3 normal;
|
||||
} df_plane;
|
||||
|
||||
/** @brief A line in 3d space.
|
||||
*
|
||||
* Expressed as the vector equation p = base + t * direction.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
df_v3 base;
|
||||
df_v3 direction;
|
||||
} df_line;
|
||||
|
||||
/** @brief The three possible result types of a line-plane intersection test.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/** The line and plane intersect in one point */
|
||||
df_line_plane_intersection_vector,
|
||||
|
||||
/** The line is contained in the plane */
|
||||
df_line_plane_intersection_contained,
|
||||
|
||||
/** The line and plane don't intersect (-> they are parallel) */
|
||||
df_line_plane_intersection_none,
|
||||
} df_line_plane_intersection_type;
|
||||
|
||||
/** @brief Result of a line-plane intersection test.
|
||||
* The contained vector is only valid if @c type = @c df_line_plane_intersection_vector.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
df_line_plane_intersection_type type;
|
||||
df_v3 vec;
|
||||
} df_line_plane_intersection;
|
||||
|
||||
/** @brief Calculate the intersection between a line and a plane in 3d space */
|
||||
df_line_plane_intersection df_calc_line_plane_intersection(df_line line, df_plane plane);
|
||||
|
||||
#endif
|
11
include/defocus/defocus.h
Normal file
11
include/defocus/defocus.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef DEFOCUS_DEFOCUS_H
|
||||
#define DEFOCUS_DEFOCUS_H
|
||||
|
||||
/** @file defocus.h
|
||||
* @brief meta header
|
||||
*/
|
||||
#include "base.h"
|
||||
#include "image.h"
|
||||
#include "pinhole.h"
|
||||
|
||||
#endif
|
62
include/defocus/image.h
Normal file
62
include/defocus/image.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#ifndef DEFOCUS_IMAGE_H
|
||||
#define DEFOCUS_IMAGE_H
|
||||
|
||||
/** @file image.h
|
||||
* @brief image type and functions
|
||||
*/
|
||||
|
||||
#include "base.h"
|
||||
|
||||
/** @brief Opaque rgba8 image object */
|
||||
typedef struct df_image df_image;
|
||||
|
||||
/** @brief create an image
|
||||
*
|
||||
* The contents of the image will be undefined.
|
||||
* @param w the image width
|
||||
* @param h the image height
|
||||
* @param out_image receives the image object
|
||||
* @return error code
|
||||
*/
|
||||
df_result df_create_image(int w, int h, df_image **out_image);
|
||||
|
||||
/** @brief load an image file
|
||||
*
|
||||
* The image data will be converted to rgba8
|
||||
*
|
||||
* @param w the image width
|
||||
* @param h the image height
|
||||
* @param out_image receives the image object
|
||||
* @return error code
|
||||
*/
|
||||
df_result df_load_image(const char *path, int *out_w, int *out_h, df_image **out_image);
|
||||
|
||||
/** @brief Write an image to a PNG file
|
||||
* @param img the image
|
||||
* @param path the path
|
||||
*/
|
||||
df_result df_write_image(df_image *img, const char *path);
|
||||
|
||||
/** @brief Free an image.
|
||||
*
|
||||
* Any pointer to the image will be invalid after this.
|
||||
* @param img the image
|
||||
*/
|
||||
void df_release_image(df_image *img);
|
||||
|
||||
/** @brief Returns the dimensions of the image */
|
||||
void df_get_image_size(const df_image *image, int *w, int *h);
|
||||
|
||||
/** @brief Returns the color value at pixel coordinates x, y
|
||||
*
|
||||
* Returns black for coordinates outside the image.
|
||||
*/
|
||||
df_color df_get_image_pixel(const df_image *image, int x, int y);
|
||||
|
||||
/** @brief Set the color value at pixel coordinates x, y.
|
||||
*
|
||||
* Does nothing for coordinates outside the image.
|
||||
*/
|
||||
void df_set_image_pixel(df_image *image, int x, int y, df_color c);
|
||||
|
||||
#endif
|
12
include/defocus/pinhole.h
Normal file
12
include/defocus/pinhole.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef DF_PINHOLE_H
|
||||
#define DF_PINHOLE_H
|
||||
|
||||
/** @file pinhole.h
|
||||
* @brief Defocus based on pinhole camera model.
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
|
||||
void df_pinhole(const df_image *in_image, float focal_length, float orig_z, float new_z, df_image *out_image);
|
||||
|
||||
#endif
|
14
lib/color.c
Normal file
14
lib/color.c
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <defocus/base.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
df_color df_lerp_color(df_color a, df_color b, double t)
|
||||
{
|
||||
df_color r;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
double af = (double)a.e[i];
|
||||
double bf = (double)b.e[i];
|
||||
r.e[i] = (uint8_t)floor(af + (bf - af) * t);
|
||||
}
|
||||
return r;
|
||||
}
|
110
lib/image.c
Normal file
110
lib/image.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
#include <defocus/image.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
||||
struct df_image
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
uint8_t *pixels;
|
||||
};
|
||||
|
||||
df_result df_create_image(int w, int h, df_image **out_image)
|
||||
{
|
||||
df_image *img = malloc(sizeof(df_image));
|
||||
if (!img)
|
||||
return df_result_out_of_memory;
|
||||
DF_ZERO_STRUCT(img);
|
||||
|
||||
img->width = w;
|
||||
img->height = h;
|
||||
img->pixels = malloc(4 * sizeof(uint8_t) * w * h);
|
||||
if (!img->pixels) {
|
||||
free(img);
|
||||
return df_result_out_of_memory;
|
||||
}
|
||||
memset(img->pixels, 0, 4 * w * h);
|
||||
|
||||
*out_image = img;
|
||||
return df_result_success;
|
||||
}
|
||||
|
||||
df_result df_load_image(const char *path, int *out_w, int *out_h, df_image **out_image)
|
||||
{
|
||||
int w, h, c;
|
||||
stbi_uc *pixels = stbi_load(path, &w, &h, &c, 4);
|
||||
if (!pixels) {
|
||||
fprintf(stderr, "ERROR: failed to load %s: %s\n", path, stbi_failure_reason());
|
||||
return df_result_io_error;
|
||||
}
|
||||
|
||||
df_result res = df_result_success;
|
||||
df_image *img = malloc(sizeof(df_image));
|
||||
if (!img) {
|
||||
res = df_result_out_of_memory;
|
||||
goto err;
|
||||
}
|
||||
DF_ZERO_STRUCT(img);
|
||||
|
||||
img->width = w;
|
||||
img->height = h;
|
||||
img->pixels = (uint8_t *)pixels;
|
||||
|
||||
*out_image = img;
|
||||
*out_w = w;
|
||||
*out_h = h;
|
||||
|
||||
goto out;
|
||||
err:
|
||||
free(img);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
void df_release_image(df_image *img)
|
||||
{
|
||||
if (img) {
|
||||
free(img->pixels);
|
||||
free(img);
|
||||
}
|
||||
}
|
||||
|
||||
df_result df_write_image(df_image *image, const char *path)
|
||||
{
|
||||
df_result res = stbi_write_png(path, image->width, image->height, 4, image->pixels, image->width * 4)
|
||||
? df_result_success
|
||||
: df_result_io_error;
|
||||
return res;
|
||||
}
|
||||
|
||||
void df_get_image_size(const df_image *image, int *w, int *h)
|
||||
{
|
||||
if (w)
|
||||
*w = image->width;
|
||||
if (h)
|
||||
*h = image->height;
|
||||
}
|
||||
|
||||
df_color df_get_image_pixel(const df_image *image, int x, int y)
|
||||
{
|
||||
df_color c = {0, 0, 0, 255};
|
||||
if (x >= 0 && x < image->width && y >= 0 && y < image->height) {
|
||||
memcpy(&c.e[0], &image->pixels[4 * (y * image->width + x)], 4);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void df_set_image_pixel(df_image *image, int x, int y, df_color c)
|
||||
{
|
||||
if (x >= 0 && x < image->width && y >= 0 && y < image->height) {
|
||||
memcpy(&image->pixels[4 * (y * image->width + x)], &c.e[0], 4);
|
||||
}
|
||||
}
|
15
lib/log.c
Normal file
15
lib/log.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <defocus/base.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
static const char *log_level_names[] = {"VERBOSE", "INFO", "WARN", "ERROR"};
|
||||
|
||||
void df_log_impl(int level, const char *file, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "[%s] %s:%d: ", log_level_names[level], file, line);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
60
lib/math.c
Normal file
60
lib/math.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include <defocus/base.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
df_v3 df_add_v3(df_v3 a, df_v3 b)
|
||||
{
|
||||
df_v3 v = {a.x + b.x, a.y + b.y, a.z + b.z};
|
||||
return v;
|
||||
}
|
||||
|
||||
df_v3 df_sub_v3(df_v3 a, df_v3 b)
|
||||
{
|
||||
df_v3 v = {a.x - b.x, a.y - b.y, a.z - b.z};
|
||||
return v;
|
||||
}
|
||||
|
||||
float df_dot_v3(df_v3 a, df_v3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
|
||||
|
||||
df_v3 df_mul_v3(float t, df_v3 v)
|
||||
{
|
||||
df_v3 r = {t * v.x, t * v.y, t * v.z};
|
||||
return r;
|
||||
}
|
||||
|
||||
df_v3 df_normalize_v3(df_v3 v)
|
||||
{
|
||||
float len_square = df_dot_v3(v, v);
|
||||
float len = sqrtf(len_square);
|
||||
df_v3 n = {v.x / len, v.y / len, v.z / len};
|
||||
return n;
|
||||
}
|
||||
|
||||
df_line_plane_intersection df_calc_line_plane_intersection(df_line line, df_plane plane)
|
||||
{
|
||||
/* check case */
|
||||
float dot = df_dot_v3(line.direction, plane.normal);
|
||||
df_v3 base_diff = df_sub_v3(plane.base, line.base);
|
||||
float dot2 = df_dot_v3(base_diff, plane.normal);
|
||||
if (dot != 0) {
|
||||
float t = dot2 / dot;
|
||||
df_v3 point = df_add_v3(line.base, df_mul_v3(t, line.direction));
|
||||
df_line_plane_intersection intersection = {
|
||||
.type = df_line_plane_intersection_vector,
|
||||
.vec = point,
|
||||
};
|
||||
return intersection;
|
||||
} else {
|
||||
if (dot2 == 0) {
|
||||
df_line_plane_intersection intersection = {
|
||||
.type = df_line_plane_intersection_contained,
|
||||
};
|
||||
return intersection;
|
||||
} else {
|
||||
df_line_plane_intersection intersection = {
|
||||
.type = df_line_plane_intersection_none,
|
||||
};
|
||||
return intersection;
|
||||
}
|
||||
}
|
||||
}
|
76
lib/pinhole.c
Normal file
76
lib/pinhole.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include <defocus/pinhole.h>
|
||||
#include <defocus/base.h>
|
||||
#include <defocus/image.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
void df_pinhole(const df_image *in_image, float focal_length, float orig_z, float new_z, df_image *out_image)
|
||||
{
|
||||
/* orig_z is the z-coordinate of the original image plane (=> in_image is located there)
|
||||
* new_z is the z-coordinate of the output image plane (=> out_image is located there)
|
||||
*
|
||||
* We can map from image coordinates to world coordinates, because we know the z coordinate of
|
||||
* the input image plane and the focal length of the camera.
|
||||
*
|
||||
* Let x,y,z be the world coordinates and u, v the image coordintes.
|
||||
* The pinhole camera model gives us:
|
||||
* u = f/z * x; v = f/z * y
|
||||
* => x = u * z / f
|
||||
* => y = v * z / f
|
||||
*/
|
||||
|
||||
int w, h;
|
||||
df_get_image_size(in_image, &w, &h);
|
||||
|
||||
int out_w, out_h;
|
||||
df_get_image_size(out_image, &out_w, &out_h);
|
||||
|
||||
double in_z_over_f = orig_z / focal_length;
|
||||
double out_f_over_z = focal_length / new_z;
|
||||
|
||||
int prev_out_iy = -1;
|
||||
for (int iy = 0; iy < h; ++iy) {
|
||||
double v = (double)iy / (double)h;
|
||||
double y = in_z_over_f * v;
|
||||
double out_v = out_f_over_z * y;
|
||||
|
||||
int out_iy = (int)floor(out_v * (double)out_h);
|
||||
|
||||
int prev_out_ix = -1;
|
||||
for (int ix = 0; ix < w; ++ix) {
|
||||
double u = (double)ix / (double)w;
|
||||
double x = in_z_over_f * u;
|
||||
double out_u = out_f_over_z * x;
|
||||
|
||||
int out_ix = (int)floor(out_u * (double)out_w);
|
||||
|
||||
df_color px = df_get_image_pixel(in_image, ix, iy);
|
||||
df_set_image_pixel(out_image, out_ix, out_iy, px);
|
||||
|
||||
/* Go back and interpolate between this pixel and the previous one. */
|
||||
if ((out_ix - prev_out_ix) > 1) {
|
||||
df_color prev_px = df_get_image_pixel(out_image, prev_out_ix, out_iy);
|
||||
for (int d = prev_out_ix + 1; d < out_ix; ++d) {
|
||||
double t = (double)(d - prev_out_ix) / (double)(out_ix - prev_out_ix);
|
||||
df_color color = df_lerp_color(prev_px, px, t);
|
||||
df_set_image_pixel(out_image, d, out_iy, color);
|
||||
}
|
||||
}
|
||||
prev_out_ix = out_ix;
|
||||
}
|
||||
|
||||
/* Go back and interpolate between this row and the previous one */
|
||||
if ((out_iy - prev_out_iy) > 1) {
|
||||
for (int y = prev_out_iy + 1; y < out_iy; ++y) {
|
||||
double t = (double)(y - prev_out_iy) / (double)(out_iy - prev_out_iy);
|
||||
for (int x = 0; x < out_w; ++x) {
|
||||
df_color a = df_get_image_pixel(out_image, x, prev_out_iy);
|
||||
df_color b = df_get_image_pixel(out_image, x, out_iy);
|
||||
df_color color = df_lerp_color(a, b, t);
|
||||
df_set_image_pixel(out_image, x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_out_iy = out_iy;
|
||||
}
|
||||
}
|
18
meson.build
Normal file
18
meson.build
Normal file
|
@ -0,0 +1,18 @@
|
|||
project('defocus-modules', 'c', default_options: ['c_std=c11'])
|
||||
|
||||
incdir = include_directories('include', '3p')
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
m_dep = cc.find_library('m', required: false)
|
||||
|
||||
lib = library('df',
|
||||
'lib/log.c',
|
||||
'lib/math.c',
|
||||
'lib/pinhole.c',
|
||||
'lib/image.c',
|
||||
'lib/color.c',
|
||||
include_directories: incdir,
|
||||
dependencies: m_dep,
|
||||
version: '0.1.0',
|
||||
soversion: '0')
|
||||
executable('defocus', 'bin/defocus.c', include_directories: incdir, link_with: lib)
|
Loading…
Reference in New Issue
Block a user