What is the meaning of a negative number when using getRGB()? - java

I am new to color stuff, rendering etc. and watching a couple tutorial videos about rendering etc. My question is, when I call a getRGB method on a pixel, it returns a negative int. what is the meaning of this negative number? For example, when i call getRGB on a color with r: 186, g: 186, b: 186, it returns -4539718. How is this number related to its rgb value? I've made a couple of google search but was not successful.

The getRGB method returns an int whose 4 bytes are the alpha, red, green, and blue components in that order. Assuming that the pixel is not transparent, the alpha is 255 (0xFF). It's the most significant byte in the int, and the first bit is set in that value. Because in Java int values are signed according to Two's Complement, the value is actually negative because that first bit is on.

To get the color of a pixel:
Color c = new Color(image.getRGB(10,10));
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();

Related

How to check if a pixel is black using image.getRGB(x, y)

Should I expect the color of the pixel to be black if
image.getRGB(x, y) returns 0?
My assumption: I would expect 0 because the bit values of each of the values (Red, Green, Blue) would be zero. Am I correct in thinking this?
No, BufferedImage#getRGB() returns hex number. See this unit test:
public class TestRgb {
#Test
public void testBlack(){
BufferedImage bufferedImage = new BufferedImage(1,1, TYPE_BYTE_BINARY);
Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.setPaint(new Color(0,0,0)); //black
graphics2D.fillRect(0,0,1,1);
// pass - alpha channel set by default, even on all black pixels
TestCase.assertTrue(bufferedImage.getRGB(0,0)==0xFF000000);
// pass - when looking at just the color values (last 24 bits) the value is 0
TestCase.assertTrue((bufferedImage.getRGB(0,0) & 0x00FFFFFF)==0);
// fail - see above
TestCase.assertTrue(bufferedImage.getRGB(0,0)==0);
}
}
"Returns the RGB value representing the color in the default sRGB ColorModel. (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are =blue)."
That is, the packing (in hex locations) is as follows, where each component can have a value of 0 (0x00) .. 255 (0xFF).
AARRGGBB
Thus, the final value is not only dependent upon RGB, when all color components are zero:
AA000000
In fact, AA will be 0xFF ("100% opaque") by default unless it has explicitly been set to a different value in a buffer / model that supports an alpha channel.

Using setRGB to set 0-255 values instead of hex code values

I am currently using the .setRGB() method. It appears that the input for the int[] rgbArray is a hex-code value, which are very large integer values. I currently have a set of integers that range from 0 - 255, so whenever I input them using .setRGB, the image is just pure black, which makes sense given the range of hex values versus RGB values.
I was wondering is there a way for me to use non-hex values?
It's not Hex; it's bit-fiddled RGB. I would use java.awt.Color and then call getRGB(). So,
int rgb = new Color(red, green, blue).getRGB();
As mentioned in the other answer, the "large values" that you are talking about are the combined R,G,B components of the color, and possibly an "Alpha" component.
Setting a value of 255 with the setRGB method should thus cause the pixel to become perfeclty blue - unless it is an image that has an alpha channel. In this case it would become a perfectly transparent blue (aka "black").
However, when you have a value between 0 and 255, you can convert it into an RGB value (with 0=black and 255=white) as follows:
int value = ...
int rgb = (255 << 24) | (value << 16) | (value << 8) | value;
(The alpha component here is set to 255. For images without alpha channel, this will not change anything. But for images that have an alpha channel, this is crucial to make sure that the color is actually visible)

Java Color(int rgba) constructor and int overflow

According to the docs, this constructor exists:
public Color(int rgba,
boolean hasalpha)
I'm failing to see how you could use this to create the equivalent of Color(255,255,255,255) (e.g. 0xFFFFFFFF) given that java has no unsigned ints, however.
How do you use this constructor for a "big" color?
EDIT
Evidently the constructor can be used (surprise), but parsing an RGBa color string like this fails:
int x = Integer.parseInt("0xFFFFFFFF", 16); // Number format error
Color c = new Color(x, true);
The solution seems to be to use BigInteger to do the parsing. Sorry for the misdirected question!
Your question is not misdirected, but you seems to have misunderstood Kon's answer:
You are right about Java's Integer being signed all the time, but this doesn't mean that there are less bits of information in that number.
When you create a Color:
new Color(255, 255, 255, 255)
it is the same as using:
new Color(0xFFFFFFFF, true)
or using:
new Color(0b11111111111111111111111111111111, true)
0xFFFFFFFF is in fact -1, but this doesn't mean that any of the bits change; It's only a question of representation. The Color just cuts out the necessary bits for each color component.
So you can, in fact, create your desired color using:
Color c = new Color(-1,true);
System.out.println(c);
System.out.println(c.getAlpha());
which yields:
java.awt.Color[r=255,g=255,b=255]
255
Go binary.
Color c = new Color(0b11111111111111111111111111111111, true);
As per the Java docs, "alpha component is in bits 24-31, the red component is in bits 16-23, the green component is in bits 8-15, and the blue component is in bits 0-7"

