Skip to content

Commit 4f3fee3

Browse files
iche033mergify[bot]
authored andcommitted
Add function for extracting single channel data from an RGB[A] image (#706)
Signed-off-by: Ian Chen <[email protected]> (cherry picked from commit e481234) # Conflicts: # graphics/src/AssimpLoader.cc
1 parent 0942236 commit 4f3fee3

File tree

4 files changed

+131
-8
lines changed

4 files changed

+131
-8
lines changed

graphics/include/gz/common/Image.hh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ namespace gz
6262
/// \brief Encapsulates an image
6363
class GZ_COMMON_GRAPHICS_VISIBLE Image
6464
{
65+
/// \brief Image channel
66+
public: enum class Channel
67+
{
68+
/// \brief Red channel
69+
RED = 0,
70+
/// \brief Green channel
71+
GREEN = 1,
72+
/// \brief Blue channel
73+
BLUE = 2,
74+
/// \brief Alpha channel
75+
ALPHA = 3
76+
};
77+
6578
/// \brief Pixel formats enumeration
6679
public: enum PixelFormatType
6780
{
@@ -222,6 +235,12 @@ namespace gz
222235
/// \return true if image has a bitmap
223236
public: bool Valid() const;
224237

238+
/// \brief Extract a single channel (red, green, blue, or alpha) from
239+
/// an RGB[A] image and return a single channel 8 bit image data.
240+
/// \param[in] _channel Channel to extract
241+
/// \return 8 bit single channel image data
242+
public: std::vector<unsigned char> ChannelData(Channel _channel) const;
243+
225244
/// \brief Convert a single channel image data buffer into an RGB image.
226245
/// During the conversion, the input image data are normalized to 8 bit
227246
/// values i.e. [0, 255]. Optionally, specify min and max values to use

graphics/src/AssimpLoader.cc

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,11 @@ std::pair<std::string, ImagePtr> AssimpLoader::Implementation::LoadTexture(
572572

573573
std::pair<ImagePtr, ImagePtr>
574574
AssimpLoader::Implementation::SplitMetallicRoughnessMap(
575+
<<<<<<< HEAD
575576
const common::Image& _img) const
577+
=======
578+
const Image &_img) const
579+
>>>>>>> e481234 (Add function for extracting single channel data from an RGB[A] image (#706))
576580
{
577581
std::pair<ImagePtr, ImagePtr> ret;
578582
// Metalness in B roughness in G
@@ -583,20 +587,26 @@ std::pair<ImagePtr, ImagePtr>
583587
std::vector<unsigned char> metalnessData(width * height * bytesPerPixel);
584588
std::vector<unsigned char> roughnessData(width * height * bytesPerPixel);
585589

590+
std::vector<unsigned char> metalnessData8bit =
591+
_img.ChannelData(Image::Channel::BLUE);
592+
std::vector<unsigned char> roughnessData8bit =
593+
_img.ChannelData(Image::Channel::GREEN);
586594
for (unsigned int y = 0; y < height; ++y)
587595
{
588596
for (unsigned int x = 0; x < width; ++x)
589597
{
590598
// RGBA so 4 bytes per pixel, alpha fully opaque
591-
auto baseIndex = bytesPerPixel * (y * width + x);
592-
auto color = _img.Pixel(x, (height - y - 1));
593-
metalnessData[baseIndex] = color.B() * 255.0;
594-
metalnessData[baseIndex + 1] = color.B() * 255.0;
595-
metalnessData[baseIndex + 2] = color.B() * 255.0;
599+
unsigned int idx = y * width + x;
600+
unsigned int colorB = metalnessData8bit[idx];
601+
unsigned int colorG = roughnessData8bit[idx];
602+
auto baseIndex = bytesPerPixel * idx;
603+
metalnessData[baseIndex] = colorB;
604+
metalnessData[baseIndex + 1] = colorB;
605+
metalnessData[baseIndex + 2] = colorB;
596606
metalnessData[baseIndex + 3] = 255;
597-
roughnessData[baseIndex] = color.G() * 255.0;
598-
roughnessData[baseIndex + 1] = color.G() * 255.0;
599-
roughnessData[baseIndex + 2] = color.G() * 255.0;
607+
roughnessData[baseIndex] = colorG;
608+
roughnessData[baseIndex + 1] = colorG;
609+
roughnessData[baseIndex + 2] = colorG;
600610
roughnessData[baseIndex + 3] = 255;
601611
}
602612
}

graphics/src/Image.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <cstdint>
2323
#include <cstring>
2424
#include <string>
25+
#include <vector>
2526

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

807808
return copy;
808809
}
810+
811+
//////////////////////////////////////////////////
812+
std::vector<unsigned char> Image::ChannelData(Channel _channel) const
813+
{
814+
if ((this->dataPtr->imageType != FIT_BITMAP) ||
815+
(this->dataPtr->colorType != FIC_RGB &&
816+
this->dataPtr->colorType != FIC_RGBALPHA))
817+
{
818+
gzerr << "Extraction of channel data is only support for RGB[A] images"
819+
<< std::endl;
820+
return {};
821+
}
822+
823+
FIBITMAP* channelData = nullptr;
824+
switch (_channel)
825+
{
826+
case Channel::RED:
827+
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_RED);
828+
break;
829+
case Channel::GREEN:
830+
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_GREEN);
831+
break;
832+
case Channel::BLUE:
833+
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_BLUE);
834+
break;
835+
case Channel::ALPHA:
836+
channelData = FreeImage_GetChannel(this->dataPtr->bitmap, FICC_ALPHA);
837+
break;
838+
default:
839+
break;
840+
}
841+
842+
if (!channelData)
843+
{
844+
gzerr << "Invalid input channel: " << static_cast<int>(_channel)
845+
<< std::endl;
846+
return {};
847+
}
848+
849+
FIBITMAP *tmp = FreeImage_ConvertTo8Bits(channelData);
850+
std::vector<unsigned char> data = this->dataPtr->DataImpl(tmp);
851+
FreeImage_Unload(tmp);
852+
return data;
853+
}

graphics/src/Image_TEST.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,55 @@ TEST_F(ImageTest, Color16bit)
784784
}
785785
}
786786

