Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix reading pixel values from single channel 16 bit image #439

Merged
merged 4 commits into from
Sep 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 58 additions & 10 deletions graphics/src/Image.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ namespace gz
/// \return bitmap data with red and blue pixels swapped
public: FIBITMAP* SwapRedBlue(const unsigned int &_width,
const unsigned int &_height) const;

/// \brief Get pixel value at specified index.
/// \param[in] _dib Pointer to Freeimage bitmap
/// \param[in] _x Pixel index in horizontal direction
/// \param[in] _y Pixel index in vertical direction
/// \param[out] _color Pixel value at specified index
nkoenig marked this conversation as resolved.
Show resolved Hide resolved
/// \return TRUE value if the pixel index was found and the color
/// value set, FALSE otherwise.
public: BOOL PixelIndex(FIBITMAP *_dib, unsigned _x, unsigned _y,
math::Color &_color) const;
};
}
}
Expand Down Expand Up @@ -507,16 +517,13 @@ math::Color Image::Pixel(unsigned int _x, unsigned int _y) const
}
else
{
BYTE byteValue;
if (FreeImage_GetPixelIndex(
this->dataPtr->bitmap, _x, _y, &byteValue) == FALSE)
if (this->dataPtr->PixelIndex(
this->dataPtr->bitmap, _x, _y, clr) == FALSE)
{
gzerr << "Image: Coordinates out of range ["
<< _x << " " << _y << "] \n";
return clr;
}

clr.Set(byteValue, byteValue, byteValue);
}

return clr;
Expand Down Expand Up @@ -590,23 +597,21 @@ math::Color Image::MaxColor() const
}
else
{
BYTE byteValue;
for (y = 0; y < this->Height(); y++)
{
for (x = 0; x < this->Width(); x++)
{
clr.Set(0, 0, 0, 0);

if (FreeImage_GetPixelIndex(
this->dataPtr->bitmap, x, y, &byteValue) == FALSE)
if (this->dataPtr->PixelIndex(
this->dataPtr->bitmap, x, y, clr) == FALSE)

{
gzerr << "Image: Coordinates out of range ["
<< x << " " << y << "] \n";
continue;
}

clr.Set(byteValue, byteValue, byteValue);

if (clr.R() + clr.G() + clr.B() > maxClr.R() + maxClr.G() + maxClr.B())
{
maxClr = clr;
Expand All @@ -618,6 +623,49 @@ math::Color Image::MaxColor() const
return maxClr;
}

//////////////////////////////////////////////////
BOOL Image::Implementation::PixelIndex(
FIBITMAP *_dib, unsigned _x, unsigned _y, math::Color &_color) const
{
if (!_dib)
return FALSE;

FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(_dib);
// 8 bit images
if (imageType == FIT_BITMAP)
{
BYTE byteValue;
// FreeImage_GetPixelIndex should also work with 1 and 4 bit images
if (FreeImage_GetPixelIndex(
_dib, _x, _y, &byteValue) == FALSE)
{
return FALSE;
}

unsigned int bpp = FreeImage_GetBPP(_dib);
// convert to float value between 0-1
float value = byteValue / static_cast<float>(((1 << (bpp)) - 1));
_color.Set(value, value, value);
}
// 16 bit images
else if (imageType == FIT_UINT16)
{
if ((_x < FreeImage_GetWidth(_dib)) && (_y < FreeImage_GetHeight(_dib)))
{
WORD *bits = reinterpret_cast<WORD *>(FreeImage_GetScanLine(_dib, _y));
uint16_t word = static_cast<uint16_t>(bits[_x]);
// convert to float value between 0-1
float value = word / static_cast<float>(math::MAX_UI16);
_color.Set(value, value, value);
}
else
{
return FALSE;
}
}
return TRUE;
}

//////////////////////////////////////////////////
void Image::Rescale(int _width, int _height)
{
Expand Down
44 changes: 44 additions & 0 deletions graphics/src/Image_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,50 @@ TEST_F(ImageTest, ConvertToRGBImage)
}
}

/////////////////////////////////////////////////
TEST_F(ImageTest, Grayscale)
{
{
common::Image img;
std::string fileName = common::testing::TestFile("data",
"grayscale_8bit.png");
EXPECT_EQ(0, img.Load(fileName));
unsigned int width = 4u;
unsigned int height = 4u;
unsigned int bits = 8u;
EXPECT_TRUE(img.Valid());
EXPECT_EQ(width, img.Width());
EXPECT_EQ(height, img.Height());
EXPECT_EQ(bits, img.BPP());
EXPECT_EQ(width * bits / 8u, img.Pitch());
EXPECT_EQ(common::Image::PixelFormatType::L_INT8, img.PixelFormat());
math::Color maxColor(0.847f, 0.847f, 0.847f);
EXPECT_NEAR(maxColor.R(), img.MaxColor().R(), 1e-3);
EXPECT_NEAR(maxColor.G(), img.MaxColor().G(), 1e-3);
EXPECT_NEAR(maxColor.B(), img.MaxColor().B(), 1e-3);
}

{
common::Image img;
std::string fileName = common::testing::TestFile("data",
"grayscale_16bit.png");
EXPECT_EQ(0, img.Load(fileName));
unsigned int width = 4u;
unsigned int height = 4u;
unsigned int bits = 16u;
EXPECT_TRUE(img.Valid());
EXPECT_EQ(width, img.Width());
EXPECT_EQ(height, img.Height());
EXPECT_EQ(bits, img.BPP());
EXPECT_EQ(width * bits / 8u, img.Pitch());
EXPECT_EQ(common::Image::PixelFormatType::L_INT16, img.PixelFormat());
math::Color maxColor(0.847f, 0.847f, 0.847f);
EXPECT_NEAR(maxColor.R(), img.MaxColor().R(), 1e-3);
EXPECT_NEAR(maxColor.G(), img.MaxColor().G(), 1e-3);
EXPECT_NEAR(maxColor.B(), img.MaxColor().B(), 1e-3);
}
}

using string_int2 = std::tuple<const char *, unsigned int, unsigned int>;

class ImagePerformanceTest : public ImageTest,
Expand Down
Binary file added test/data/grayscale_16bit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/data/grayscale_8bit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.