Skip to content
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
19 changes: 19 additions & 0 deletions graphics/include/gz/common/Image.hh
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ namespace gz
/// \brief Encapsulates an image
class GZ_COMMON_GRAPHICS_VISIBLE Image
{
/// \brief Image channel
public: enum class Channel
{
/// \brief Red channel
RED = 0,
/// \brief Green channel
GREEN = 1,
/// \brief Blue channel
BLUE = 2,
/// \brief Alpha channel
ALPHA = 3
};

/// \brief Pixel formats enumeration
public: enum PixelFormatType
{
Expand Down Expand Up @@ -222,6 +235,12 @@ namespace gz
/// \return true if image has a bitmap
public: bool Valid() const;

/// \brief Extract a single channel (red, green, blue, or alpha) from
/// an RGB[A] image and return a single channel 8 bit image data.
/// \param[in] _channel Channel to extract
/// \return 8 bit single channel image data
public: std::vector<unsigned char> ChannelData(Channel _channel) const;

/// \brief Convert a single channel image data buffer into an RGB image.
/// During the conversion, the input image data are normalized to 8 bit
/// values i.e. [0, 255]. Optionally, specify min and max values to use
Expand Down
24 changes: 15 additions & 9 deletions graphics/src/AssimpLoader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ std::pair<std::string, ImagePtr> AssimpLoader::Implementation::LoadTexture(

std::pair<ImagePtr, ImagePtr>
AssimpLoader::Implementation::SplitMetallicRoughnessMap(
const common::Image& _img) const
const common::Image &_img) const
{
std::pair<ImagePtr, ImagePtr> ret;
// Metalness in B roughness in G
Expand All @@ -583,20 +583,26 @@ std::pair<ImagePtr, ImagePtr>
std::vector<unsigned char> metalnessData(width * height * bytesPerPixel);
std::vector<unsigned char> roughnessData(width * height * bytesPerPixel);

std::vector<unsigned char> metalnessData8bit =
_img.ChannelData(Image::Channel::BLUE);
std::vector<unsigned char> roughnessData8bit =
_img.ChannelData(Image::Channel::GREEN);
for (unsigned int y = 0; y < height; ++y)
{
for (unsigned int x = 0; x < width; ++x)
{
// RGBA so 4 bytes per pixel, alpha fully opaque
auto baseIndex = bytesPerPixel * (y * width + x);
auto color = _img.Pixel(x, (height - y - 1));
metalnessData[baseIndex] = color.B() * 255.0;
metalnessData[baseIndex + 1] = color.B() * 255.0;
metalnessData[baseIndex + 2] = color.B() * 255.0;
unsigned int idx = y * width + x;
unsigned int colorB = metalnessData8bit[idx];
unsigned int colorG = roughnessData8bit[idx];
auto baseIndex = bytesPerPixel * idx;
metalnessData[baseIndex] = colorB;
metalnessData[baseIndex + 1] = colorB;
metalnessData[baseIndex + 2] = colorB;
metalnessData[baseIndex + 3] = 255;
roughnessData[baseIndex] = color.G() * 255.0;
roughnessData[baseIndex + 1] = color.G() * 255.0;
roughnessData[baseIndex + 2] = color.G() * 255.0;
roughnessData[baseIndex] = colorG;
roughnessData[baseIndex + 1] = colorG;
roughnessData[baseIndex + 2] = colorG;
roughnessData[baseIndex + 3] = 255;
}
}
Expand Down
45 changes: 45 additions & 0 deletions graphics/src/Image.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>

#include <gz/common/Console.hh>
#include <gz/common/Util.hh>
Expand Down Expand Up @@ -806,3 +807,47 @@ FIBITMAP* Image::Implementation::SwapRedBlue(const unsigned int &_width,

return copy;
}

//////////////////////////////////////////////////
std::vector<unsigned char> Image::ChannelData(Channel _channel) const
{
if ((this->dataPtr->imageType != FIT_BITMAP) ||
(this->dataPtr->colorType != FIC_RGB &&
this->dataPtr->colorType != FIC_RGBALPHA))
{
gzerr << "Extraction of channel data is only support for RGB[A] images"
<< std::endl;
return {};
}

FIBITMAP* channelData = nullptr;
switch (_channel)
{
case Channel::RED:
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_RED);
break;
case Channel::GREEN:
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_GREEN);
break;
case Channel::BLUE:
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_BLUE);
break;
case Channel::ALPHA:
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_ALPHA);
break;
default:
break;
}

if (!channelData)
{
gzerr << "Invalid input channel: " << static_cast<int>(_channel)
<< std::endl;
return {};
}

FIBITMAP *tmp = FreeImage_ConvertTo8Bits(channelData);
std::vector<unsigned char> data = this->dataPtr->DataImpl(tmp);
FreeImage_Unload(tmp);
return data;
}
49 changes: 49 additions & 0 deletions graphics/src/Image_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,55 @@ TEST_F(ImageTest, Color16bit)
}
}

/////////////////////////////////////////////////
TEST_F(ImageTest, ChannelData)
{
// load image, extra data from each channel and verify values
common::Image img;
ASSERT_EQ(0, img.Load(kTestData));
ASSERT_TRUE(img.Valid());

std::vector<unsigned char> red =
img.ChannelData(common::Image::Channel::RED);
std::vector<unsigned char> green =
img.ChannelData(common::Image::Channel::GREEN);
std::vector<unsigned char> blue =
img.ChannelData(common::Image::Channel::BLUE);
std::vector<unsigned char> alpha =
img.ChannelData(common::Image::Channel::ALPHA);

EXPECT_FALSE(red.empty());
ASSERT_EQ(img.Width() * img.Height(), red.size());
ASSERT_EQ(red.size(), green.size());
ASSERT_EQ(red.size(), blue.size());
ASSERT_EQ(red.size(), alpha.size());

for (auto i = 0u; i < img.Height(); ++i)
{
for (auto j = 0u; j < img.Width(); ++j)
{
unsigned int idx = i * img.Width() + j;
unsigned int r = red[idx];
unsigned int g = green[idx];
unsigned int b = blue[idx];
unsigned int a = alpha[idx];

ASSERT_EQ(0u, g);
ASSERT_EQ(255u, a);
if (j < 80)
{
ASSERT_EQ(255u, r);
ASSERT_EQ(0u, b);
}
else
{
ASSERT_EQ(0u, r);
ASSERT_EQ(255u, b);
}
}
}
}

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

class ImagePerformanceTest : public ImageTest,
Expand Down
Loading