787+
/////////////////////////////////////////////////
788+
TEST_F(ImageTest, ChannelData)
789+
{
790+
// load image, extra data from each channel and verify values
791+
common::Image img;
792+
ASSERT_EQ(0, img.Load(kTestData));
793+
ASSERT_TRUE(img.Valid());
794+
795+
std::vector<unsigned char> red =
796+
img.ChannelData(common::Image::Channel::RED);
797+
std::vector<unsigned char> green =
798+
img.ChannelData(common::Image::Channel::GREEN);
799+
std::vector<unsigned char> blue =
800+
img.ChannelData(common::Image::Channel::BLUE);
801+
std::vector<unsigned char> alpha =
802+
img.ChannelData(common::Image::Channel::ALPHA);
803+
804+
EXPECT_FALSE(red.empty());
805+
ASSERT_EQ(img.Width() * img.Height(), red.size());
806+
ASSERT_EQ(red.size(), green.size());
807+
ASSERT_EQ(red.size(), blue.size());
808+
ASSERT_EQ(red.size(), alpha.size());
809+
810+
for (auto i = 0u; i < img.Height(); ++i)
811+
{
812+
for (auto j = 0u; j < img.Width(); ++j)
813+
{
814+
unsigned int idx = i * img.Width() + j;
815+
unsigned int r = red[idx];
816+
unsigned int g = green[idx];
817+
unsigned int b = blue[idx];
818+
unsigned int a = alpha[idx];
819+
820+
ASSERT_EQ(0u, g);
821+
ASSERT_EQ(255u, a);
822+
if (j < 80)
823+
{
824+
ASSERT_EQ(255u, r);
825+
ASSERT_EQ(0u, b);
826+
}
827+
else
828+
{
829+
ASSERT_EQ(0u, r);
830+
ASSERT_EQ(255u, b);
831+
}
832+
}
833+
}
834+
}
835+
787836
using string_int2 = std::tuple<const char *, unsigned int, unsigned int>;
788837

789838
class ImagePerformanceTest : public ImageTest,

0 commit comments

Comments
 (0)