translating shifts from Java (Processing) to C++ (arduino)

can you post such a picture ?

have to tune it as it is too dark, even with the most correct translation function you provided

the reason is that the values of R, G, and B are not 0..255 which is assumed in the gray formulas.

int r = (lsb >> 3) & 0x1F;
int g = ((lsb & 0x07) << 3) | ((msb >> 5) & 0x07) ;
int b = (msb & 0x1f);

r = r << 3;  // as r is only 5 bit we must shift it to the left 3 positions
g = g << 2; // g has 6 bits
b = b << 3;  // ....

and now gray = (r + g + b )/3; or the more sophisticated formulas.

// and for some fun you could add some noise which will have a smoothing effect.

r = r << 3 + random(8); // fills up the 3 zero bits with some noise
g = g << 2 + random(4);
b = b << 3 + random(8);

@Robert

  1. if this work is done you should post a link to the HarcoCam group so others may use it to.
  2. the work is only really done if you make a separate command for downloading grayscale pictures that exists besides the rgb pictures.
    we now patched the dl command maybe create a dg (download gray) command?

Hi robtillaart,

  1. I am already in contact with them. They got the link to the discussions right when I created them. So far there is little response. But their website states that they are on vacation until the 13th.
  2. Updating the library and the Hub sketch was the plan anyway. I will try another thing (see 3) and than start cleaning up the code and do the library/sketch updating. Maybe the hacrocam guys want to kick in once they are back. :slight_smile: Otehrwise I'll provide them the updated code. Gettingthe serial transmition times of the cam down will extend the pissiblities for robotics use (where I want to use it for). This together with the low price tag ... I hope more people will buy the cam and a comunity starts to build up.
  3. Once the grayscale bought down the transmition time for the picture to half of the rgb time, I will now try to go to 4 bit grayscale. Should reduce it again by 50%. First step is to dig into the bit shifting and masking thing to combine the two times four bit to one byte.
  4. With the alpha correction code you provided....
r = r << 3;  // as r is only 5 bit we must shift it to the left 3 positions
g = g << 2; // g has 6 bits
b = b << 3;  // ....

.... I get an image with many black arreas (I think in the most bright areas of the picture). Using the bit shift here and take only green as gray, I get a nearly complete black picture.

Shifting one bit less ...

r = r << 2;
g = g << 1;
b = b << 2;

... gives a brighter image without the black areas.

BTW. I am surprised how well only taking the green chanel works. Almost no visible difference to the calculated values.

Thanks
Robert

  1. OK
  2. OK
  3. OK, had the same idea see other thread => you will get colour banding

I get an image with many black areas

As I have no HW to check things some advices are just based upon the code :wink:

I am surprised how well only taking the green chanel works. Almost no visible difference to the calculated values.

In the formulas green is ~60% of the info. that's why.

Q: Is it possible to post images ? RGB / gray (printscreen)

Hi,

here is an overview of the pics, including the one with the theoretically correct bit shift- which gives the black areas..

The 4 bit version is simulated only. It still works with 8 bit which I shifted right and left to reduce color depth.
I will now have to combine the two bytes to one and do the decoding on the other side.

Attached you also find the data sheet for the cam. Got it from a nice guy from hacroca (who is actually on vacation).
It shows that the RRRRRGGG GGGBBBBB coding is correct.

Regards,
Robert

TCM8230MD-1.pdf (952 KB)

