Image manipulation almost OK in C++.
This commit is contained in:
parent
14dd949f10
commit
d3082cb5f4
13 changed files with 381 additions and 302 deletions
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
105
cpp/include/Image.hpp
Normal file
105
cpp/include/Image.hpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#ifndef H_Image
|
||||
#define H_Image
|
||||
|
||||
#include <Eigen/Dense>
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
/// @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
|
||||
17
cpp/include/Slicer360ToPerspective.hpp
Normal file
17
cpp/include/Slicer360ToPerspective.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef H_Slicer360ToPerspective
|
||||
#define H_Slicer360ToPerspective
|
||||
|
||||
#include <Camera.hpp>
|
||||
|
||||
/// @brief This class encapsulates the algorithms to convert a 360-degree image to a perspective image.
|
||||
class Slicer360ToPerspective {
|
||||
public:
|
||||
Slicer360ToPerspective();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
std::vector<Camera> cameras;//!< A vector of cameras that are used to convert the 360-degree image to perspective images.
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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 <vector>
|
||||
|
||||
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<unsigned char> 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_ */
|
||||
100
cpp/src/Image.cpp
Normal file
100
cpp/src/Image.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#include <Image.hpp>
|
||||
|
||||
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];
|
||||
}
|
||||
6
cpp/src/Slicer360ToPerspective.cpp
Normal file
6
cpp/src/Slicer360ToPerspective.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include <Slicer360ToPerspective.hpp>
|
||||
|
||||
Slicer360ToPerspective::Slicer360ToPerspective()
|
||||
{
|
||||
|
||||
}
|
||||
6
cpp/src/main.cpp.nope
Normal file
6
cpp/src/main.cpp.nope
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello, World!\n";
|
||||
return 0;
|
||||
}
|
||||
2
cpp/src/stb_image.cpp
Normal file
2
cpp/src/stb_image.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
2
cpp/src/stb_image_write.cpp
Normal file
2
cpp/src/stb_image_write.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#include <iostream>
|
||||
#include <Camera.hpp>
|
||||
#include <Image.hpp>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h> // 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";
|
||||
}
|
||||
}
|
||||
27
test_interpolation.py
Normal file
27
test_interpolation.py
Normal file
|
|
@ -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()
|
||||
Loading…
Add table
Reference in a new issue