Combine/compare colors in java - java

I would like to do 2 things:
Compare two colors (RGB), so that comparer gives me say 1 if the colors are the same and 0 if the compared colors are on the opposite sides of RGB like black and white, and some number from 0 to 1 if they are somehow equal (like both are reddish)
Mix 2 or more colors together to produce a new one: mixing blue and yellow should give me green, mixing red and green should give black etc.
Questions:
Is there any parts of java API which can do something like this for me? If not is there any 3rd part open source java libraries which can facilitate that?
Thanks.

1.
There are many different methods for comparing colors. If you want perceptual dissimilarity, check out the comments of other users. If you just want something simple that gives an indication: use this code:
int rgb1 = ...
int rgb2 = ...
int r, g, b;
r = (rgb1 >> 16) & 0x000000ff;
g = (rgb1 >> 8) & 0x000000ff;
b = rgb1 & 0x000000ff;
r -= (rgb2 >> 16) & 0x000000ff;
g -= (rgb2 >> 8) & 0x000000ff;
b -= rgb2 & 0x000000ff;
double answer = (r*r+g*g+b*b)/(255*255*3.0);
It calculates a euclidean distance and scales it to range from 0 to 1.
2.
Just as there are many different ways to compare colors, there are many ways to combine colors. It depends on what you want.
You could take the average but that's not what you want. As it would darken the resulting color.
EDIT: here is the code to take the average:
r = (rgb1 >> 16) & 0x000000ff;
g = (rgb1 >> 8) & 0x000000ff;
b = rgb1 & 0x000000ff;
r += (rgb2 >> 16) & 0x000000ff;
g += (rgb2 >> 8) & 0x000000ff;
b += rgb2 & 0x000000ff;
int average = ((r/2)<<16)+((g/2)<<8)+(b/2);
If you are somewhat mathematically inclined think about what behavior you actually look for, and try to put it in a formula (or rather 3 formulas, one for red, one for green, and one for blue)
It shouldn't be hard to convert the formula to java code.
You can put individual r, g and b values back into a single rgb value using
int rgb = (r<<16) | (g<<8) | b
Edit: notice that computers work with `red GREEN blue´, where yellow is a combination of green and blue, not the other way around. Conversion can be done, but I have not done it yet. Perhaps conversion between rgb and ryb color spaces may be of help.

Related

RGB colors in java Vs VB.net

I'm no native English speaker, so please excuses any translation errors.
I'm not really having a coding problem. It's more of a conceptual question.
I wrote two times the same piece of code translating an image into a list of RGB values. (1 combination of 3 values for each pixel).
I wrote the code first in VB.net using:
Dim bmp As New Bitmap(File)
For x As Integer = 0 To w - 1
For y As Integer = 0 To h - 1
Dim c As Color = bmp.GetPixel(x, y)
Dim Red as integer = c.R
Dim Green as integer = c.G
Dim Blue as integer = c.B
Next y
next x
Afterwards I wrote the following in Java:
BufferedImage image = ImageIO.read(new File(File))
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int pixel = image.getRGB(i,j);
int Red = ((pixel >> 16) & 0xff);
int Green = ((pixel >> 8) & 0xff);
int Blue = ((pixel) & 0xff);
}
}
My expectation would be to get the same values from both pieces of code, since they use the same image. I tried it on an image (270x320) which was a photograph (so a full spectrum of colors). To my surprise I saw there where small differences in the RGB values between the VB.net and Java codes.
If I compare the java(red)'s versus the VB.net(red)'s, the java(green)'s versus the VB.net(green)'s and the java(blue)'s versus the VB.net(blue)'s I compare 270x320x3 = 259.2k combinations. The differences between the integers gotten from the VB.net and from the Java code are as followed:
No difference: 250178 (96.5%)
One difference: 7426 (2.9%)
Two difference: 1582 (0.6%)
Three difference: 14 (0.0%)
Four or more diff.: 0 (0.0%)
Can anybody explain to me where this difference comes from? Has it to do with the way of reading the colors, the way of buffering the image, or with something like anti-aliasing?
Really curious what the reason is, thx in advance
As mentioned by others, the difference is caused by JPEG's lossy compression.
You should be testing these methods with a lossless format.

How to hide a char within a pixel

I want to know how to alter the least significant bit(s) of a pixel to hide a character. The picture must remain visually unchanged but I would like to hide a message within it.
To make your problem more specific, let's say you are using a limited 7 bit character set and a plain RGB image (no alpha channel). You can split the character bits into groups of 2-2-3. Since blue is the channel that we see the least variation in, you can hide the 3 bit group in the blue channel. The following encoding/decoding examples will use a Color object to represent the RGB triplet, but the code should work for any equivalent representation:
Encode
Given a pixel that has some original value in the image and a character that you want to encode, replace it with
Color px; // The initial color in the image
char ch; // The character to encode
...
// Store 2,2,3 bits of char in lowest bits of each pixel
// ... & ~0x3 clears the lowest two bits, the or assigns the replacement bits
Color newPx = new Color((px.getRed() & ~0x3) | ((ch & 0x60) >> 5),
(px.getGreen() & ~0x3) | ((ch & 0x18) >> 3),
(px.getBlue() & ~0x7) | (ch & 0x7));
Decode
Color px; // The image pixel with an encoded char
...
char ch = ((px.getRed() & 0x3) << 5) |
((px.getGreen() & 0x3) << 3) |
(px.getBlue() & 0x7);
You have to know what part of the image contains the modified pixels for this to work. Also, make sure that your image data is compressed losslessly if you compress it at all.
To do this, you're going to need to define some convention for mapping your bits. We know that in an ARGB color definition for a pixel, 8 bits are assigned to each the Alpha, Red, Green, and Blue values. As you do not want to map your character entirely over one color, I suspect you will want to break it up evenly over each of the 4 values. You may also not want to edit the alpha, but you can adjust the code I provide fairly easily to accommodate that. Here is how an int is structured. Keep in mind each of the values of the components are 8 bits (range 0-255)
int color = (alpha << 24) | (red << 16) | (green << 8) | blue
which is to say
int blue = color & 0xFF;
int green = (color >> 8) & 0xFF;
int red = (color >> 16) & 0xFF;
int alpha = (color >> 24) & 0xFF;
to hide the rightmost two bits of character c into a component (alpha, red, green, or blue) use
component = (component & 0xFC) | (c & 0x3);
repeat for each color and after each time shift c over two;
c >>= 2;
repackage as a color
int color = (alpha << 24) | (red << 16) | (green << 8) | blue;
to decode, break back into components
int blue = color & 0xFF;
int green = (color >> 8) & 0xFF;
int red = (color >> 16) & 0xFF;
int alpha = (color >> 24) & 0xFF;
then construct your character
char c = ((alpha & 0x3) << 6) | ((red & 0x3) << 4) | ((green & 0x3) << 2) | (blue & 0x3);
this last bit assumes that when you were hiding the bits in the components you went in the order I listed ( alpha, red, green, blue). I hope this helps you with your work, presumable steganography.
Happy coding! Leave a comment if you have any questions.

Java - Decimal color to RGB color

I have a decimal (not hexadecimal) color code and, using Java, I need to convert it to the three RGB colors.
So for example, 16777215 (pure white) needs to get converted to Red: 255 Green: 255 Blue: 255.
65280 (pure green) needs to get converted to Red: 0 Green 255: Blue: 0 Here is a converter for more examples.
Just doing some small calculations and playing with the calculator on the page linked above, I have determined:
Red equals 65536 (256^2)
(255x65536 = 16711680, aka pure red)
Green equals 256 (256^1)
(255x256 = 65280, aka pure green)
Blue equals 1 (256^0)
(255x1 = 255, aka pure blue)
I can tell it obviously has something to do with bytes, but I am missing that last little bit. I am not the best with the whole concept of bits/bytes/etc and how it interacts with Java, so it is likely fairly simple.
So, anyone know the best way of going about this? What would be the best way to convert a single numerical decimal color into the three separate RGB values using java?
You where telling right: RGB values are encoded as bytes in a int. R is byte 2, G is byte 1 and B is byte 0, summing up to a 24bit color depth. Depending on the endianess, this could be a possible representation.
00000000 00000000 00000000 00000000 <-- 32bit int
^ ^ ^
| | |
+--red here | +--green here
8bit | 8bit
|
+--blue here
8bit
You can extract RGB values with some bit shift and masking:
int red = (color >> 16) & 0xff;
int green = (color >> 8) & 0xff;
int blue = color & 0xff;
You could do
Color color = new Color(16777215);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
You can get the channels out by simple bitwise operations.
int r = (color >> 16) & 0xff;
int g = (color >> 8) & 0xff;
int b = color & 0xff;
From there, it should be easy to do whatever you want with the color information.
Decimal, hexadecimal: does not matter. Your computer uses binary representations internally.
You may have noticed that 0xFF00 == 65280.
Decimal and Hexadecimal are user representations.
I know I am a bit late, but...
int r = color / 65536;
int g = (color - r * 65536) / 256;
int b = color - r * 65536 - g * 256;
This is really doing the exact same thing as the binary shifts even though it doesn't use bitwise operators. This also only works when using valid RGB values (meaning each value is an integer between 0 and 255). For efficiency, however, I would use the binary shifts from the above answers.

Problems with "normal" blending of two images with alpha

I'm trying to do some blending of images in Java. After succcesfully doing multiply and screen blending, "normal" blending is causing me headaches.
I found on Wikipedia that the formula for blending two pixels with alpha is:
Co being resulting color, Ca color of top image, Cb color of bottom image and Aa -> alpha of top, Ab -> alpha of bottom.
I've tried to translate this to Java, and now have:
(t_X == Components from top image, b_X == Components from bottom image)
float t_a = (topPixels[i] >> 24) & 0xff, t_r = (topPixels[i] >> 16) & 0xff, t_g = (topPixels[i] >> 8) & 0xff, t_b = topPixels[i] & 0xff;
float b_a = (bottomPixels[i] >> 24) & 0xff, b_r = (bottomPixels[i] >> 16) & 0xff, b_g = (bottomPixels[i] >> 8) & 0xff, b_b = bottomPixels[i] & 0xff;
destPixels[i] =
(255 << 24 |
(int)((t_r * t_a) + ((b_r * b_a) * (((255 - t_a) / 255)))) << 16 |
(int)((t_g * t_a) + ((b_g * b_a) * (((255 - t_a) / 255)))) << 8 |
(int)((t_b * t_a) + ((b_b * b_a) * (((255 - t_a) / 255)))) << 0
);
But this seems to be wrong as the resulting image comes out wrong.
Any ideas what I'm missing, or is my lack of mathematical skill getting the best of me again when translating the formula to code?
You need to change a lot of this.
t_r, t_a etc must all be floats from 0 to 1. Do all your calculations in floating point, then multiply by 255 and then cast to int.
If t_a is not a floating point value, then calculations such as (255 - t_a) / 255 are done as integers too. You need to cast one of your inputs to a float beforehand, e.g ((255 - t_a) / 255f).

Get Bytes from an int to avoid bit shifting fun - Java (Median Filtering)

I'm trying to perform a Median filter on an image in Java but it's terribly slow. Firstly, if any of you know of a standalone implementation I could use it would be fantastic if you could let me know. I'm implementing on Android, trying to replicate a small part of the JAI.
In my method I take each pixel, extract the R,G & B values using
r = pixel >> 16 & 0xFF
Or similar, find the median for the kernel and finish with
pixel = a | r <<16 | g << 8 | b
Is there any way I can grab the bytes from an int in such a way that this would be faster?
Kind regards,
Gavin
EDIT: Full code to help diagnose my low performance upon request
For the actual source file please go here that's where my implementation of medianFilter can be found.
width and height variables are for the size of dest and are available as class member variables. The pixels are linearized into a one dimensional array.
private void medianFilterSquare(int[] source, int[] dest, int rWidth,
int rHeight, int radius) {
// Source has been reflected into a border of size radius
// This makes it radius * 2 pixels wider and taller than the dest
int r,g,b;
int destOffset, rOffset, kOffset;
// The first offset into the source to calculate a median for
// This corresponds to the first pixel in dest
int rFirst = radius + (rWidth*radius);
// We use a square kernel with the radius passed
int neighbours = (radius+radius+1)*(radius+radius+1);
int index;
// Arrays to accumulate the values for median calculation
int[] rs = new int[neighbours];
int[] gs = new int[neighbours];
int[] bs = new int[neighbours];
// Declaring outside the loop helps speed? I'm sure this is done for me
// by the compiler
int pixel;
// Iterate over the destination pixels
for(int x = 0; x < height; x++){
for(int y = 0; y < width; y++){
// Offset into destination
destOffset = x + (y * width);
// Offset into source with border size radius
rOffset = destOffset + rFirst + (y * (radius *2));
index = 0;
// Iterate over kernel
for(int xk = -radius; xk < radius ; xk ++){
for(int yk = -radius; yk < radius ; yk ++){
kOffset = rOffset + (xk + (rWidth*yk));
pixel = source[kOffset];
// Color.red is equivalent to (pixel>>16) & 0xFF
rs[index] = Color.red(pixel);
gs[index] = Color.green(pixel);
bs[index] = Color.blue(pixel);
index++;
}
}
r = medianFilter(rs);
g = medianFilter(gs);
b = medianFilter(bs);
dest[destOffset] = Color.rgb(r, g, b);
}
}
}
As others have said, it's possible that it's the bit in between which is causing the problem. One thing I would say (which may be obvious, but anyway) - don't just profile the application on a desktop VM and assume that the bottleneck will be in the same place. I wouldn't be at all surprised to find entirely different bottlenecks within Dalvik.
Is it possible for you to work with the values still shifted? For instance, if you were to just mask for different colours:
int r = pixel & 0xff0000;
int g = pixel & 0xff00;
int b = pixel & 0xff;
could you tweak your processing algorithm accordingly?
One final thought: I always find the precedence of shift operators confusing. I'd strongly recommend that from a readability point of view, you bracket them:
r = (pixel >> 16) & 0xFF;
pixel = a | (r <<16) | (g << 8) | b;
Irrelevant to performance, but if I were a maintainer I'd certainly appreciate it :)
The fastet way to get your r,g,b values should be
new byte[] {
(byte)(value >>> 24),
(byte)(value >>> 16),
(byte)(value >>> 8),
(byte)value
};
Concentrating on how to do the bit operations is a distraction. It only matters how you're doing these operations because you're needlessly processing the same pixel over and over.
You're calling median filter for every pixel three times, and you're getting multiple pixels around the pixel per pixel. Which means you're doing all that bit work for the same pixel multiple times. You have for loops nested four deep!
If your radius is 5, you're processing 121 pixels. Then you move down by one and process 121 pixels again, and you've already converted all but 11 of them! You do the same thing for every pixel down, then move to the right one pixel. For a radius of five, you're doing two orders of magnitude as many rgb conversions as you have to.
I'd suggest keeping your image in or converting your image to separate red, blue, and green arrays first.
If radius is large, you could keep the red, blue, and green sums as you move along, subtracting out the pixels from the top and adding in the pixels from the bottom as you crawl down the bitmap, but that would make the code a touch more complicated. Whether you add code to optimize further depends on your requirements.
Also, you have a bunch of little things that could be optimized. I'm not sure if the compiler is taking care of them or not. For instance, you could do some strength reduction. You don't need any of the multiplications you have in the lines that calculate neighbors, destOffset, rOffset, or kOffset. Addition is all you need for those if you refactor the code a bit.
You can occasionally get away with doing arithmetic on the red & blue components simultaneously in a single int:
int average(int rgb1, int rgb2)
{
int rb = (((rgb1 & 0xFF00FF) + (rgb2 & 0xFF00FF)) >> 1) & 0xFF00FF;
int g = (((rgb1 & 0xFF00) + (rgb2 & 0xFF00)) >> 1) & 0xFF00;
return (rb | g);
}
because the red and blue components are separated by 8 bits, they don't interfere with each other.
I've never seen a significant (more than 5-10%) speedup from this though.

Categories