2

I am writing a small program to convert an OpenInventor file to a PCD one. To do so I have two files in input, namely the OpenInventor file and a JPEG image. The texture coordinates are float values between 0.0 and 1.0.

I use OpenCV to extract the RGB value and return it in decimal format, but the following function does not seem to work properly...

float get_color(cv::Mat img, float x, float y) {

    int i = x*img.cols;
    int j = y*img.rows;

    unsigned char R = img.ptr<unsigned char>(j)[3*i];
    unsigned char G = img.ptr<unsigned char>(j)[3*i+1];
    unsigned char B = img.ptr<unsigned char>(j)[3*i+2];

    return  R*pow(16,4) +
            G*pow(16,2) +
            B;
}

I load the image with

 cv::imread("filename.jpg", CV_LOAD_IMAGE_COLOR).
sciarp
  • 314
  • 3
  • 14
  • 1
    How can you possibly represent an RGB color with just one `float`? – Desmond Hume Jul 22 '12 at 19:02
  • @DesmondHume: My thoughts exactly. – Goz Jul 22 '12 at 19:05
  • What do you want to do with that one float? Do you maybe want an average so you get a gray scale image? – Shahbaz Jul 22 '12 at 19:12
  • Actually, you can store 3 bytes in a float. Floats are 32 bit, with a 24 bit mantissa. Only 23 of these are actually stored, but that doesn't matter since due to the floating point stuff the first bit is always 1. So, if you represent R, G and B with an 8 bit value each, simply using something like 256*256*R+256*G+B will do the trick, and should be fully reversible. Why anyone would use a float instead of an int is beyond me, though – Christian Stieber Jul 22 '12 at 19:13
  • @ChristianStieber I have a 24-bit RGB color in mind. According to your formula it is represented as `3302550.0`. Could you reverse it back to its R, G, and B values? – Desmond Hume Jul 22 '12 at 19:21
  • @DesmondHume, B = 45, G = 100, R = 50. – Shahbaz Jul 22 '12 at 19:24
  • 1
    @DesmondHume, yeah, I think I had a typo computing B. Anyway, B is 150. What I meant was, it's very simple to do the reverse, I don't understand what's your objection! – Shahbaz Jul 22 '12 at 20:25
  • Thank you all for the comments...ahahah! This is amazing! If you wanna convert back and forth from a RGB value expressed in float notation (whose max is 2*3,4*10^38, and FYI a RGB has max value in decimal base of 16777215 ) you can use this website http://www.yellowpipe.com/yis/tools/hex-to-rgb/color-converter.php/ ...use then your calculator to make hex->dec. Anyway this was not the point of the question...I would really appreciate to have other critiques about the method, I agree there are better way to express RGB but for the time being is what it is...thanks! – sciarp Jul 23 '12 at 06:40

2 Answers2

1

Do you mean to return it as a 32-bit integer?

unsigned int get_color(cv::Mat img, float x, float y) 
{

    int i = x*img.cols;
    int j = y*img.rows;

    unsigned char R = img.ptr<unsigned char>(j)[3*i];
    unsigned char G = img.ptr<unsigned char>(j)[3*i+1];
    unsigned char B = img.ptr<unsigned char>(j)[3*i+2];

    return  (R << 16) |
            (G << 8) |
            B;
}

Or perhaps you want to return it as floats in which case you need to do the following

struct FloatColour
{
    float r;
    float g;
    float b;
};

float get_color(cv::Mat img, float x, float y) 
{

    int i = x*img.cols;
    int j = y*img.rows;

    unsigned char R = img.ptr<unsigned char>(j)[3*i];
    unsigned char G = img.ptr<unsigned char>(j)[3*i+1];
    unsigned char B = img.ptr<unsigned char>(j)[3*i+2];

    FloatColour retCol;
    retCol.r = R / 255.0f;
    retCol.g = G / 255.0f;
    retCol.b = B / 255.0f;
    return retCol;
}
Goz
  • 61,365
  • 24
  • 124
  • 204
1

I found the answer to my own question in a comment found in the PCL's header "point_types.hpp" (PCL version: 1.5.1):

Due to historical reasons (PCL was first developed as a ROS package), the RGB information is packed into an integer and casted to a float. This is something we wish to remove in the near future, but in the meantime, the following code snippet should help you pack and unpack RGB colors in your PointXYZRGB structure:

uint8_t r = 255, g = 0, b = 0;
uint32_t rgb = ((uint32_t)r << 16 | (uint32_t)g << 8 | (uint32_t)b);
p.rgb = *reinterpret_cast<float*>(&rgb);

After refactoring and few other bug fixes, the function has become:

float get_color(cv::Mat img, float s, float t){

        int j = (1.0 - s)*(float)img.cols;
        int i = (1.0 - t)*(float)img.rows;

        uint8_t R = img.at<cv::Vec3b>(i,j)[2];
        uint8_t G = img.at<cv::Vec3b>(i,j)[1];
        uint8_t B = img.at<cv::Vec3b>(i,j)[0];

        uint32_t rgb_32 = ((uint32_t)R << 16 | (uint32_t)G << 8 | (uint32_t)B);

        return *reinterpret_cast<float*>(&rgb_32);
}
Community
  • 1
  • 1
sciarp
  • 314
  • 3
  • 14