I am looking to replace pixels in an image that are black to some degree (semi-black) to become fully black.
The method to do this is setRGB(int x, int y, int rgb). I know this. What I do not know is how to detect pixels that are semi-black.
I have tried (i is a BufferedImage):
final int rgb = i.getRGB(x, y);
if (rgb == -16777216) {
i.setRGB(x, y, -16777216);
}
To do this, but it only replaces the pixels that are pure black with pure black.
I have also tried dimming the image, but that does not work either.
Any ideas on how I test for generic blackness?
My goal: the image I am reading is thin text. I wish to make this bolder text by this.
The integer that you receive represents the combined red, green, blue and alpha values. Essentially, you need to:
break that integer down into its component red, green, blue values
from those values, assess the overall "brightness" of the pixel
As a rough implementation, you could do something like this:
int pixVal = ... getRGB() as you have
int red = (pixVal >>> 16);
int green = (pixVal >>> 8) & 0xff;
int blue = pixVal & 0xff;
int brightness = (red + green + blue) / 3;
if (brightness < 16) {
// pixel is black
}
Now, the value 16 is a rough value: ideally, you would tailor this to the particular image.
Purists might also whinge that the perceived "brightness" of a pixel isn't literally the mean of the red/green/blue pixels (because the human eye is not equally sensitive to these components). But that's the rough idea to work from.
Related
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);
}
I am trying to figure out how to make my game draw a certain tile in a specific spot using an image to represent each spot. So if a pixel of that image was the color red a specified picture(tile) would be draw in the game, and each pixel that was green stood for a different specified image. I have seen people who make games do this but I dont know how to do it and I dont know the name for it.
If you need more info I can try to explain what I want to do more. Could someone please help?
That may actually be slower in the long run. I would definitely recommend you use a byte array to represent the tiles, i.e. byte[width][height]. It will be faster, easier to manage and easier to extend to something like spriteData[width][height] if a single byte does not supply enough information anymore.
However, if you insist on using an image to store game data, you can use something like the following:
File file = new File("mygamedata.jpg");
BufferedImage image = ImageIO.read(file);
// Getting pixel color at position x, y (width, height)
int colour = image.getRGB(x ,y);
int red = (colour & 0x00ff0000) >> 16;
int green = (colour & 0x0000ff00) >> 8;
int blue = colour & 0x000000ff;
System.out.println("Red colour component = " + red);
System.out.println("Green colour component = " + green);
System.out.println("Blue colour component = " + blue);
Each component will be in the range (0...255) and you can use that to determine the correct tile, i.e.
Graphics2D gfx = (Graphics2D) offScreenImage.getImage();
if (red == 120 && green == 0 && blue == 0) {
gc.drawImage(tile[whichTileYouWantForRed], x, y, null); // where x and y is the pixel you read.
}
Alternatively, you can skip extracting the components altogether, and simply use colour, i.e.
if (colour == 0x00ff0000) {
gc.drawImage(tile[whichTileYouWantForRed], x, y, null); // where x and y is the pixel you read.
}
(Which will be slightly faster anyway and actually what you want.)
I have a colour #6A8F6509
I wish to remove the Alpha part of that colour and be left with only RGB components (i.e. #RRGGBB).
The resulting colour must look identical to the initial one without the transparency.
How do I go about this on Android's Java?
Update: The initial background is always white (#FFF)
int newColor = oldColor | 0xFF000000;
If you want to do it with the code you can try following code:
static int stripAlpha(int color){
return Color.rgb(Color.red(color), Color.green(color), Color.blue(color));
}
For each color:
C' = C(a/255) + 255(1-(a/255))
So for #6A8F6509:
R' = 143(106/255) + 255(1-(106/255) = (approx) 208
G' = 101(106/255) + 255(1-(106/255) = (approx) 191
B' = 9(106/255) + 255(1-(106/255) = (approx) 153
So your answer should be: #D0BF99, if my math is correct. This only applies to an all white background as well - for a non-white background, the second addend should have the appropriate corresponding color value of the background instead of 255.
-- EDIT --
Looking at the formula again, I'm not entirely sure whether the formula gets applied to each color or the entire color (a quick visual test should be able to tell you - I'm guessing per color). I should point out that this is the formula direct from the Alpha Compositing wiki page:
http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
try
#FF8F6509
the first two digits indicate the alpha value of any color.
Calculate the way a semi-transparent color will look when placed on top of another color.
Kotlin color extension:
#ColorInt
fun #receiver:ColorInt Int.removeAlpha(#ColorInt underlyingColor: Int): Int {
return ColorUtils.blendARGB(this, underlyingColor, alpha / 255F)
}
Usage:
Color.parseColor("#6A8F6509").removeAlpha(underlyingColor = Color.WHITE)
Jetpack Compose version is
Color(0x6A8F6509).compositeOver(Color.White)
I'll admit to not knowing Android's Java, but can't you just change the color from #6A8F6509 to #FF8F6509? The in most modern programming languages, color is typically encoded as ##AARRGGBB.
AA = Hex of the Alpha, ranging from 0 (hex 00), full transparent, to 255 (hex FF), no transparency.
RR = Hex of the red part of the color. Similar to above, 0 is no red, 255 is full red.
GG = Hex of green.
BB = Hex of blue.
-Edit-
Based on your update, you can do this to get the color:
For each of the red, green, and blue:
get the difference between the transparent color and the background color and multiply that by the alpha value. Divide that by 255 (hex FF, if you prefer). Finally, add that number to the transparent color's value.
In your case:
int transparentR = 0x8F;
int transparentG = 0x65;
int transparentB = 0x09;
int backgroundR = 0xFF;
int backgroundG = 0xFF;
int backgroundB = 0xFF;
int alpha = 0x6A;
int newR = transparentR + ( ( (backgroundR - transparentR) * alpha ) / 255 );
int newG = transparentR + ( ( (backgroundG - transparentG) * alpha ) / 255 );
int newB = transparentR + ( ( (backgroundB - transparentB) * alpha ) / 255 );
-Edit, again-
Ok, I've redone the formula based on LJ2's answer using Wikipedia's Alpha Blending function. and had a colleague confirm this with Paint.Net. This is the version where the background Color is fully opaque, and it's in C#, sorry:
int transparentColor2(int intFgColor, int intBgColor, int intAlpha)
{
double dAlpha = (Convert.ToDouble(intAlpha)/255.0);
double dFirst = Convert.ToDouble(intFgColor) * dAlpha;
double dSecond = Convert.ToDouble(intBgColor) * (1 - dAlpha);
return Convert.ToInt32(dFirst + dSecond);
}
do this for each R, G, and B value, and you should get the right answer. Incase Android's Java has different, double could be Double/Single/Float, and int could be Int32/Int16/Int64/Byte. I don't remember how to Convert between the two in Java, unfortunately.
How do I interpret the returned array from build-in method getPixels for a Bitmap?
Here is my code:
public void foo() {
int[] pixels;
Bitmap bitmapFoo = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.test2);
int height = bitmapFoo.getHeight();
int width = bitmapFoo.getWidth();
pixels = new int[height * width];
bitmapFoo.getPixels(pixels, 0, width, 1, 1, width - 1, height - 1);
}
The array "pixels" gets returned with values from -988,602,635 to 1,242,635,509 and that was just from a few colors on a simple PNG file I made. How can I interpret the numbers that get returned from this method?
Edit: I realize this single integer represents a color. I just don't understand how to interpret this single integer into the RBG and alpha values that make up the color.
Thanks.
PS. If your asking yourself, "what is he trying to do?" I am trying to figure out a way to dynamically modify the color of a bitmap.
You can also do the following to retrieve colors from
an int :
int mColor = 0xffffffff;
int alpha = Color.alpha(mColor);
int red = Color.red(mColor);
int green = Color.green(mColor);
int blue = Color.blue(mColor);
It returns an int for the Color class.
The Color class defines methods for
creating and converting color ints.
Colors are represented as packed ints,
made up of 4 bytes: alpha, red, green,
blue. The values are unpremultiplied,
meaning any transparency is stored
solely in the alpha component, and not
in the color components. The
components are stored as follows
(alpha << 24) | (red << 16) | (green
<< 8) | blue. Each component ranges
between 0..255 with 0 meaning no
contribution for that component, and
255 meaning 100% contribution. Thus
opaque-black would be 0xFF000000 (100%
opaque but no contributes from red,
gree, blue, and opaque-white would be
0xFFFFFFFF
For example, when you use the Paint object:
Paint pRed = new Paint();
pRed.setColor(Color.RED);
setColor expects an int. Color.RED is that int value for their pre-defined meaning of "red".
Even more:
int alpha=argb>>24;
int red=(argb & 0x00FF0000)>>16;
int green=(argb & 0x0000FF00)>>8;
int blue=(argb & 0x000000FF);
If you have your alpha, red, green and blue values, your in color is equal to (alpha << 24) + (red << 16) + (green << 8) + blue.
To retrieve your alpha, red, green and blue values from an int, say argb:
int alpha=argb>>24;
int red=(argb-alpha)>>16;
int green=(argb-(alpha+red))>>8;
int blue=(argb-(alpha+red+green));
Besides that, I think it should be
bitmapFoo.getPixels(pixels, 0, width, 0, 0, width, height);
The coordinates start from 0, right?
Is there an easy way to convert between color models in Java (RGB, HSV and Lab).
Assuming RGB color model:
How do I calculate black body spectrum color palette? I want to use it for a heatmap chart.
How about single-wavelength spectrum?
Edit: I found that the ColorSpace class can be used for conversions between RGB/CIE and many other color models.
Java has built-in RGB to HSB conversion. Whenever I need a quick pallet of colors in Java I just do this:
public Color[] generateColors(int n)
{
Color[] cols = new Color[n];
for(int i = 0; i < n; i++)
{
cols[i] = Color.getHSBColor((float) i / (float) n, 0.85f, 1.0f);
}
return cols;
}
It is a quick and dirty hack (I would tweak the 'magic' numbers for your app), but for my simple uses it generates a nice bright pleasant pallet.
Maybe I'm not understanding your question, but you can't really generate a true black-body spectrum from an RGB output device. Limited color gamut would be an issue, if nothing else. If all you want is something that visually resembles a black-body spectrum, that's probably a lot easier.
As an approximation, ramp from (R,G,B) (0,0,0) to (255,0,0), then to (255,255,0), then to (255,255,255). That'd give you the dull-red to orange, to yellow, to white transition.
If you want something more scientific, the Wikipedia article on black body radiation has some plots of color vs temperature. Once you figure out the CIE coordinates, you can translate those to RGB in your favorite color space.
Edit: found some other online references:
What color is the Sun?
What color is a blackbody?
You can build such a palette using the HSV color-model. That's easy once you have the HSV to RGB code in place and play around with the numbers for some minutes.
However, I think it's not worth it to add the code to your project just to generate a little palette.
It's much easier and less work to extract the palettes you need from a file and add them as a static array.
Photoshop let's you edit palettes and comes with a very nice black body palette as a preset.
You can simply save these as a .act file. The file itself is just a simple 256 color á 3 byte file (order is read, green, blue. 8 bits per channel).
You can generate this color spectrum https://i.stack.imgur.com/ktLmt.jpg
using the following code:
public void render(Screen screen) {
int green = 255;
int red = 0;
for (int i = 0; i <= 255 * 2; i++) {
int rate = i / 255;
screen.fillRect((x + (i * width)/6), y, width, height, new Color(red, green, 0));
red += 1 - rate;
green -= rate;
}
}
This is a nice way to make a HSL color square in AS3.
/**
* Generate a BitmapData HSL color square (n x n) of hue
* At a low n dimension you get cool blocky color palettes (e.g. try n=10)
*/
function generateColorSquare(n:uint, hue:uint):BitmapData
{
var bd:BitmapData = new BitmapData(n, n, false, 0xFFFFFF);
for (var i:uint=n*n; i > 0; i--)
{
bd.setPixel(i % n, Math.floor(i / n), HSBColor.convertHSBtoRGB(hue, i / (n*n), (1/n) * (i % n) ));
}
return bd;
}