From d3082cb5f48d04688698d5623ff1ad37469dbcd6 Mon Sep 17 00:00:00 2001 From: Jerome Date: Sun, 30 Apr 2023 14:42:10 +0200 Subject: [PATCH] Image manipulation almost OK in C++. --- .gitignore | 13 +++ cpp/Makefile | 4 +- cpp/include/Image.hpp | 105 +++++++++++++++++ cpp/include/Slicer360ToPerspective.hpp | 17 +++ cpp/include/tinyimage.h | 146 ----------------------- cpp/src/Image.cpp | 100 ++++++++++++++++ cpp/src/Slicer360ToPerspective.cpp | 6 + cpp/src/main.cpp.nope | 6 + cpp/src/stb_image.cpp | 2 + cpp/src/stb_image_write.cpp | 2 + cpp/src/tests.cpp | 102 ++++++++++++++++- cpp/src/tinyimage.cpp | 153 ------------------------- test_interpolation.py | 27 +++++ 13 files changed, 381 insertions(+), 302 deletions(-) create mode 100644 .gitignore create mode 100644 cpp/include/Image.hpp create mode 100644 cpp/include/Slicer360ToPerspective.hpp delete mode 100644 cpp/include/tinyimage.h create mode 100644 cpp/src/Image.cpp create mode 100644 cpp/src/Slicer360ToPerspective.cpp create mode 100644 cpp/src/main.cpp.nope create mode 100644 cpp/src/stb_image.cpp create mode 100644 cpp/src/stb_image_write.cpp delete mode 100644 cpp/src/tinyimage.cpp create mode 100644 test_interpolation.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ea7bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +cpp/obj/* +cpp/stb-master/* +cpp/*.png +cpp/*.jpg +cpp/*.tga +cpp/*.bmp +*.png +*.jpg +*.bmp +*.tga +__pycache__/* +*.pyc +settings.json diff --git a/cpp/Makefile b/cpp/Makefile index 49772fd..fb8ebb6 100644 --- a/cpp/Makefile +++ b/cpp/Makefile @@ -1,6 +1,6 @@ CXX = g++ -CXXFLAGS = -std=c++17 -Wall -Wextra -pedantic -I./include -g -INCLUDES = -I./include -ID:/Users/Jerome/Documents/Ingenierie/Programmation/eigen-3.4.0 +CXXFLAGS = -std=c++17 -Wall -Wextra -pedantic -g +INCLUDES = -I./include -ID:/Users/Jerome/Documents/Ingenierie/Programmation/eigen-3.4.0 -I./stb-master SRC_DIR = src OBJ_DIR = obj diff --git a/cpp/include/Image.hpp b/cpp/include/Image.hpp new file mode 100644 index 0000000..d25b64d --- /dev/null +++ b/cpp/include/Image.hpp @@ -0,0 +1,105 @@ +#ifndef H_Image +#define H_Image + +#include +#include +#include + +/// @brief This class encapsulates the raw data of an image. +/// The Image class has a constructor that takes the width, height, and optionally depth of the image, and dynamically allocates a buffer of size width * height * depth to store the image data. The destructor deallocates the buffer to avoid memory leaks. +/// The class provides three accessor methods GetWidth(), GetHeight(), and GetDepth() to query the image dimensions. +/// The GetPixel() method takes the x, y, and z coordinates of the pixel (in row-major order) and returns the corresponding value from the buffer. +/// The SetPixel() method takes the x, y, and z coordinates of the pixel and a value, and sets the corresponding pixel in the buffer to the given value. +/// Note that the GetPixel() and SetPixel() methods use the formula z * width * height + y * width + x to compute the index of the pixel in the buffer. This formula assumes row-major order, where the x coordinate varies fastest, followed by the y coordinate, and then the z coordinate. If the image had a different ordering, the formula would need to be adjusted accordingly. +class Image { + public: + /// @brief Initializes the image with the given width, height, and optionally depth. Warning : the values are uninitialized. + /// @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); + + /// @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 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. + Save(std::string const& filename) const; + + int GetWidth() const; + int GetHeight() const; + int GetDepth() const; + + /// @brief Fills the image with the given value. All channels are set. + /// @param value Value to fill the image with. + Image & Fill(unsigned char value); + + /// @brief Fills the image with the given rgb value. + /// @param rgb RGB value to fill the image with. + Image & Fill(Eigen::Vector3i const& rgb); + + /// @brief Returns the value of the chosen channel of the given pixel. + /// @param i Row index. + /// @param j Column index. + /// @param c Channel index. + /// @return The value of the chosen channel of the given pixel. + unsigned char GetPixelValue(int i, int j, int c = 0) const; + + /// @brief Sets the value of the chosen channel of the given pixel. + /// @param i Row index. + /// @param j Column index. + /// @param c Channel index. + /// @param value Value of the chosen channel of the given pixel. + void SetPixelValue(int i, int j, int c, unsigned char value); + + /// @brief Returns a mutable reference to the chosen channel of the given pixel. + /// @param i Row index. + /// @param j Column index. + /// @param c Channel index. + /// @return A mutable reference to the value of the chosen channel of the given pixel. + unsigned char & PixelValue(int i, int j, int c = 0); + + /// @brief Returns the given pixel as a 3D-vector containing the RGB values. + /// @param i Row index. + /// @param j Column index. + /// @return Given pixel as a 3D-vector containing the RGB values. + Eigen::Vector3i GetPixel(int i, int j) const; + + /// @brief Returns the given pixel as a 3D-vector containing the RGB values. + /// @param pos 2D vector containing the row and column indices. + /// @return Given pixel as a 3D-vector containing the RGB values. + Eigen::Vector3i GetPixel(Eigen::Vector2i const& pos) const; + + /// @brief Sets the given pixel to the given RGB values. + /// @param i Row index. + /// @param j Column index. + /// @param rgb 3D-vector containing the RGB values. + /// @return Reference to the image. + Image & SetPixel(int i, int j, Eigen::Vector3i const& rgb); + + /// @brief Sets the given pixel to the given RGB values. + /// @param pos 2D vector containing the row and column indices. + /// @param rgb 3D-vector containing the RGB values. + /// @return Reference to the image. + Image & SetPixel(Eigen::Vector2i const& pos, Eigen::Vector3i const& rgb); + + /// @brief Accesses the value at the given index of the raw image data. + /// @param i Index of the element. Max is (width * height * depth) - 1. + /// @return The value at the given index of the raw image data. + unsigned char operator[](int i) const; + + private: + Image(Image const& other) = delete; // Copy constructor (deleted) + + int width; + int height; + int depth; + unsigned char* data; +}; + +#endif diff --git a/cpp/include/Slicer360ToPerspective.hpp b/cpp/include/Slicer360ToPerspective.hpp new file mode 100644 index 0000000..6ae2faf --- /dev/null +++ b/cpp/include/Slicer360ToPerspective.hpp @@ -0,0 +1,17 @@ +#ifndef H_Slicer360ToPerspective +#define H_Slicer360ToPerspective + +#include + +/// @brief This class encapsulates the algorithms to convert a 360-degree image to a perspective image. +class Slicer360ToPerspective { + public: + Slicer360ToPerspective(); + + + + private: + std::vector cameras;//!< A vector of cameras that are used to convert the 360-degree image to perspective images. +}; + +#endif diff --git a/cpp/include/tinyimage.h b/cpp/include/tinyimage.h deleted file mode 100644 index d0d801e..0000000 --- a/cpp/include/tinyimage.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - TinyImage - A tiny C/C++ image loading and saving library for graphics APIs. - Author: Charles Dong -*/ - -#ifndef TINYIMAGE_H_ -#define TINYIMAGE_H_ - -enum TinyImgColorType -{ - TINYIMG_RGB, - TINYIMG_RGBA -}; - -enum TinyImgError -{ - TINYIMG_OK, - TINYIMG_FORMAT_UNSUPPORTED, - TINYIMG_FILE_NOT_FOUND, - TINYIMG_INVALID_ARGUMENT -}; - -/* C-style interface begin */ - -/* - @brief Loads an image from disk. - - @param[filename] The name of the image file. - @param[width] Pointer to an integer that stores the image width (should be not NULL). - @param[height] Pointer to an integer that stores the image height (should be not NULL). - @param[type] The color type of the final image data. - - @return The image data in unsigned chars. If an error occurs, then NULL will be returned. -*/ -unsigned char * tinyimg_load(const char * filename, int * width, int * height, TinyImgColorType type); - -/* - @brief Frees the image data. - - @param[image] The image data. -*/ -void tinyimg_free(unsigned char * image); - -/* - @brief Saves the given image to disk. - - @param[filename] The name of the image file. - @param[width] The image width. - @param[height] The image height. - @param[type] The color type of the image data. - @param[image] The image data. - - @return 1 if successful, 0 if fails. -*/ -int tinyimg_save(const char * filename, int width, int height, TinyImgColorType type, const unsigned char * image); - -/* - @brief Gets the error code of the last error. - - @return The error code. If no error occured, 0 will be returned. -*/ -TinyImgError tinyimg_get_error(); - -/* - @brief Gets the description of the last error. - - @return The error string. If no error occured, NULL will be returned. -*/ -const char * tinyimg_get_error_str(); - -/* C-style interface end */ - -/* C++ style interface begin */ - -#ifdef __cplusplus - -#define TINYIMG_BEGIN namespace tinyimg { -#define TINYIMG_END } - -#include - -TINYIMG_BEGIN - -/* - @brief Loads an image from disk. - - @param[filename] The name of the image file. - @param[width] The image width. - @param[height] The image height. - @param[type] The color type of the final image data. - - @return The image data in unsigned chars. If an error occurs, then nullptr will be returned. -*/ -unsigned char * load(const char * filename, int & width, int & height, TinyImgColorType type); - -/* - @brief Frees the image data. - - @param[image] The image data. -*/ -void free(unsigned char * image); -/* - @brief Loads an image from disk into a vector. - - @param[filename] The name of the image file. - @param[width] The image width. - @param[height] The image height. - @param[type] The color type of the final image data. - - @return The image data in a vector. If an error occurs, an empty vector will be returned. -*/ -std::vector load_vec(const char * filename, int & width, int & height, TinyImgColorType type); - -/* - @brief Saves the given image to disk. - - @param[filename] The name of the image file. - @param[width] The image width. - @param[height] The image height. - @param[type] The color type of the image data. - @param[image] The image data. - - @return true if successful, false if fails. -*/ -bool save(const char * filename, int width, int height, TinyImgColorType type, const unsigned char * image); - -/* - @brief Gets the error code of the last error. - - @return The error code. If no error occured, 0 will be returned. -*/ -TinyImgError get_error(); - -/* -@brief Gets the description of the last error. - -@return The error string. If no error occured, nullptr will be returned. -*/ -const char * get_error_str(); - -TINYIMG_END - -#endif /* __cplusplus */ - -#endif /* TINYIMAGE_H_ */ \ No newline at end of file diff --git a/cpp/src/Image.cpp b/cpp/src/Image.cpp new file mode 100644 index 0000000..db7a6f3 --- /dev/null +++ b/cpp/src/Image.cpp @@ -0,0 +1,100 @@ +#include + +Image::Image(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) { + data = new unsigned char[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); + + // Allocate memory using new[] and copy the data from image.data. This avoids allocating memory with malloc and freeing it with delete. + if (image_data != nullptr) { + data = new unsigned char[width * height * depth]; + std::memcpy(data, image_data, width * height * depth); + stbi_image_free(image_data); + } else { // If the image loading process has failed + width = 1; + height = 1; + depth = 1; + data = new unsigned char[width * height * depth]; + data[0] = 0; + } +} + +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); + if(filename.size() > 4 && filename.substr(filename.size() - 4) == ".jpg") + return stbi_write_jpg(filename.c_str(), width, height, depth, (const void *)data, 100); + if(filename.size() > 4 && filename.substr(filename.size() - 4) == ".bmp") + return stbi_write_bmp(filename.c_str(), width, height, depth, (const void *)data); + if(filename.size() > 4 && filename.substr(filename.size() - 4) == ".tga") + return stbi_write_tga(filename.c_str(), width, height, depth, (const void *)data); + return -1;// If the file extension is not supported +} + +int Image::GetWidth() const { + return width; +} + +int Image::GetHeight() const { + return height; +} + +int Image::GetDepth() const { + return depth; +} + +Image & Image::Fill(unsigned char value) { + std::memset(data, value, width * height * depth); + return *this; +} + +Image & Image::Fill(Eigen::Vector3i const& rgb) { + for(int i = 0 ; i < height ; i++) + for(int j = 0 ; j < width ; j++) + SetPixel(i, j, rgb); + return *this; +} + +unsigned char Image::GetPixelValue(int i, int j, int c) const { + return data[i*width*depth + j*depth + c]; +} + +void Image::SetPixelValue(int i, int j, int c, unsigned char value) { + data[i*width*depth + j*depth + c] = value; +} + +unsigned char & Image::PixelValue(int i, int j, int c) { + return data[i*width*depth + j*depth + c]; +} + +Eigen::Vector3i Image::GetPixel(int i, int j) const { + int index = i*width*depth + j*depth; + return Eigen::Vector3i((int)data[index], (int)data[index + 1], (int)data[index + 2]); +} + +Eigen::Vector3i Image::GetPixel(Eigen::Vector2i const& pos) const { + return GetPixel(pos[0], pos[1]); +} + +Image & Image::SetPixel(int i, int j, Eigen::Vector3i const& rgb) { + SetPixelValue(i, j, 0, (unsigned char)rgb[0]); + SetPixelValue(i, j, 1, (unsigned char)rgb[1]); + SetPixelValue(i, j, 2, (unsigned char)rgb[2]); + return *this; +} + +Image & Image::SetPixel(Eigen::Vector2i const& pos, Eigen::Vector3i const& rgb) { + SetPixel(pos[0], pos[1], rgb); + return *this; +} + +unsigned char Image::operator[](int i) const { + return data[i]; +} diff --git a/cpp/src/Slicer360ToPerspective.cpp b/cpp/src/Slicer360ToPerspective.cpp new file mode 100644 index 0000000..f02ac73 --- /dev/null +++ b/cpp/src/Slicer360ToPerspective.cpp @@ -0,0 +1,6 @@ +#include + +Slicer360ToPerspective::Slicer360ToPerspective() +{ + +} \ No newline at end of file diff --git a/cpp/src/main.cpp.nope b/cpp/src/main.cpp.nope new file mode 100644 index 0000000..ad8283b --- /dev/null +++ b/cpp/src/main.cpp.nope @@ -0,0 +1,6 @@ +#include + +int main() { + std::cout << "Hello, World!\n"; + return 0; +} diff --git a/cpp/src/stb_image.cpp b/cpp/src/stb_image.cpp new file mode 100644 index 0000000..148bce1 --- /dev/null +++ b/cpp/src/stb_image.cpp @@ -0,0 +1,2 @@ +#define STB_IMAGE_IMPLEMENTATION +#include \ No newline at end of file diff --git a/cpp/src/stb_image_write.cpp b/cpp/src/stb_image_write.cpp new file mode 100644 index 0000000..2f540c3 --- /dev/null +++ b/cpp/src/stb_image_write.cpp @@ -0,0 +1,2 @@ +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include \ No newline at end of file diff --git a/cpp/src/tests.cpp b/cpp/src/tests.cpp index 6d2d729..b288964 100644 --- a/cpp/src/tests.cpp +++ b/cpp/src/tests.cpp @@ -1,5 +1,6 @@ #include #include +#include #define _USE_MATH_DEFINES #include @@ -129,7 +130,7 @@ int main() { camera.SetFOV(20*DEG2RAD); camera.SetUp(Eigen::Vector3d(0, 0, 1)); camera.SetTarget(Eigen::Vector3d(1.,.5,.3)); - + EXPECT_VEC_EQ(camera.ComputeRayDirInCameraFrame(Eigen::Vector2d( 0.0, 0.0)), Eigen::Vector3d(0.0, 0.0, -1.0)); EXPECT_VEC_EQ(camera.ComputeRayDirInCameraFrame(Eigen::Vector2d( 1.0, 0.0)), Eigen::Vector3d(0.1736481776669304, 0, -0.9848077530122081)); EXPECT_VEC_EQ(camera.ComputeRayDirInCameraFrame(Eigen::Vector2d( 1.0, 1.0)), Eigen::Vector3d(0.1710878697460355, 0.1710878697460355, -0.970287525247814)); @@ -166,6 +167,105 @@ int main() { } } + {// Image + std::cout << "Image\n"; + { + std::cout << "Constructors\n"; + Image image1(640, 480); + EXPECT_EQ(image1.GetWidth(), 640); + EXPECT_EQ(image1.GetHeight(), 480); + EXPECT_EQ(image1.GetDepth(), 1); + + Image image2(1080, 720, 3); + EXPECT_EQ(image2.GetWidth(), 1080); + EXPECT_EQ(image2.GetHeight(), 720); + EXPECT_EQ(image2.GetDepth(), 3); + } + + { + std::cout << "Pixel accessors\n"; + Image image(20, 10, 3); + image.SetPixelValue(5, 7, 0, 69); + image.SetPixelValue(5, 7, 1, 100); + image.SetPixelValue(5, 7, 2, 42); + EXPECT_EQ(image.GetPixelValue(5, 7, 0), 69); + EXPECT_EQ(image.GetPixelValue(5, 7, 1), 100); + EXPECT_EQ(image.GetPixelValue(5, 7, 2), 42); + + // Test reference accessor + image.PixelValue(5, 7, 0) = 13; + image.PixelValue(5, 7, 1) = 37; + image.PixelValue(5, 7, 2) = 74; + EXPECT_EQ(image.PixelValue(5, 7, 0), 13); + EXPECT_EQ(image.PixelValue(5, 7, 1), 37); + EXPECT_EQ(image.PixelValue(5, 7, 2), 74); + + // Test Vector accessors + EXPECT_EQ(image.GetPixel(5, 7), Eigen::Vector3i(13, 37, 74)); + EXPECT_EQ(image.GetPixel(Eigen::Vector2i(5, 7)), Eigen::Vector3i(13, 37, 74)); + + image.SetPixel(5, 7, Eigen::Vector3i(1, 2, 3)); + EXPECT_EQ(image.GetPixel(5, 7), Eigen::Vector3i(1, 2, 3)); + + image.SetPixel(Eigen::Vector2i(6, 8), Eigen::Vector3i(3, 2, 1)); + EXPECT_EQ(image.GetPixel(Eigen::Vector2i(6, 8)), Eigen::Vector3i(3, 2, 1)); + } + + { + std::cout << "Test Fill(rgb)\n"; + Image image(3, 2, 3); + image.Fill(Eigen::Vector3i(1, 2, 3)); + for (int y = 0; y < image.GetHeight(); ++y) { + for (int x = 0; x < image.GetWidth(); ++x) { + EXPECT_EQ(image.GetPixel(x, y), Eigen::Vector3i(1, 2, 3)); + } + } + } + + { + std::cout << "Test Fill(uchar)\n"; + Image image(3, 2, 3); + image.Fill(69); + for (int y = 0; y < image.GetHeight(); ++y) { + for (int x = 0; x < image.GetWidth(); ++x) { + EXPECT_EQ(image.GetPixel(x, y), Eigen::Vector3i(69, 69, 69)); + } + } + } + + { + std::cout << "Image loading\n"; + Image image("../test_img_4x3.png"); + EXPECT_EQ(image.GetWidth(), 4); + EXPECT_EQ(image.GetHeight(), 3); + EXPECT_EQ(image.GetDepth(), 3); + + for(int i = 0; i < image.GetHeight(); ++i) { + for(int j = 0; j < image.GetWidth(); ++j) { + auto pixel = image.GetPixel(i, j); + std::cout << i << " " << j << " (" << pixel(0)/255.0 << ", " << pixel(1)/255.0 << ", " << pixel(2)/255.0 << ")\n"; + } + } + + for(int i = 0 ; i < image.GetWidth()*image.GetHeight()*image.GetDepth() ; i++) + std::cout << i << "\t" << (int)(image[i]) << "\t" << (image[i]/255.0) << "\n"; + } + + { + std::cout << "Image saving\n"; + Image image(512, 256, 3); + for(int i = 0; i < image.GetHeight(); ++i) { + for(int j = 0; j < image.GetWidth(); ++j) { + image.SetPixel(i, j, Eigen::Vector3i(127, i%256, j%256)); + } + } + image.Save("test_img_512x256.png"); + image.Save("test_img_512x256.jpg"); + image.Save("test_img_512x256.bmp"); + image.Save("test_img_512x256.tga"); + } + } + PRINT_TESTS_SUMMARY(); return 0; diff --git a/cpp/src/tinyimage.cpp b/cpp/src/tinyimage.cpp deleted file mode 100644 index 85acd88..0000000 --- a/cpp/src/tinyimage.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* Source file for TinyImage */ - -/* Prevent error C4996 in Visual Studio compilers */ -#ifdef _MSC_VER -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include "tinyimage.h" - -#include -#include -#include // for pow() - -/* The error code */ -TinyImgError _error; - -/* Internal functions */ - -int _equal(const char * str1, const char * str2); -int _tinyimg_check_format(const char * extension); -int _tinyimg_open_file(FILE ** fp, const char * filename); -unsigned char * _tinyimg_load(FILE * fp, const char * extension, int * width, int * height); -unsigned char * _tinyimg_load_bmp(FILE * fp, int * width, int * height); - -int _equal(const char * str1, const char * str2) -{ - return strcmp(str1, str2) == 0; -} - -int _tinyimg_check_format(const char * extension) -{ - return extension != NULL && (_equal(extension, ".bmp")); -} - -int _tinyimg_open_file(FILE ** fp, const char * filename) -{ - *fp = fopen(filename, "rb"); - return *fp != NULL; -} - -unsigned char * _tinyimg_load(FILE * fp, const char * extension, int * width, int * height) -{ - if (_equal(extension, ".bmp")) - return _tinyimg_load_bmp(fp, width, height); -} - -unsigned char * _tinyimg_load_bmp(FILE * fp, int * width, int * height) -{ - unsigned char * image; // image data - unsigned char * palette = NULL; // palette data (if uses palette) - int width_file; // pixels per line in BMP (note that BMP has 4-pixel alignment for each line) - int size; // pixel count - short bit_count; // bit count per pixel (24 if no palette) - int color_count = 0; // colors used (if uses palette) - unsigned char temp; - int count = 0; - - /* Checks if the pointers are not NULL */ - if (width == NULL || height == NULL) - { - _error = TINYIMG_INVALID_ARGUMENT; - return NULL; - } - - fseek(fp, 18, SEEK_SET); - fread(width, sizeof(int), 1, fp); // read width - fread(height, sizeof(int), 1, fp); // read height - - fseek(fp, 28, SEEK_SET); - fread(&bit_count, sizeof(short), 1, fp); // read bit count - - fseek(fp, 54, SEEK_SET); - /* If uses palette (bit count is not 24) */ - if (bit_count != 24) - { - color_count = (int)pow(2.0, bit_count); - palette = (unsigned char *)malloc(sizeof(unsigned char) * 4 * color_count); - fread(palette, sizeof(unsigned char), 4 * color_count, fp); - } - - /* Allocates memory for the image */ - width_file = ((*width) + 3) / 4 * 4; // Increase the width to make sure it's multiple of 4 - size = width_file * (*height); - image = (unsigned char *)malloc(sizeof(unsigned char) * size * 3); - - /* Reads the image data */ - if (bit_count == 24) - fread(image, sizeof(unsigned char), size * 3, fp); - else - { - while (count < size) - { - fread(&temp, sizeof(unsigned char), 1, fp); - image[count * 3] = palette[temp * 4]; - image[count * 3 + 1] = palette[temp * 4 + 1]; - image[count * 3 + 2] = palette[temp * 4 + 2]; - count++; - } - } - - fclose(fp); - return image; -} - -/* External functions */ - -unsigned char * tinyimg_load(const char * filename, int * width, int * height, TinyImgColorType type) -{ - const char * extension; - FILE * fp; - - /* Check if the image format is supported */ - extension = strrchr(filename, '.'); - if (!_tinyimg_check_format(extension)) - { - _error = TINYIMG_FORMAT_UNSUPPORTED; - return NULL; - } - - /* Check if the file exists */ - if (!_tinyimg_open_file(&fp, filename)) - { - _error = TINYIMG_FILE_NOT_FOUND; - return NULL; - } - - return _tinyimg_load(fp, extension, width, height); -} - -void tinyimg_free(unsigned char * image) -{ - free(image); -} - -TinyImgError tinyimg_get_error() -{ - return _error; -} - -const char * tinyimg_get_error_str() -{ - switch (_error) - { - case TINYIMG_OK: - return NULL; - case TINYIMG_FORMAT_UNSUPPORTED: - return "format unsupported"; - case TINYIMG_FILE_NOT_FOUND: - return "file not found"; - case TINYIMG_INVALID_ARGUMENT: - return "invalid argument"; - } -} \ No newline at end of file diff --git a/test_interpolation.py b/test_interpolation.py new file mode 100644 index 0000000..237d176 --- /dev/null +++ b/test_interpolation.py @@ -0,0 +1,27 @@ +import numpy as np +import matplotlib.pyplot as plt + +def interp2_normalized(f00, f10, f01, f11, x, y): + a00 = f00 + a10 = f10 - f00 + a01 = f01 - f00 + a11 = f11 - f10 - f01 + f00 + return a00 + a10*x + a01*y + a11*x*y + +def interp2(x0, y0, x1, y1, f00, f10, f01, f11, x, y): + x_n = (x - x0)/(x1 - x0) + y_n = (y - y0)/(y1 - y0) + return interp2_normalized(f00, f10, f01, f11, x_n, y_n) + +if __name__ == '__main__': + f00, f10, f01, f11 = 0, 1, 2, -3 + N = 101 + F = np.zeros((N,N)) + for i in range(N): + for j in range(N): + F[i,j] = interp2_normalized(f00, f10, f01, f11, i/(N-1), j/(N-1)) + + plt.figure() + plt.imshow(F) + plt.colorbar() + plt.show() \ No newline at end of file