I am implementing an alpha blending, and one of the examples I came across used this format. I am confused why the division by 256 and why isn't there inv_alpha in red and blue channels
int pixel,vga_pixel;
int alpha, blue, green, red, pixel;
int height = 1296;
int width = 968;
int x, y;
for (y = 0; y <= height; y++){
for (x = 0; x <= width; x++){
pixel = *(img.memloc + x + y);
//0xff gets the first 8 bits, in this case red
red = pixel & 0xff;
//shift by 8 to get rid of red then AND to get first 8, here green
green = pixel >> 8 & 0xff;
blue = pixel >> 16 & 0xff;
alpha = pixel >> 24 & 0xff;
int inv_alpha = 0xff - alpha; // 1-alpha
int vga_red = (red*(int)alpha);
int vga_green = (green*(int)alpha + inv_alpha/256);
int vga_blue = (blue*(int)alpha);
int vga_alpha = 0xff;
int vga_pixel = vga_alpha << 24 | vga_blue << 16 | vga_green << 8 | vga_red;
}
}
Can anyone clarify if this is a valid method, and why?
It look's like you've mixed the formulas from integer and floating point blending. For example the vga_red should probably become 255 if both red and alpha is, so it would be closer to (red*alpha)/255, but probably you should probably ensure correct rounding by using (red*alpha+127)/255.
The dividing inv_alpha with 256 would always yield zero so it's probably wrong, I'd guess that you want the result to be green if alpha is 255 and 255 if alpha is 0. So it would become something like (green*alpha+127)/255 + inv_alpha.
The formula for alpha blending is C = alpha_A * A + (1 - alpha_A * B). But in this formula we're working with floating point values and alpha is a value between 0 and 1.
Since we're working with integer values the alpha (and red, green and blue as well) is a value between 0 and 255. So the value of 1 - alpha_A is encapsulated in inv_alpha_A = 255 - alpha_A.
Since each color may not exceed the maximum value of one byte we have to ensure that the calculated number does not exceed 255. So we have to divide by 255.This results in:
C = (alpha_A * A + inv_aplha_A * B) / 255
(I intentionally skipped the rounding problem).
Related
I am trying to implement a function that blends two colors encoded with RGB565 using Alpha blending
Crgb565 = (1-a)Argb565 + a*Brgb565
Where a is the alpha parameter, and the alpha blending value of 0.0-1.0 is mapped to an unsigned char value on the range 0-32.
we can choose to use a five bit representation for a instead, thus restricting it to the range of 0-31 (effectively mapping to an alpha blending value of 0.0-0.96875).
Following code I am trying to implement, can you please suggest better way wrt less temp variable , memory optimization (number of multiplications and required memory accesses ),Is my logic for alpha bending is correct? I am not getting correct result/expected output, Seems like I am missing something, please review the code, Every suggest is appreciated, have some doubt based on alpha parameter. I have put my doubts in code comment section. Is there any way to shortening the alpha blending equations(division operation)?
=====================================================
unsigned short blend_rgb565(unsigned short A, unsigned short B, unsigned char Alpha)
{
unsigned short res = 0;
// Alpha converted from [0..255] to [0..31] (8 bit to 5 bit)
/* I want the alpha parameter (0-32), do i need to add something in Alpha before right shift?? */
Alpha = Alpha >> 3;
// Split Image A into R, G, B components
/*Do I need to take it as unsigned short or uint8_t also work fine ??*/
unsigned short A_r = A >> 11;
unsigned short A_g = (A >> 5) & ((1u << 6) - 1); // ((1u << 6) - 1) --> 00000000 00111111
unsigned short A_b = A & ((1u << 5) - 1); // ((1u << 5) - 1) --> 00000000 00011111
// Split Image B into R, G, B components
unsigned short B_r = B >> 11;
unsigned short B_g = (B >> 5) & ((1u << 6) - 1);
unsigned short B_b = B & ((1u << 5) - 1);
// Alpha blend components
/*Do I need to use 255(8 bit) instead of 32(5 bit), Why we are dividing by it , I have taken the ref from internet , but need little bit more clarification ??*/
unsigned short uiC_r = (A_r * Alpha + B_r * (32 - Alpha)) / 32;
unsigned short uiC_g = (A_g * Alpha + B_g * (32 - Alpha)) / 32;
unsigned short uiC_b = (A_b * Alpha + B_b * (32 - Alpha)) / 32;
// Pack result
res= (unsigned short) ((uiC_r << 11) | (uiC_g << 5) | uiC_b);
return res;
}
=====================
EDIT:
Adding method 2 ,is this approach is correct ?
Method 2:
// rrrrrggggggbbbbb
#define RB_MASK 63519 // 0b1111100000011111 --> hex :F81F
#define G_MASK 2016 // 0b0000011111100000 --> hex :07E0
#define RB_MUL_MASK 2032608 // 0b111110000001111100000 --> hex :1F03E0
#define G_MUL_MASK 64512 // 0b000001111110000000000 --> hex :FC00
unsigned short blend_rgb565(unsigned short A,unsigned short B,unsigned char Alpha) {
// Alpha converted from [0..255] to [0..31]
Alpha = Alpha >> 3
uint8_t beta = 32 - Alpha;
// so (0..32)*Alpha + (0..32)*beta always in 0..32
return (unsigned short)
(
(
( ( Alpha * (uint32_t)( A & RB_MASK ) + beta * (uint32_t)( B & RB_MASK )) & RB_MUL_MASK )
|
( ( Alpha * ( A & G_MASK ) + beta * ( B & G_MASK )) & G_MUL_MASK )
)
>> 5 // removing the alpha component 5 bit
);
}
It's possible to reduce the multiplies from 6 to 2 if you space out the RGB values into 2 32-bit integers before multiplying:
unsigned short blend_rgb565(unsigned short A, unsigned short B, unsigned char Alpha)
{
unsigned short res = 0;
// Alpha converted from [0..255] to [0..31] (8 bit to 5 bit)
Alpha = Alpha >> 3;
// Alpha = (Alpha + (Alpha >> 5)) >> 3; // map from 0-255 to 0-32 (if Alpha is unsigned short or larger)
// Space out A and B from RRRRRGGGGGGBBBBB to 00000RRRRR00000GGGGGG00000BBBBB
// 31 = 11111 binary
// 63 = 111111 binary
unsigned int A32 = (unsigned int)A;
unsigned int A_spaced = A32 & 31; // B
A_spaced |= (A32 & (63 << 5)) << 5; // G
A_spaced |= (A32 & (31 << 11)) << 11; // R
unsigned int B32 = (unsigned int)B;
unsigned int B_spaced = B32 & 31; // B
B_spaced |= (B32 & (63 << 5)) << 5; // G
B_spaced |= (B32 & (31 << 11)) << 11; // R
// multiply and add the alpha to give a result RRRRRrrrrrGGGGGGgggggBBBBBbbbbb,
// where RGB are the most significant bits we want to keep
unsigned int C_spaced = (A_spaced * Alpha) + (B_spaced * (32 - Alpha));
// remap back to RRRRRGGGGGBBBBB
res = (unsigned short)(((C_spaced >> 5) & 31) + ((C_spaced >> 10) & (63 << 5)) + ((C_spaced >> 16) & (31 << 11)));
return res;
}
You need to profile this to see if it is faster, it assumes that multiplications you save are slower than the extra bit-manipulations you replace them with.
can you please suggest better way wrt less temp variable
There is no advantage to remove temporary variables from the implementation. When you compile with optimizations turned on (e.g. -O2 or /O2) those temp variables will get optimized away.
Two adjustments I would make to your code:
Use uint16_t instead of unsigned short. For most platforms, it won't matter since sizeof(uint16_t)==sizeof(unsigned short), but it helps to be definitive.
No point in converting alpha from an 8-bit value to a 5-bit value. You'll get better accuracy with blending if you let alpha have the full range
Some of your bit-shifting looks weird. It might work. But I use a simpler approach.
Here's an adjustment to your implementation:
#include <stdint.h>
#define MAKE_RGB565(r, g, b) ((r << 11) | (g << 5) | (b))
uint16_t blend_rgb565(uint16_t a, uint16_t b, uint8_t Alpha)
{
const uint8_t invAlpha = 255 - Alpha;
uint16_t A_r = a >> 11;
uint16_t A_g = (a >> 5) & 0x3f;
uint16_t A_b = a & 0x1f;
uint16_t B_r = b >> 11;
uint16_t B_g = (b >> 5) & 0x3f;
uint16_t B_b = b & 0x1f;
uint32_t C_r = (A_r * invAlpha + B_r * Alpha) / 255;
uint32_t C_g = (A_g * invAlpha + B_g * Alpha) / 255;
uint32_t C_b = (A_b * invAlpha + B_b * Alpha) / 255;
return MAKE_RGB565(C_r, C_g, C_b);
}
But the bigger issue is that this function works on exactly one one pair of pixel colors. If you are invoking this function across an entire image or pair of images, the overhead of using the function call is going to be a major performance issue - even with compiler optimizations and inlining. So if you are calling this function row x col times, you should probably manually inline the code into your loop that is enumerating over every pixel on an image (or pair of images).
In the same vein as #samgak's answer, you can implement more efficiently on a 64 bits architecture by "post-masking", as follows:
rrrrrggggggbbbbb
Replicate to a long long (by shifting or mapping the long long to four shorts)
---------------- rrrrrggggggbbbbb rrrrrggggggbbbbb rrrrrggggggbbbbb
Mask out the useless bits
---------------- rrrrr----------- -----gggggg----- -----------bbbbb
Multiply by α
-----------rrrrr rrrrr----------- ggggggggggg----- ------bbbbbbbbbb
Mask out the low order bits
-----------rrrrr ---------------- gggggg---------- ------bbbbb-----
Pack
rrrrrgggggbbbbb
Another saving is possible by rewriting
(1 - α) X + α Y
as
X + α (Y - X)
(or X - α (X - Y) to avoid negatives). This spares a multiply (at the expense of a comparison).
Update:
The "saving" above cannot work because the negatives should be handled component-wise.
I want to color k clusters of points in a 2D grid. Right now I using a naive approach.
I'm using RGB to set a color, the G component is fix, R is counted down gradually, B is counted up gradually. So the first cluster has R set to 255 and the last to 0, vice versa for B.
int r = 255, g = 80, b = 0;
// do stuff
int step = 255 / k;
// loop over data
int cluster = getCurrentCluster();
int currentR = r - (cluster * step);
int currentG = g;
int currentB = b + (cluster * step);
The current solution is working and effektive. It's possible to differentiate the clusters by colors
But I don't like it, and would prefer rainbow colors or at least a richer spectrum.
How can I achieve that? How can I map an integer in interval [0, k) to a color that meets my requirements?
Another approach that came to my mind was to map the integer to a wave length in a given interval, e.g. 400 nm to 800 nm (should roughly be the rainbow spectrum, if I recall correctly) and convert the wavelength to RGB.
If you want to map a linear range to a rainbow like spectrum then you are better off starting with a color space like HSV and then convert to RGB.
Here you find the details of the conversion
HSV will give the nicest results, but needs trigonometry.
Instead, consider three functions:
R: r = x < 256 ? 255 - x : x < 512 ? 0 : x - 512
G: g = x < 256 ? x : x < 512 ? 512 - x : 0
B: b = x < 256 ? 0 : x < 512 ? x - 256 : 768 - x
These may be easier and faster, although less aestethically pleasing (not so a nice yellow, orange, etc.)
I have read an image in Mat format.
Mat image = imread("image.png", 1);
I declare a pointer to its data using
unsigned char *ptr_source = image.data
Now, I want to access the value of R,G and B values at each pixel in a for loop. I already know the method to do it with img.at<Veb3b>(i,j) or similar things but now, I have to do it using a pointer of unsigned char type.
uchar R_value = ptr_source[ i*?? + ??? ];
uchar G_value = ptr_source[ i*?? + ??? ];
uchar B_value = ptr_source[ i*?? + ??? ];
IMPORTANT: Some people here have mentioned to use the following:
unsigned char *input = (unsigned char*)(img.data);
for(int j = 0;j < img.rows;j++){
for(int i = 0;i < img.cols;i++){
unsigned char b = input[img.step * j + i ] ;
unsigned char g = input[img.step * j + i + 1];
unsigned char r = input[img.step * j + i + 2];
}
}
which makes sense to me as per the openCV docs but unfortunately it is not working in my case. The other method posted at SO says to use the following:
uchar b = frame.data[frame.channels()*(frame.cols*y + x) + 0];
uchar g = frame.data[frame.channels()*(frame.cols*y + x) + 1];
uchar r = frame.data[frame.channels()*(frame.cols*y + x) + 2];
Basic Question: Though, it seems to be working but I do not understand it logically. Why do we need to multiply (frame.cols*y + x) with frame.channels() ??
The cv::Mat::channels() method returns the number of channels in an image.
In a 8UC3 three-channel color image, channels() returns 3, and the pixels are stored in consecutive byte-triplets: BGRBGRBGRBGRBGR....
To access pixel (x,y) given a unsigned char* ptr_source pointer, you need to calculate the pixel offset. The image width is frame.cols. Each pixel is channels() == 3 bytes, so the pixel's unsiged char* offset will be ptr_source + frame.channels()*(frame.cols*y + x). This unsigned char* would usually be the blue channel with the following 2 chars the green and red.
For example, given a 3x4 image, the pixels in memory would look like this (spaces for clarity only):
r\c 0 1 2
0 BGR BGR BGR
1 BGR BGR BGR
2 BGR>BGR<BGR
3 BGR BGR BGR
So if you count bytes you'll see that the blue channel byte of pixel (1,2) is exactly at byte offset 3*(2*3+1) = 21
It is actually advisable to use img.step instead of the raw computation since some images have padding at the end of each pixel row so that it is not always true that img.step[0] == img.channels()*img.cols.
In this case you should use ptr_source[img.step[0]*y + img.channels()*x].
Additionally, your question assumes that the pixel depth is 8U which may not be correct for all images. If it is not, you will need to multiply everything by the depth (bytes per pixel) as well.
And this is essentially what cv::Mat:at<> does...
So I've successfully access pixel data in a frame using the c++ frame access wrapper on the opencv webpage
template<class Frame>
class Frame_Data {
IplImage *imgp;
public:
Frame_Data (IplImage *img=0) {imgp = img;}
~Frame_Data () {imgp = 0;}
void operator=(IplImage *img) {imgp=img;}
inline Frame* operator[] (int rowIndex) {
return ((Frame*)(imgp->imageData + rowIndex*imgp->widthStep));
}
};
typedef struct {
unsigned char b,g,r;
} RgbPixel;
typedef struct {
float b,g,r;
} RgbPixelFloat;
typedef Frame_Data<RgbPixel> RgbImage;
Im then using 2 for loops to go through the frame pixel array such as:
for (int i = ymin; i < ymax; i++)
{
for (int j = xmin; j < xmax; j++)
{
int r = image[i][j].r;
int g = image[i][j].g;
int b = image[i][j].b;
So lets say I want to throw in an IF statement to check pixel data colors. I've seen some websites list them as stuff like
image[i][j].r=0xFF;
or if g < 0x20
Im not used to the hex looking values, i tried to look them up but can't find any refernece, im used to cvscalars, so what do these mean? Like what does 0x20 stand for? or what about 0xFF?
thanks
The range from 0x00 ... 0xFF that you are seeing is one byte which can hold a value between 0 and 255 which is how pixel color data is stored, generally in 3 or 4 bytes consisting of Red, Blue, Green and optionally Alpha.
The CvScalar is just a convenience container of 1, 2, 3 or 4 doubles which can be used to hold these values in a slightly different form.
For example:
cv.RGB(1.0, 0.5, 0.3) sets the red component of the color to 1.0 or 100%, the green component to 0.5 or 50% and the blue component to 0.3 or 30%. When the actual color structure is created each of these components will be made up of exactly one byte so this is analagous to setting the
R (red component) to 1.0 * 0xFF = 0xFF
G (green component) to 0.5 * 0xFF = 0x7F
B (blue component) to 0.3 * 0xFF = 0x26
The alpha is automatically set to 1.0 or 0xFF
Hexidecimal is just another representation of a number (base 16).
It's not too hard to get used to, you just need to learn how to convert to and from regular base 10 numbers.
Open up your favourite windows/mac calculator, switch to Hex mode, and type in FF. (the 0x prefix just tells the code that it's it's hexidecimal number)
Switch to Dec[imal] and the number will change to 255.
Type 32 in, in Decimal mode, then click hex, you'll see the number change to 20 (or 0x20 as it is in your code)
Now you can go from hexidecimal to decimal, you can go from decimal to scalar quite easily; Just convert the range;
float Scalar = static_cast<float>( Decimal ) / 255.f; // 255 being the largest value for your byte-colour
Enjoy Hex! You'll find it a very useful, neat and important way of looking at data.
All right, so I have been very frustrated trying to convert a 12-bit buffer to an 8-bit one.
The image source is a 12-bit GrayScale (decompressed from JPEG2000) whose color range goes from 0-4095. Now I have to reduce that to 0-255. Common sense tells me that I should simply divide each pixel value like this. But when I try this, the image comes out too light.
void
TwelveToEightBit(
unsigned char * charArray,
unsigned char * shortArray,
const int num )
{
short shortValue = 0; //Will contain the two bytes in the shortArray.
double doubleValue = 0; //Will contain intermediary calculations.
for( int i = 0, j =0; i < num; i++, j +=2 )
{
// Bitwise manipulations to fit two chars onto one short.
shortValue = (shortArray[j]<<8);
shortValue += (shortArray[j+1]);
charArray[i] = (( unsigned char)(shortValue/16));
}
}
Now I can tell that there needs to be some contrast adjustments. Any ideas anyone?
Many Thanks in advance
In actuality, it was merely some simple Contrast adjustments that needed to be made. I realized this as soon as I loaded up the result image in Photoshop and did auto-contrast....the image result would very closely resemble the expected output image.
I found out an algorithm that does the contrast and will post it here for other's convenience:
#include <math.h>
short shortValue = 0; //Will contain the two bytes in the shortBuffer.
double doubleValue = 0; //Will contain intermediary calculations.
//Contrast adjustment necessary when converting
//setting 50 as the contrast seems to be real sweetspot.
double contrast = pow( ((100.0f + 50.0f) / 100.0f), 2);
for ( int i = 0, j =0; i < num; i++, j += 2 )
{
//Bitwise manipulations to fit two chars onto one short.
shortValue = (shortBuffer[j]<<8);
shortValue += (shortBuffer[j+1]);
doubleValue = (double)shortValue;
//Divide by 16 to bring down to 0-255 from 0-4095 (12 to 8 bits)
doubleValue /= 16;
//Flatten it out from 0-1
doubleValue /= 255;
//Center pixel values at 0, so that the range is -0.5 to 0.5
doubleValue -= 0.5f;
//Multiply and just by the contrast ratio, this distances the color
//distributing right at the center....see histogram for further details
doubleValue *= contrast;
//change back to a 0-1 range
doubleValue += 0.5f;
//and back to 0-255
doubleValue *= 255;
//If the pixel values clip a little, equalize them.
if (doubleValue >255)
doubleValue = 255;
else if (doubleValue<0)
doubleValue = 0;
//Finally, put back into the char buffer.
charBuffer[i] = (( unsigned char)(doubleValue));
}
The main problem, as I understand, is to convert a 12-bit value to a 8-bit one.
Range of 12-bit value = 0 - 4095 (4096 values)
Range of 8-bit value = 0 - 255 ( 256 values)
I would try to convert a 12-bit value x to a 8-bit value y
First, scale down first to the range 0-1, and
Then, scale up to the range 0-256.
Some C-ish code:
uint16_t x = some_value;
uint8_t y = (uint8_t) ((double) x/4096 ) * 256;
Update
Thanks to Kriss's comment, I realized that I disregarded the speed issue. The above solution, due to floating operations, might be slower than pure integer operations.
Then I started considering another solution. How about constructing y with the 8 most significant bits of x? In other words, by trimming off the 4 least significant bits.
y = x >> 4;
Will this work?
if you just want to drop the bottom 4 least significant bits you can do the following:
unsigned int start_value = SOMEVALUE; // starting value
value = (value & 0xFF0 ); // drop bits
unsigned char final_value =(uint8_t)value >> 4; //bit shift to 8 bits
Note the "unsigned". You don't want the signed bit mucking with your values.
Like this:
// Image is stored in 'data'
unsigned short* I = (unsigned short*)data;
for(int i=0; i<imageSize; i++) {
// 'color' is the 8-bit value
char color = (char)((double)(255*I[i])/(double)(1<<12));
/*...*/
}
Wild guess: your code assumes a big-endian machine (most significant byte first). A Windows PC is little-endian. So perhaps try
shortValue = (shortArray[j+1]<<8);
shortValue += (shortArray[j]);
If indeed endiasness is the problem then the code you presented would just shave off the 4 most significant bits of every value, and expand the rest to the intensity range. Hm, EDIT, 2 secs later: no, that was a thinko. But try it anyway?
Cheers & hth.,
– Alf