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