Added Bilinear interpolation.
This commit is contained in:
parent
d3082cb5f4
commit
1e5ffeb4b4
3 changed files with 60 additions and 6 deletions
|
|
@ -13,6 +13,13 @@
|
|||
/// 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 Interpolation methods.
|
||||
enum class InterpMethod {
|
||||
NEAREST, ///< Nearest neighbor interpolation.
|
||||
BILINEAR, ///< Bilinear interpolation.
|
||||
LANCZOS ///< Lanczos filtering interpolation.
|
||||
};
|
||||
|
||||
/// @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.
|
||||
|
|
@ -75,6 +82,12 @@ class Image {
|
|||
/// @return Given pixel as a 3D-vector containing the RGB values.
|
||||
Eigen::Vector3i GetPixel(Eigen::Vector2i const& pos) const;
|
||||
|
||||
/// @brief Returns the given pixel as a 3D-vector containing the RGB values, using the selected interpolation method.
|
||||
/// @param pos 2D vector containing the row and column indices. Floating point values are used.
|
||||
/// @param interp_method Interpolation method to use.
|
||||
/// @return Interpolated pixel as a 3D-vector containing the RGB values.
|
||||
Eigen::Vector3i GetPixelInterp(Eigen::Vector2d const& pos, InterpMethod const& interp_method) const;
|
||||
|
||||
/// @brief Sets the given pixel to the given RGB values.
|
||||
/// @param i Row index.
|
||||
/// @param j Column index.
|
||||
|
|
|
|||
|
|
@ -83,6 +83,19 @@ Eigen::Vector3i Image::GetPixel(Eigen::Vector2i const& pos) const {
|
|||
return GetPixel(pos[0], pos[1]);
|
||||
}
|
||||
|
||||
Eigen::Vector3i Image::GetPixelInterp(Eigen::Vector2d const& pos, InterpMethod const& interp_method) const {
|
||||
if(interp_method == Image::InterpMethod::BILINEAR) {
|
||||
int i = (int)std::floor(pos[0]);
|
||||
int j = (int)std::floor(pos[1]);
|
||||
double u = pos[0] - i;
|
||||
double v = pos[1] - j;
|
||||
Eigen::Vector3i rgb = ((1 - u) * (1 - v) * GetPixel(i, j).cast<double>() + u * (1 - v) * GetPixel(i + 1, j).cast<double>() + (1 - u) * v * GetPixel(i, j + 1).cast<double>() + u * v * GetPixel(i + 1, j + 1).cast<double>()).cast<int>();
|
||||
return rgb;
|
||||
}
|
||||
else // By default, use nearest neighbor interpolation
|
||||
return GetPixel((int)std::round(pos[0]), (int)std::round(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]);
|
||||
|
|
|
|||
|
|
@ -215,9 +215,9 @@ int main() {
|
|||
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));
|
||||
for (int i = 0; i < image.GetHeight(); ++i) {
|
||||
for (int j = 0; j < image.GetWidth(); ++j) {
|
||||
EXPECT_EQ(image.GetPixel(i, j), Eigen::Vector3i(1, 2, 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -226,9 +226,9 @@ int main() {
|
|||
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));
|
||||
for (int i = 0; i < image.GetHeight(); ++i) {
|
||||
for (int j = 0; j < image.GetWidth(); ++j) {
|
||||
EXPECT_EQ(image.GetPixel(i, j), Eigen::Vector3i(69, 69, 69));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -264,6 +264,34 @@ int main() {
|
|||
image.Save("test_img_512x256.bmp");
|
||||
image.Save("test_img_512x256.tga");
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "Bilinear interpolation\n";
|
||||
Image image1(3, 3, 3); // Source image
|
||||
Image image2(512, 512, 3); // Interpolated image (nearest neighbor)
|
||||
Image image3(512, 512, 3); // Interpolated image (bilinear)
|
||||
image1.SetPixel(0, 0, Eigen::Vector3i(255, 127, 0));
|
||||
image1.SetPixel(0, 1, Eigen::Vector3i(127, 192, 64));
|
||||
image1.SetPixel(0, 2, Eigen::Vector3i(100, 100, 50));
|
||||
image1.SetPixel(1, 0, Eigen::Vector3i(30, 0, 210));
|
||||
image1.SetPixel(1, 1, Eigen::Vector3i(192, 64, 0));
|
||||
image1.SetPixel(1, 2, Eigen::Vector3i(64, 150, 192));
|
||||
image1.SetPixel(2, 0, Eigen::Vector3i(100, 50, 150));
|
||||
image1.SetPixel(2, 1, Eigen::Vector3i(50, 120, 190));
|
||||
image1.SetPixel(2, 2, Eigen::Vector3i(240, 50, 15));
|
||||
|
||||
for(int i = 0; i < image2.GetHeight(); ++i) {
|
||||
for(int j = 0; j < image2.GetWidth(); ++j) {
|
||||
Eigen::Vector2d pos_float((double)i/image2.GetHeight()*(image1.GetHeight()-1), (double)j/image2.GetWidth()*(image1.GetWidth()-1));
|
||||
image2.SetPixel(i, j, image1.GetPixelInterp(pos_float, Image::InterpMethod::NEAREST));
|
||||
image3.SetPixel(i, j, image1.GetPixelInterp(pos_float, Image::InterpMethod::BILINEAR));
|
||||
}
|
||||
}
|
||||
|
||||
image1.Save("interp_src_3x3.png");
|
||||
image2.Save("interp_nearest_512x512.png");
|
||||
image3.Save("interp_bilinear_512x512.png");
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_TESTS_SUMMARY();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue