How to convert 16 bit hex color to RGB888 values in C++ - c++

I have uint16_t color and need to convert it into its RGB equivalent. The hex is set up so the first 5 bits represent red, next 6 for green, and last 5 for blue.
So far I have found something close to a solution but not quite due to truncation.
void hexToRGB(uint16_t hexValue)
{
int r = ((hexValue >> 11) & 0x1F); // Extract the 5 R bits
int g = ((hexValue >> 5) & 0x3F); // Extract the 6 G bits
int b = ((hexValue) & 0x1F); // Extract the 5 B bits
r = ((r * 255) / 31) - 4;
g = ((g * 255) / 63) - 2;
b = ((b * 255) / 31) - 4;
printf("r: %d, g: %d, b: %d\n",r, g, b);
}
int main()
{
//50712=0xC618
hexToRGB(50712);
return 0;
}
The example above yields r: 193, g: 192, b: 193 which should be r: 192, g: 192, b: 192 I have been using this question as reference, but I essentially need a backwards solution to what they are asking.

What about the following:
unsigned r = (hexValue & 0xF800) >> 8; // rrrrr... ........ -> rrrrr000
unsigned g = (hexValue & 0x07E0) >> 3; // .....ggg ggg..... -> gggggg00
unsigned b = (hexValue & 0x1F) << 3; // ............bbbbb -> bbbbb000
printf("r: %d, g: %d, b: %d\n", r, g, b);
That should result in 0xC618 --> 192, 192, 192, but 0xFFFF --> 248, 252, 248, i.e. not pure white.
If you want 0xFFFF to be pure white, you'll have to scale, so
unsigned r = (hexValue & 0xF800) >> 11;
unsigned g = (hexValue & 0x07E0) >> 5;
unsigned b = hexValue & 0x001F;
r = (r * 255) / 31;
g = (g * 255) / 63;
b = (b * 255) / 31;
Then 0xC618 --> 197, 194, 197, instead of the expected 192, 192, 192, but 0xFFFF is pure white and 0x0000 is pure black.

There are no "correct" ways to convert from the RGB565 scale to RGB888. Each colour component needs to be scaled from its 5-bit or 6-bit range to an 8-bit range and there are varying ways to do this each often producing different types of visual artifact in an image.
When scaling a colour in the n-bit range we might decide we want the following to be generally true:
that absolute black (eg 00000 in 5-bit space) must map to absolute black in 8-bit space;
that absolute white (eg 11111 in 5-bit space) must map to absolute white in 8-bit space;
Achieving this means we basically wish to scale the value from (2n - 1) shades in n-bit space into (28 - 1) shades in 8-bit space. That is, we want to effectively do the following in some way:
r_8 = (255 * r / 31)
g_8 = (255 * g / 63)
b_8 = (255 * b / 31)
Different approaches often taken are:
scale using integer division
scale using floating division and then round
bitshift into 8-bit space and add the most significant bits
The latter approach is effectively the following
r_8 = (r << 3) | (r >> 2)
g_8 = (g << 2) | (g >> 4)
b_8 = (b << 3) | (b >> 2)
For your 5-bit value 11000 these would result in 8-bit values of:
197
197
198 (11000000 | 110)
Similarly your six bit value 110000 would result in 8-bit values of:
194
194
195 (11000000 | 11)

Related

Convert RGB surface to YUV in hardware using Direct3D 9

I have an ARGB Direct3D9 surface that I need to blit into UYVY surface of the same dimensions. Both surfaces are in system memory. How can I accomplish this?
UpdateSurface and StretchRect fail.
I'm open to using textures instead of surfaces if needed.
This must be done in GPU, i.e. with hardware acceleration.
In DirectXTex there is code for doing all these conversions you could look at for reference. The legacy Direct3D 9 D3DFMT_UYVY format is the same as DXGI_FORMAT_YUY2 with some channel swizzling.
These formats encode two visible pixels in each image pixel:
struct XMUBYTEN4 { // DirectXMath data type
uint8_t x;
uint8_t y;
uint8_t z;
uint8_t w;
};
XMUBYTEN4 rgb1, rgb2 = // Input pixel pair
int y0 = ((66 * rgb1.x + 129 * rgb1.y + 25 * rgb1.z + 128) >> 8) + 16;
int u0 = ((-38 * rgb1.x - 74 * rgb1.y + 112 * rgb1.z + 128) >> 8) + 128;
int v0 = ((112 * rgb1.x - 94 * rgb1.y - 18 * rgb1.z + 128) >> 8) + 128;
int y1 = ((66 * rgb2.x + 129 * rgb2.y + 25 * rgb2.z + 128) >> 8) + 16;
int u1 = ((-38 * rgb2.x - 74 * rgb2.y + 112 * rgb2.z + 128) >> 8) + 128;
int v1 = ((112 * rgb2.x - 94 * rgb2.y - 18 * rgb2.z + 128) >> 8) + 128;
For DXGI_FORMAT_YUY2 you would use:
XMUBYTEN4 *dPtr = // Output pixel pair
dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>(y0, 0), 255));
dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 255));
dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>(y1, 0), 255));
dPtr->w = static_cast<uint8_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 255));
For D3DFMT_UYVY you would use:
dPtr->x = static_cast<uint8_t>(std::min<int>(std::max<int>((u0 + u1) >> 1, 0), 255));
dPtr->y = static_cast<uint8_t>(std::min<int>(std::max<int>(y0, 0), 255));
dPtr->z = static_cast<uint8_t>(std::min<int>(std::max<int>((v0 + v1) >> 1, 0), 255));
dPtr->w = static_cast<uint8_t>(std::min<int>(std::max<int>(y1, 0), 255));

Fill array dynamicly with gradient color c++

