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

Hi,

I’m trying to translate/reuse some processing code which uses shifts. (for translating 2 byte RGB to 1byte grayscale) - I am stuck.
I didn’t yet understand the difference between the shift operations.

Maybe someone could enlight me and help with the translation.

Processing code:

``````//loc is defined and (I think) doesn't matter too much for the translation
int msb = packedbuf[2*loc] & 0xff;
int lsb = packedbuf[2*loc+1] & 0xff;
int r = (lsb >>> 3);
int g = ((lsb & 0x7) << 3);
g |= (msb >>> 5);
int b = (msb & 0x1f);

r = (r << 3)|(r >>> 2);
g = (g << 2)|(g >>> 4);
b = (b << 3)|(b >>> 2);
``````

My arduino code, which is wrong as I just removed everything what didn’t seemed to be c++ bit shift related:

``````//l is defined and is used instead of loc from the processing code, variables are defined earlier in the code
msb = 2*l;
lsb = 2*l+1;

r = (lsb >> 3);
g = (lsb << 3);
g |= (msb >> 5);
b = (msb);

r = (r << 3)|(r >> 2);
g = (g << 2)|(g >> 4);
b = (b << 3)|(b >> 2);
``````

I am going back to wikipedia and google trying to understand the java shift operations …

Thanks
Robert

Maybe there some explanation on what has to be achived by the code helps:

I have two bytes as RGB value: RRRRRGGG GGGBBBBB. At least that’s what I expect to get from the camera. (If I would fully understand what the processing code does, I would be sure )

I want to seperate them into three integers.
int 1= RRRRR
int 2= GGGGG
int 3= BBBBB

I thought it would maybe possible like this:

``````//buf contains the the byte stream
for (unsigned int l= 0; l < TWI_BUFFER_LENGTH/2; ++l){
r = (buf[l*2] >> 16) & 0xff ;     //bitwise shifting
g = (buf[l*2] >> 8) & 0xff ;
b = buf[l*2] & 0xff ;
//here calculate grayscale and write to grayscale img buffer
}
``````

But it only gives me a black picture.

Robert

robvoi: Maybe there some explanation on what has to be achived by the code helps:

I have two bytes as RGB value: RRRRRGGG GGGBBBBB. At least that's what I expect to get from the camera. (If I would fully understand what the processing code does, I would be sure :-) )

I want to seperate them into three integers. int 1= RRRRR int 2= GGGGG int 3= BBBBB

Yes, that is what the Processing code seems to do. The >>> operator is the Java unsigned bit shift operator - when you do an unsigned bit shift, the bits shifted into the most significant position are zero. The code seems to extract three 5-bit values from the 16 bits. The code to extract the g (green) channel is a bit more complicated that the other channels because it has to take three bits from one byte and two bits from the other.

the A >>> B pattern translates to a (A >> B) & C pattern where C is a mask with the lower (8-B) bits set to 1

leaves:

``````int msb = packedbuf[2*loc] & 0xff;
int lsb = packedbuf[2*loc+1] & 0xff;

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

This worked. And thanks a lot for the explanation. As you now finaly also wrote the convertion function for me I now get a grayscale picture from the cam.

I have to tune it as it is too dark, even with the most correct translation function you provided (have to figure out the bit shift part, but also without the calculaiton for the whole picture only takes 0.2 seconds).

I learned a lot from the information you provided. In retrospect all you explained (beside the bit shifting part) is clear and I should have been able to do it myself. But that how it is when you learn something.

Thanks Robert

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. 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 4)

I get an image with many black areas

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

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…
http://picturepush.com/public/11918058

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));
}
``````