What is the meaning of four parameters of cvScalar constructor in javacv?

Please can some one explain the meaning of the four parameters of the cvScalar(double d, double d1, double d2, double d3) method in javacv?
How can I represent black color in cvScalar ?
The cvScalar is simply a convenient container for 1, 2, 3 or 4 floating point values.
The meaning of the data in such tuples is left to the user of the cvScalar.
For example they can be used to hold, say, Points in the plane (2-tuple), Rectangles (4-tuple), RGB colors (3-tuple), Points in a 3-D world (3-tuple) etc. The cvScalar is systematically implemented as a 4-tuple, with the unused values set to 0.
To answer the question about the RGB color black:
cvScalar cBlack = new cvScalar(0, 0, 0, 0);
// BEWARE: the params for the cvScalar constructor are not in RGB order
// it is: new cvScalar(blue, green, red, unused)
// note how the 4th scalar is unused.
Alternatively you can use the CV_RGB() convenience method as in:
CvScalar cBlack = CV_RGB(0, 0, 0);
// here the CV_RGB() arguments are in Red, Green, Blue order.
Edit: because the example above was for the color black, whereby all color components have the same value, it failed to make evident that the order of the RGB components as stored within the CvScalar is reverse from the conventional order Red, Green, Blue.
The CV_RGB() convenience method's parameters are in the conventional RGB order, but the storage in the cvScalar is in Blue, Green, Red order.
In other words, the definition of CV_RGB is as follow:
public static CvScalar CV_RGB(double r, double g, double b) {
return cvScalar(b, g, r, 0);
}
Or said otherwise yet, cvScalar(0, 1, 130, 0) is equivalent to CV_RGB(130, 1, 0), i.e. the color red, with a minute touch of green.
In addition to CV_RGB(), when using cvScalars for the purpose of color values, it may be convenient to use cvScalar.Red(), cvScalar.Blue(), cvScalar.Green() methods to extract the individual components without having to worry where these are stored. The class also include a few static instances for each of the common colors: cvScalar.GRAY, cvScalar.YELLOW, cvScalar.BLUE etc.
cvScalar is a generic array of 4 doubles. the data type is often used to represent pixel values, e.g.:
CvScalar blue = CV_RGB(64, 64, 255);
the remaining doubles are set to 0 in the constructors that take fewer than 4 values.
cvGet2D is another function that returns a pixel value in the form of a CvScalar
The easiest way to read individual pixels is with the cvGet2D() function
CvScalar cvGet2D(const CvArr*, int row, int col);
This function takes three parameters: a pointer to a data container (CVArr*) and array indices for row and column location. The data container can be an IplImage structure. The topmost row of pixels is row=0, and the bottommost is row=height-1.
The cvGet2D() function returns a C structure, CvScalar, defined as
typedef struct CvScalar
{
double val[4];
}
CvScalar;
The pixel values for each channel are in val[i]. For grayscale images, val[0] contains pixel >brightness. The other three values are set to 0. For a three-channel, BGR image, blue=val[0], >green=val[1], and red=val[2].
http://www.cognotics.com/opencv/servo_2007_series/part_1/page_4.html

How do I apply a blue to yellow gradient on a bitmap through code, brightness as factor

I need to apply a blue to yellow gradient to a bitmap.
The factor here is the brightness.
The dark areas of the photo need to be blueish and the brightest area's yellow.
So the brightness of every pixel needs to be taken as a factor.
Can someone help me how to accomplish this in c++ or java?
The input is an array of rgb integer values of the original photo.
Sounds a bit like a homework question, but here's the general idea, or at least, how I would do it.
For each pixel, calculate the average brightness, so add R G and B together then divide by 3 to get the result (you'll need to use a variable greater than 8 bits here!).
Now you have a value back in the range of 0-255 indicating the brightness of the pixel (there are various ways to calculate brightness but this will do for now).
Full blue is (0,0,255), full yellow is (255,255,0) — so you need to interpolate between these values (we'll use linear interpolation here):
If your brightness is 50 for instance, it's ~20% of 255, so you want a colour that's 80% blue and 20% yellow. You can calculate the valye for the red channel like so:
R = (brightness / max) * (R in Yellow - R in Blue);
With similar calculations for the other channels, so for our pixel with a brightness of 50 we'd do:
R = (50 / 255) * 255;
G = (50 / 255) * 255;
Of course, we can't have negative values, and using B in Yellow - B in Blue idea isn't going to cut it for the blue channel, you need to invert the interpolation. By taking our 0.2 and subtracting it from 1 we can work through the range 0-255 in the other direction:
B = (1 - (50 / 255)) * 255;
Extra note: To work with something like this in C++ I'd suggest using SDL, it's nice and easy this kind of thing.
If I understood you correctly, the following (applied to all pixels individually) should do what you want:
// max_value gives the maximum allowed value for red, green and blue; that is,
// if red, green and blue are all equal to max_value, you have full white)
change_pixel(int& red, int& green, int& blue, int max_value)
{
blue = (red+green+blue)/3;
red = green = (max_value-blue);
}

Categories