what I'm trying to do is fill an array with an rainbow gradient. The array should hold 256 entries an filled with the hex value of colors.
like:
array[0] = 0xFF0000 //red
...
array[85] = 0xFFA200 //orange
...
array[170] = 0x00AF0F //green
...
array[255] = 0xAE00FF //purple
because I do not want to assign all 256 colors "by hand" to the array I'm looking for an dynamicly approach for that. It's not necessarily need to be the ranbow displayed above. The picture is just for demonstration purpose.
Any suggestions how to do things like this in an (preferably) short code snipit avoiding a couple of nested for loops?
We want to go from:
red -> yellow
yellow -> green
green -> cyan
cyan -> blue
blue -> magenta
magenta -> red
In each pass, one of the red, green, blue components is always 0, the second is 255, and the third is increasing or decreasing between 0 and 255.
In other words:
{255, 0, 0} -> {255, 255, 0} grn increases to 255
{255, 255, 0} -> { 0, 255, 0} red decreases to 0
{0 , 255, 0} -> { 0, 255, 255} blu increases to 255
{0 , 255, 255} -> { 0, 0, 255} grn decreases to 0
{0 , 0, 255} -> {255, 0, 255} red increases to 255
{255, 0, 255} -> {255, 0, 0} blu decreases to 0
This produces 256 * 6 colors, we may not want all of those colors, so it has to be normalized. This can be done with following code:
//input: ratio is between 0.0 to 1.0
//output: rgb color
uint32_t rgb(double ratio)
{
//we want to normalize ratio so that it fits in to 6 regions
//where each region is 256 units long
int normalized = int(ratio * 256 * 6);
//find the region for this position
int region = normalized / 256;
//find the distance to the start of the closest region
int x = normalized % 256;
uint8_t r = 0, g = 0, b = 0;
switch (region)
{
case 0: r = 255; g = 0; b = 0; g += x; break;
case 1: r = 255; g = 255; b = 0; r -= x; break;
case 2: r = 0; g = 255; b = 0; b += x; break;
case 3: r = 0; g = 255; b = 255; g -= x; break;
case 4: r = 0; g = 0; b = 255; r += x; break;
case 5: r = 255; g = 0; b = 255; b -= x; break;
}
return r + (g << 8) + (b << 16);
}
Usage:
double range = 500.0;
for (double i = 0; i < range; i++)
{
uint32_t color = rgb(i / range);
...
}
Output:
One way to do what you want is to interpolate each of the component colours (RGB) from their starting to their ending value. This means using steps that are of as equal size as possible.
To get the RGB components some bit manipulation is necessary. This code gives you the three component colours for a fully-stated colour fullColour:
std::array<float, 3> colourRGB;
for(unsigned i = 0; i<3; ++i) {
colourRGB[i] = (fullColour & (0xFF << (i*8))) >> (i*8);
You use this to get the RGB array of your starting and ending colour (for example, for the red-orange range in your example this would be the RGB breakdown of 0xFF0000 and 0xFFA200). For each component you then work out the step size required for each step in your 'fade'. This is given by the total change in that component divided by the total number of steps. For the red-orange example the step size for the Red component would thus be 1.91 (because you have 86 steps and a total change of (0xA2 - 0x00, or 162 in decimal, yielding 162/86=1.91). The step sizes for the other components are zero as they don't change.
You can then iterate over the steps, at each one adding another step size and rounding to get the new value for each component. For example, at step s:
red[s] = startingRed + ((float)s * stepSizeRed)
To re-combine your rgb values back into a full colour, just apply some bit manipulation again:
fullColour[s] = 0;
for(unsigned i=0; i<3; ++i)
fullColour[s] += rgbComponent[s][i] << (i*8);
This approach yields the required 'fade' from any starting to any ending colour in any number of steps.

Advanced rgb2hsv conversion Matlab to opnecv/C++ access to pixel value

I am building a program in objective C/C++ and openCV. I am pretty skilled in Objective C but new to C++.
I am building custom RGB2HSV algorithm. My algorithm is slightly different from the openCV library cvtColor(in, out, CV_RGB2HSV).
The one I try to translate form Matlab to opencV/C++ produces so clear HSV image that no additional filtering is needed before further processing. Code below – Matlab code is self-explanatory.
I try to translate it to C++/openCV function out of it but I hit the wall trying to access pixel values of the image. I am new to C++.
I read a lot on the ways how to access Mat structure but usually I obtain either bunch of letters in a place of zeros or a number typically something like this “\202 k g”. When I try to do any multiplication operations on the say \202 the result has nothing to do with math.
Please help me to properly access the pixel values. Also in current version using uchar won’t work because some values are outside 0-255 range.
The algorithm is not mine. I cannot even point the source but it gives clearly better results than stock RGB2HSV.
Also the algorithm below is for one pixel. It needs to be applied each pixel in the image so in final version it need to wrapped with for { for {}} loops.
I also wish to share this method with community so everyone can benefit from it and saving on pre-filtering.
Please help me translate it to C++ / openCV. If possible with the best practices speed wise. Or at least how to clearly access the pixel value so it is workable with range of mathematical equations. Thanks in advance.
function[H, S, V] = rgb2hsvPixel(R,G,B)
% Algorithm:
% In case of 8-bit and 16-bit images, `R`, `G`, and `B` are converted to the
% floating-point format and scaled to fit the 0 to 1 range.
%
% V = max(R,G,B)
% S = / (V - min(R,G,B)) / V if V != 0
% \ 0 otherwise
% / 60*(G-B) / (V - min(R,G,B)) if V=R
% H = | 120 + 60*(B-R) / (V - min(R,G,B)) if V=G
% \ 240 + 60*(R-G) / (V - min(R,G,B)) if V=B
%
% If `H<0` then `H=H+360`. On output `0<=V<=1`, `0<=S<=1`, `0<=H<=360`.
red = (double(R)-16)*255/224; % \
green = (double(G)-16)*255/224; % }- R,G,B (0 <-> 255) -> (-18.2143 <-> 272.0759)
blue = (min(double(B)*2,240)-16)*255/224; % /
minV = min(red,min(green,blue));
value = max(red,max(green,blue));
delta = value - minV;
if(value~=0)
sat = (delta*255) / value;% s
if (delta ~= 0)
if( red == value )
hue = 60*( green - blue ) / delta; % between yellow & magenta
elseif( green == value )
hue = 120 + 60*( blue - red ) / delta; % between cyan & yellow
else
hue = 240 + 60*( red - green ) / delta; % between magenta & cyan
end
if( hue < 0 )
hue = hue + 360;
end
else
hue = 0;
sat = 0;
end
else
% r = g = b = 0
sat = 0;
hue = 0;
end
H = max(min(floor(((hue*255)/360)),255),0);
S = max(min(floor(sat),255),0);
V = max(min(floor(value),255),0);
end
To access the value of a pixel in a 3-channel, 8-bit precision image (type CV_8UC3) you have to do it like this:
cv::Mat image;
cv::Vec3b BGR = image.at<cv::Vec3b>(i,j);
If, as you say, 8-bit precision and range are not enough, you can declare a cv::Mat of type CV_32F to store floating point 32-bit numbers.
cv::Mat image(height, width, CV_32FC3);
//fill your image with data
for(int i = 0; i < image.rows; i++) {
for(int j = 0; j < image.cols; j++) {
cv::Vec3f BGR = image.at<cv::Vec3f>(i,j)
//process your pixel
cv::Vec3f HSV; //your calculated HSV values
image.at<cv::Vec3f>(i,j) = HSV;
}
}
Be aware that OpenCV stores rgb values in the BGR order and not RGB. Take a look at OpenCV docs to learn more about it.
If you are concerned by performance and fairly comfortable with pixel indexes, you can use directly the Mat ptr.
For example:
cv::Mat img = cv::Mat::zeros(4, 8, CV_8UC3);
uchar *ptr_row_img;
int cpt = 0;
for(int i = 0; i < img.rows; i++) {
ptr_row_img = img.ptr<uchar>(i);
for(int j = 0; j < img.cols; j++) {
for(int c = 0; c < img.channels(); c++, cpt++, ++ptr_row_img) {
*ptr_row_img = cpt;
}
}
}
std::cout << "img=\n" << img << std::endl;
The previous code should print:
img= [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23; 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47; 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
69, 70, 71; 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95]
The at access should be enough for most of the cases and is much more readable / less likely to make a mistake than using the ptr access.
References:
How to scan images, lookup tables and time measurement with OpenCV
C++: OpenCV: fast pixel iteration
Thanks everybody for help.
Thanks to your hints I constructed the custom rgb2hsv function C++/openCV.
From the top left respectively, edges after bgr->gray->edges, bgr->HSV->edges, bgr->customHSV->edges
Below each of them corresponding settings of the filters to achieve approximately the same clear results. The bigger the radius of a filter the more complex and time consuming computations.
It produces clearer edges in next steps of image processing.
It can be tweaked further experimenting with parameters in r g b channels:
red = (red-16)*1.1384; //255/244=1.1384
here 16 – the bigger the number the clearer V becomes
255/244 – also affect the outcome extending it beyond ranges 0-255, later to be clipped.
This numbers here seem to be golden ratio but anyone can adjust for specific needs.
With this function translating BGR to RGB can be avoided by directly connecting colors to proper channels in raw image.
Probably it is a little clumsy performance wise. In my case it serves in first step of color balance and histogram adjustment so speed is not that critical.
To use in constant processing video stream it need speed optimization, I think by using pointers and reducing loop complexity. Optimization is not exactly my cup of tea. So if someone helped to optimize it for the community that would be great.
Here it is ready to use:
Mat bgr2hsvCustom ( Mat& image )
{
//smallParam = 16;
for(int x = 0; x < image.rows; x++)
{
for(int y = 0; y<image.cols; y++)
{
//assigning vector to individual float BGR values
float blue = image.at<cv::Vec3b>(x,y)[0];
float green = image.at<cv::Vec3b>(x,y)[1];
float red = image.at<cv::Vec3b>(x,y)[2];
float sat, hue, minValue, maxValue, delta;
float const ang0 = 0; // func min and max don't accept varaible and number
float const ang240 = 240;
float const ang255 = 255;
red = (red-16)*1.1384; //255/244
green = (green-16)*1.1384;
blue = (min(blue*2,ang240)-16)*1.1384;
minValue = min(red,min(green,blue));
maxValue = max(red,max(green,blue));
delta = maxValue - minValue;
if (maxValue != 0)
{
sat = (delta*255) / maxValue;
if ( delta != 0)
{
if (red == maxValue){
hue = 60*(green - blue)/delta;
}
else if( green == maxValue ) {
hue = 120 + 60*( blue - red )/delta;
}
else{
hue = 240 + 60*( red - green )/delta;
}
if( hue < 0 ){
hue = hue + 360;
}
}
else{
sat = 0;
hue = 0;
}
}
else{
hue = 0;
sat = 0;
}
image.at<cv::Vec3b>(x,y)[0] = max(min(floor(maxValue),ang255),ang0); //V
image.at<cv::Vec3b>(x,y)[1] = max(min(floor(sat),ang255),ang0); //S
image.at<cv::Vec3b>(x,y)[2] = max(min(floor(((hue*255)/360)),ang255),ang0); //H
}
}
return image;
}

Hex to Dec using bit-manipulation

Could somebody explain how this actually works for example the char input = 'a'.
I understand that << shift the bits over by four places (for more than one character). But why in the second part add 9? I know 0xf = 15.....Am I missing something obvious.
result = result << 4 | *str + 9 & 0xf;
Here is my understand so far:
char input = 'a' ascii value is 97. Add 9 is 106, 106 in binary is 01101010. 0xf = 15 (00001111), therefore 01101010 & 00001111 = 00001010, this gives the value of 10 and the result is then appended on to result.
Thanks in advance.
First, let's rewrite this with parenthesis to make the order of operations more clear:
result = (result << 4) | ((*str + 9) & 0xf);
If result is 0 on input, then we have:
result = (0 << 4) | ((*str + 9) & 0xf);
Which simplifies to:
result = (0) | ((*str + 9) & 0xf);
And again to:
result = (*str + 9) & 0xf;
Now let's look at the hex and binary representations of a - f:
a = 0x61 = 01100001
b = 0x62 = 01100010
c = 0x63 = 01100011
d = 0x64 = 01100100
e = 0x65 = 01100101
f = 0x66 = 01100110
After adding 9, the & 0xf operation clears out the top 4 bits, so we don't need to worry about those. So we're effectively just adding 9 to the lower 4 bits. In the case of a, the lower 4 bits are 1, so adding 9 gives you 10, and similarly for the others.
As chux mentioned in his comment, a more straightforward way of achieving this is as follows:
result = *str - 'a' + 10;

Permutation of a number's digits

Consider number 194 declared as type int
Is it possible to obtain it's digits permutations like other ints efficiently?
Number: 194
419 int
491 int
914 int
941 int
I am using the next_permutation however it only works with arrays. So I thought it wouldn't be wise to convert int to an int array (?!) then obtain the permutation as an array and convert it to it.
Any suggestions?
Permuting the digits is basically a string-operation, not a (simple) mathematical operation. Converting to an array (string) and then using next_permutation() sounds more sensible than trying to do it mathematically.
Here's the mathematical version - without intermediate values saved:
int a = 194;
int b = (a / 100) * 100 + (a % 10) * 10 + ((a / 10) % 10) * 1; // 149
int c = (a % 10) * 100 + ((a / 10) % 10) * 10 + (a / 100) * 1; // 491
int d = (a % 10) * 100 + (a / 100) * 10 + ((a / 10) % 10) * 1; // 419
int e = ((a / 10) % 10) * 100 + (a / 100) * 10 + (a % 10) * 1; // 914
int f = ((a / 10) % 10) * 100 + (a % 10) * 10 + (a / 100) * 1; // 941
With intermediate values, it's a little easier to see what's going on (except that I generated different assignments for b through f this time).
int a = 194;
int d1 = a / 100;
int d2 = (a / 10) % 10;
int d3 = a % 10;
int a = d1 * 100 + d2 * 10 + d3 * 1; // 194
int b = d1 * 100 + d3 * 10 + d2 * 1; // 149
int c = d2 * 100 + d1 * 10 + d3 * 1; // 914
int d = d2 * 100 + d3 * 10 + d1 * 1; // 941
int e = d3 * 100 + d1 * 10 + d2 * 1; // 419
int f = d3 * 100 + d2 * 10 + d1 * 1; // 491
Use the next_permutation() mechanism; it will generalize to 4-digit and 5-digit and N-digit numbers where this will not.
You'd first have to extract each decimal place's value first: either by converting it to a character array (itoa()) or by writing a small for loop that divides the number by powers of 10. Once you have the digits separated, you can write a loop to generate the permutations.
Getting the permutations of the decimal digits will require you to interact with the number as a decimal, so power-of-2 manipulations are probably not going to help much here.
My suggestion would be:
1. Convert number to string
2. Set up the string as a circular buffer
3. Step through the buffer progressively (each increment of the index into the circular buffer will give you one permutation)
4. Reconstruct the number from the "new" arrangement of the characters representing the digits
5. Repeat for the length of the string.
Unless you are running in a slow/resource-constrained environment, I wouldn't try to overthink the problem beyond this.
Edit:
As pointed out in the comments this doesn't generate all permutations, to do so would require adding another step at the end where the process is repeated but with progressively larger increments to the index variable.