I am trying to get variants of a hex colour, given its percentage of variant. For example my hex colour is #FFFFFF , where i need to find five variants 95% is #F2F2F2 , 85% is #D9D9D9 , 75% is #BFBFBF , 65% is #A6A6A6 , 50% is #808080. How can i calculate this programatically? How can i increase or decrease the brightness of a color code depending on some percent?
Code snippet tried:
void brighten(int color, float fraction) {
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
r += (int) (fraction * (255 - r));
g += (int) (fraction * (255 - g));
b += (int) (fraction * (255 - b));
if (r < 0) {
r = 0;
}
if (r > 255) {
r = 255;
}
if (g < 0) {
g = 0;
}
if (g > 255) {
g = 255;
}
if (b < 0) {
b = 0;
}
if (b > 255) {
b = 255;
}
String resultColor = "#" + Integer.toHexString(Color.rgb((int) r, (int) g, (int) b) & 0x00ffffff);
}
This works for colors to some extend as it only darkens with given percentage. But it doesn't works to all color uniformally (example : #000000).
Use the below method to solve your problem.
// Function Calling
brighten(0x00FFFFFF, 65); //Para 1 : color code // Para 2 : percentage of color code that what you want.
void brighten(int color, int persontage) {
double r = Color.red(color);
double g = Color.green(color);
double b = Color.blue(color);
r = Math.ceil((r*persontage) / 100);
g = Math.ceil((g*persontage) / 100);
b = Math.ceil((b*persontage) / 100);
String resultColor = "#" + Integer.toHexString(Color.rgb((int) r, (int) g, (int) b) & 0x00ffffff);
Log.i(TAG, "brighten: resultColor : " + resultColor);
}
Related
Im trying to render a video frame using android NDK.
Im using this sample of google Native-Codec NDK sample code and modified it so I can manually display each video frame (non-tunneled).
so I added this code to get the output buffer which is in YUV.
ANativeWindow_setBuffersGeometry(mWindow, bufferWidth, bufferHeight,
WINDOW_FORMAT_RGBA_8888
uint8_t *decodedBuff = AMediaCodec_getOutputBuffer(d->codec, status, &bufSize);
auto format = AMediaCodec_getOutputFormat(d->codec);
LOGV("VOUT: format %s", AMediaFormat_toString(format));
AMediaFormat *myFormat = format;
int32_t w,h;
AMediaFormat_getInt32(myFormat, AMEDIAFORMAT_KEY_HEIGHT, &h);
AMediaFormat_getInt32(myFormat, AMEDIAFORMAT_KEY_WIDTH, &w);
err = ANativeWindow_lock(mWindow, &buffer, nullptr);
and these codes to convert the YUV to RGB and display it using native window.
if (err == 0) {
LOGV("ANativeWindow_lock()");
int width =w;
int height=h;
int const frameSize = width * height;
int *line = reinterpret_cast<int *>(buffer.bits);
for (int y= 0; y < height; y++) {
for (int x = 0; x < width; x++) {
/*accessing YUV420SP elements*/
int indexY = y * width + x;
int indexU = (size + (y / 2) * (width ) + (x / 2) *2);
int indexV = (int) (size + (y / 2) * (width) + (x / 2) * 2 + 1);
/*todo; this conversion to int and then later back to int really isn't required.
There's room for better work here.*/
int Y = 0xFF & decodedBuff[indexY];
int U = 0xFF & decodedBuff[indexU];
int V = 0xFF & decodedBuff[indexV];
/*constants picked up from http://www.fourcc.org/fccyvrgb.php*/
int R = (int) (Y + 1.402f * (V - 128));
int G = (int) (Y - 0.344f * (U - 128) - 0.714f * (V - 128));
int B = (int) (Y + 1.772f * (U - 128));
/*clamping values*/
R = R < 0 ? 0 : R;
G = G < 0 ? 0 : G;
B = B < 0 ? 0 : B;
R = R > 255 ? 255 : R;
G = G > 255 ? 255 : G;
B = B > 255 ? 255 : B;
line[buffer.stride * y + x] = 0xff000000 + (B << 16) + (G << 8) + R;
}
}
ANativeWindow_unlockAndPost(mWindow);
Finally I was able to display a video on my device. Now my problem is the video does not scale to fit the surface view :(
Your thoughts are very much appreciated.
I'm trying to set a custom value for the White Balance & temperature color in my camera app. I'm using camera2 API and I'm trying different ways to set this value. I found a method from a excel file to get the right RGB Temperature matrix [Red,Green,Blue] from the White Balance Value between 100 and 100.000.
I attached this method to a Seekbar and its working fine, my problem appear when I try to focus something white, then it becomes pink. Any kind of light looks like a pink torch in the screen.
I'm setting the values in this way:
mPreviewRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
RggbChannelVector rggb = getTemperatureVector(seekBackSelectedTemperature);
mPreviewRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_GAINS, myRggbChannelVector);
In other way, my method to get the matrix is this one:
public static RggbChannelVector getTemperatureVector (int WhiteBalanceValue){
float InsertTemperature = WhiteBalanceValue;
float temperature = InsertTemperature / 100;
float red;
float green;
float blue;
//Calculate red
if (temperature <= 66)
red = 255;
else {
red = temperature - 60;
red = (float) (329.698727446 * (Math.pow((double) red, -0.1332047592)));
if (red < 0)
red = 0;
if (red > 255)
red = 255;
}
//Calculate green
if (temperature <= 66) {
green = temperature;
green = (float) (99.4708025861 * Math.log(green) - 161.1195681661);
if (green < 0)
green = 0;
if (green > 255)
green = 255;
} else
green = temperature - 60;
green = (float) (288.1221695283 * (Math.pow((double) red, -0.0755148492)));
if (green < 0)
green = 0;
if (green > 255)
green = 255;
//calculate blue
if (temperature >= 66)
blue = 255;
else if (temperature <= 19)
blue = 0;
else {
blue = temperature - 10;
blue = (float) (138.5177312231 * Math.log(blue) - 305.0447927307);
if (blue < 0)
blue = 0;
if (blue > 255)
blue = 255;
}
RggbChannelVector finalTemperatureValue = new RggbChannelVector(red/255,(green/255)/2,(green/255)/2,blue/255);
return finalTemperatureValue;
}
Maybe it's because the method of my CaptureRequest is not correct, but I don't find a way to fix it.
It worked after change the template to Still_capture or Manual Template and use the next method:
captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF);
// adjust color correction using seekbar's params
captureBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
captureBuilder.set(CaptureRequest.COLOR_CORRECTION_GAINS, CameraCapabilities.colorTemperature(Integer.parseInt(awbMode)));
public static RggbChannelVector colorTemperature(int whiteBalance) {
float temperature = whiteBalance / 100;
float red;
float green;
float blue;
//Calculate red
if (temperature <= 66)
red = 255;
else {
red = temperature - 60;
red = (float) (329.698727446 * (Math.pow((double) red, -0.1332047592)));
if (red < 0)
red = 0;
if (red > 255)
red = 255;
}
//Calculate green
if (temperature <= 66) {
green = temperature;
green = (float) (99.4708025861 * Math.log(green) - 161.1195681661);
if (green < 0)
green = 0;
if (green > 255)
green = 255;
} else {
green = temperature - 60;
green = (float) (288.1221695283 * (Math.pow((double) green, -0.0755148492)));
if (green < 0)
green = 0;
if (green > 255)
green = 255;
}
//calculate blue
if (temperature >= 66)
blue = 255;
else if (temperature <= 19)
blue = 0;
else {
blue = temperature - 10;
blue = (float) (138.5177312231 * Math.log(blue) - 305.0447927307);
if (blue < 0)
blue = 0;
if (blue > 255)
blue = 255;
}
Log.v(TAG, "red=" + red + ", green=" + green + ", blue=" + blue);
return new RggbChannelVector((red / 255) * 2, (green / 255), (green / 255), (blue / 255) * 2);
}
Another possible and more simpler solution; factor must be between 0 and 100:
private static RggbChannelVector computeTemperature(final int factor)
{
return new RggbChannelVector(0.635f + (0.0208333f * factor), 1.0f, 1.0f, 3.7420394f + (-0.0287829f * factor));
}
I am trying to create a wallpaper and am using the HSV conversion in the "android.graphics.color" class. I was very surprised when i realized that a conversion of a created HSV color with a specified hue (0..360) to a rgb color (an integer) and a back conversion to a HSV color will not result in the same hue. This is my code:
int c = Color.HSVToColor(new float[] { 100f, 1, 1 });
float[] f = new float[3];
Color.colorToHSV(c, f);
alert(f[0]);
I am starting with a hue of 100 degree and the result is 99.76471.
I wonder why there is that (in my opinion) relatively big inaccuracy.
But a much bigger problem is, that when you put that value in the code again, the new result decreases again.
int c = Color.HSVToColor(new float[] { 99.76471f, 1, 1 });
float[] f = new float[3];
Color.colorToHSV(c, f);
alert(f[0]);
If I start with 99.76471, I get 99.52941. This is kind of a problem for me.
I did something similar in java with the "java.awt.Color" class where I did not have those problems. Unfortunately, I cannot use this class in android.
This is an interesting problem. It's not avoidable with the android class because of low float precision. However, I found a similar solution written in javascript here.
If it's important enough for you to want to define your own method/class to do the conversions, here is a Java conversion which should give you better precision:
#Size(3)
/** Does the same as {#link android.graphics.Color#colorToHSV(int, float[])} */
public double[] colorToHSV(#ColorInt int color) {
//this line copied vertabim
return rgbToHsv((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF);
}
#Size(3)
public double[] rgbToHsv(double r, double g, double b) {
final double max = Math.max(r, Math.max(g, b));
final double min = Math.min(r, Math.min(g, b));
final double diff = max - min;
final double h;
final double s = ((max == 0d)? 0d : diff / max);
final double v = max / 255d;
if (min == max) {
h = 0d;
} else if (r == max) {
double tempH = (g - b) + diff * (g < b ? 6: 0);
tempH /= 6 * diff;
h = tempH;
} else if (g == max) {
double tempH = (b - r) + diff * 2;
tempH /= 6 * diff;
h = tempH;
} else {
double tempH = (r - g) + diff * 4;
tempH /= 6 * diff;
h = tempH;
}
return new double[] { h, s, v };
}
I have to confess ignorance here - I've done quick conversion and not had time to test properly. There might be a more optimal solution, but this should get you started at least.
Don't miss the mirrored procedure from the source link. Next is the translation to the Kotlin lang.
fun hsvToRGB(hsv: DoubleArray): Int {
val i = floor(hsv[0] * 6).toInt()
val f = hsv[0] * 6 - i
val p = hsv[2] * (1 - hsv[1])
val q = hsv[2] * (1 - f * hsv[1])
val t = hsv[2] * (1 - (1 - f) * hsv[1])
val r: Double
val g: Double
val b: Double
when (i % 6) {
0 -> {r = hsv[2]; g = t; b = p}
1 -> {r = q; g = hsv[2]; b = p}
2 -> {r = p; g = hsv[2]; b = t}
3 -> {r = p; g = q; b = hsv[2]}
4 -> {r = t; g = p; b = hsv[2]}
5 -> {r = hsv[2]; g = p; b = q}
else -> {r = 0.0; g = 0.0; b = 0.0}
}
return Color.rgb((r * 255).roundToInt(), (g * 255).roundToInt(), (b * 255).roundToInt())
}
fun rgbToHSV(color: Int, target: DoubleArray) {
val r = Color.red(color).toDouble()
val g = Color.green(color).toDouble()
val b = Color.blue(color).toDouble()
val max = kotlin.math.max(r, kotlin.math.max(g, b))
val min = kotlin.math.min(r, kotlin.math.min(g, b))
val diff = max - min
target[1] = if (max == 0.0) {0.0} else {diff / max}
target[2] = max / 255.0
target[0] = if (min == max) {
0.0
} else if (r == max) {
var tempH = (g - b) + diff * if (g < b) { 6} else {0}
tempH /= 6 * diff
tempH
} else if (g == max) {
var tempH = (b - r) + diff * 2
tempH /= 6 * diff
tempH
} else {
var tempH = (r - g) + diff * 4
tempH /= 6 * diff
tempH
}
}
In my app i want to edit images like brightness, contrast, etc. I got some tutorial and i am trying this to change contrast
public static Bitmap createContrast(Bitmap src, double value) {
// image size
int width = src.getWidth();
int height = src.getHeight();
// create output bitmap
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
// color information
int A, R, G, B;
int pixel;
// get contrast value
double contrast = Math.pow((100 + value) / 100, 2);
// scan through all pixels
for(int x = 0; x < width; ++x) {
for(int y = 0; y < height; ++y) {
// get pixel color
pixel = src.getPixel(x, y);
A = Color.alpha(pixel);
// apply filter contrast for every channel R, G, B
R = Color.red(pixel);
R = (int)(((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if(R < 0) { R = 0; }
else if(R > 255) { R = 255; }
G = Color.red(pixel);
G = (int)(((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if(G < 0) { G = 0; }
else if(G > 255) { G = 255; }
B = Color.red(pixel);
B = (int)(((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
if(B < 0) { B = 0; }
else if(B > 255) { B = 255; }
// set new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
// return final image
return bmOut;
calling it as :
ImageView image = (ImageView)(findViewById(R.id.image));
//image.setImageBitmap(createContrast(bitmap));
But i dont see any offect happening for the image. Can you please help where i am going wrong.
I saw the effectFactory from APi 14 . IS there something similar / any tutorial that can be used for older versions for image processing
There are three basic problems with this approach. The first two are coding issues. First, you are always calling Color.red, and there is no Color.green and Color.blue to be found in your code. The second issue is that this calculation is too repetitive. You assume the colors are in the range [0, 255], so it is much faster to create a array of 256 positions with the contrast calculated for each i in [0, 255].
The third issue is more problematic. Why did you consider this algorithm to improve contrast ? The results are meaningless for RGB, you might get something better in a different color system. Here are the results you should expect, with your parameter value at 0, 10, 20, and 30:
And here is a sample Python code to perform the operation:
import sys
from PIL import Image
img = Image.open(sys.argv[1])
width, height = img.size
cvalue = float(sys.argv[2]) # Your parameter "value".
contrast = ((100 + cvalue) / 100) ** 2
def apply_contrast(c):
c = (((c / 255.) - 0.5) * contrast + 0.5) * 255.0
return min(255, max(0, int(c)))
# Build the lookup table.
ltu = []
for i in range(256):
ltu.append(apply_contrast(i))
# The following "point" method applies a function to each
# value in the image. It considers the image as a flat sequence
# of values.
img = img.point(lambda x: ltu[x])
img.save(sys.argv[3])
I am not too familiar with bit shifting so I have the following question.
I use the function below (found elsewhere) to decode from YUV to an RGB int array.
Now I want to adjust red or green or blue values to create some custom filter effect.
I need to retrieve the R value, G value, and B value. Each value ranging from 0-255.
After that I need to restore it in the rgb array at the specified index.
So I need to retrieve each color from rgb[i] and than be able to store it again in rgb[i]
void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143)
r = 262143;
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
if (b < 0)
b = 0;
else if (b > 262143)
b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
}
Basically color transformation is multiplication of color vector by matrix, and android offers support for it. Look:
http://developer.android.com/reference/android/graphics/ColorMatrix.html
It offers several convenience methods to create desired transformations. ( see sample on end)
How to change colors of a Drawable in Android?
For your convenience the Color-class contains many methods for getting and setting specific parts of a 32bit color integer, such as
Color.red(color)
returns the red part of the int color.
Or
Color.argb(alpha, red, green, blue)
to create an integer from the specified values (range 0-255).
The documentation for the different methods also specifies how to implement the bit-shifting yourself, if that is what you want to do.