for (unsigned int l= 0; l < TWI_BUFFER_LENGTH/2; ++l){

Please don't use the variable name l.

That looks amazingly like 1 on my PC, so the code l = 0 looks like "assign zero to one".

And you can imagine what this looks like:

b = buf[l*2] & 0xff ;

Also the variable name l and I look very similar (l = lower-case L and I = upper-case i).

Good point. I'll keep it in mind for new code. For editors we have dev friendly fonts. The browser hasn't. Otherwise using one for the code outline in the forum would have been nice.

Robert

Font or not, I wouldn't encourage it.

Imagine code where you had variables l (lower-case L), I (upper-case i) and O (upper-case o). And you had lines like this:

a = 1;
b = l;
c = I;
d = 0;
e = O;

You would have to have eagle eyes and good concentration not to get confused by that sort of stuff.

And you don't necessarily control the sort of font that other people who view your code might use.

From your code above this line:

lsb = 2*l+1;

... manages to combine L and one in the same line.

Yes, I know it's nitpicking. But improve on that and other problems will go away as the code is more readable. More spaces would help too.

eg.

lsb = (2 * loc) + 1;

Again, thanks. Especially using one char variable names makes it unnecessarily harder.

struct rgb_t
{
    union
    {
        struct {
            unsigned r:5;
            unsigned g:6;
            unsigned b:5;
        }
        uint16_t    rgb;
    }
};


rgb_t   rgb = { 1, 2, 3 };
int     r   = rgb.r;
int     g   = rgb.g;
int     b   = rgb.b;

'rgb_t' is the same size as an 'unsigned int', or 'uint16_t, on the Arduino.

rgb_t   rgb;

rgb.rgb = rgbPacked;

int     r   = rgb.r;
int     g   = rgb.g;
int     b   = rgb.b;

Thanks lloyddean .. but I don't quite understand the code you provided. Is this another way to decode the 2 byte RGB?

Thanks
Robert

Yes, but with a lot less work on your part in that you write less code.

Post your code and we'll go about getting to work the way you want.

Looking at a post in the 'Sensors' forum I saw you had posted some code. Here is a reimplementation of a short section in your library code -

struct rgb_t
{
    union {
        struct {
            unsigned _b:5;
            unsigned _g:6;
            unsigned _r:5;
        };
        uint16_t    _rgb;
    };
    
    rgb_t(uint8_t r, uint8_t g, uint8_t b)
        : _r(r), _g(g), _b(b)
    {}
    
    rgb_t(uint16_t rgb)
        : _rgb(rgb)
    {}

    operator uint16_t() const { return _rgb; };
    uint8_t red()   const     { return _r;   };
    uint8_t green() const     { return _g;   };
    uint8_t blue()  const     { return _b;   };
};

uint32_t HacroCam::pixel(uint8_t r, uint8_t g, uint8_t b)
{
    return rgb_t(r >> 3, g >> 2, b >> 3);
}

byte HacroCam::lsb(byte r, byte g, byte b) {
    return lowByte(pixel(r, g, b));
}

byte HacroCam::msb(byte r, byte g, byte b) {
    return highByte(pixel(r, g, b));
}

If I understand the basis of your original question you wish to convert a source pixel buffer of 'rrrrrggggggbbbbb' values to a gray scale equivalent destination pixel buffer.

The following code fragment should accomplish that ...

struct rgb_t
{
    union {
        struct {
            unsigned _b:5;
            unsigned _g:6;
            unsigned _r:5;
        };
        uint16_t    _rgb;
    };
    
    rgb_t(uint8_t r, uint8_t g, uint8_t b)
        : _r(r), _g(g), _b(b)
    {}
    
    rgb_t(uint16_t rgb)
        : _rgb(rgb)
    {}

    operator uint16_t() const { return _rgb; };
    uint8_t red()   const     { return _r;   };
    uint8_t green() const     { return _g;   };
    uint8_t blue()  const     { return _b;   };
};


uint8_t bufSrc[32];    // color pixel buffer
uint8_t bufDst[32];    // gray scale buffer

// convert the color pixel buffer 'bufSrc' to an average gray scale pixel buffer 'bufDst'

rgb_t* pSrc = (rgb_t*)bufSrc;
rgb_t* pDst = (rgb_t*)bufDst;

for (uint16_t i = sizeof(bufSrc) / 2; i--; )
{
    rgb_t    pixelSrc = *pSrc++;
    uint8_t  average  = (pixelSrc.red() + (pixelSrc.green() >> 1) + pixelSrc.blue());
    *pDst++ = rgb_t(average, average << 1, average);
}

You are correct. I try to converto 16 bit rgb to 8 bit and 4 bit grayscale.
Your code looks very clean. Creating a struct/class is really good, if reused often. Thanks for the input and example.

Do you expect your code to be more efficient or does the compiler translate my "beginner style" code to something equal?

Robert

The above example code is converting from 16-bit color to 16-bit gray scale.

What do you mean by converting to 8 bit and 4 bit grayscale.

rrrrrggggggbbbbb -> what 8-bit
rrrrrggggggbbbbb -> what 4-bit

I mean:
16 bit RGB = 1 pixel per 2 byte -> RRRRRGGGGGGBBBBB
8 bit grayscale = 1 pixel per byte -> GGGGGGGG

pix1 pix2
4 bit grayscale = 2 pixel per byte -> GGGG GGGG

It's working with the code provided by robtillaart. Yours is more compat but also (for me) more complaex to read.
If it ismore efficient regarding storage space or calculation time, I will try to implement it.

Thanks
Robert