I'm trying to generate a color that could highlight an item as "selected" based on the color of the current object. I've tried increasing some of the HSB values, but I can't come up with a generalized formula. Particularly, I have problems when working with white (a brighter white doesn't look much different than a regular white). There's no requirement that says I need to make it brighter, so some sort of "inverse" color would work well too. Are there any standard algorithms or techniques for doing something like this (I'm guessing yes, but I couldn't find any -- I'm not sure if there's a name for this)?
thanks,
Jeff
Maybe the negatif effect:
pseudo:
int red = originalColor.red
int green = originalColor.green
int blue = originalColor.blue
int newRed = 255 - red
int newGreen = 255 - green
int newBlue = 255 - blue
Color negativeColor = new Color(newRed, newGreen, newBlue)
Or adding a blue color-effect:
int red = originalColor.red
int green = originalColor.green
int blue = originalColor.blue
int newRed = 255 - red
int newGreen = 255 - green
int newBlue = 255 - blue + 100
if newBlue > 255 {
newBlue = 255
newRed = newRed - 50
newGreen = newGreen - 50
if newRed < 0 {newRed = 0}
if newGreen < 0 {newGreen = 0}
}
Color negativeColor = new Color(newRed, newGreen, newBlue)
If you're using HSB, try shifting the hue by half the maximum value either up or down, that should give you the "opposite" color (also called the complementary color). However, this doesn't do you any good for the grey spectrum, which has no hue and will thus look identical.
If you do this with both hue and brightness, you will get a kind of "negative", which works in all cases. A true negative would have you "flip" the brightness value around the mid-point, but that doesn't work for medium-gray, which would still be medium-gray.
It not always possible to make a color brighter (what do you do with white?), so shifting both hue and brightness by half is the most reliable if you're looking for contrast.
One technique you can use is to swap the item's foreground (text) color and its background color. If the text and background colors of your item already have a pleasing contrast, the selected item should continue to look good.
(source: wordpress.com)
That is the technique used on this site (Stack Overflow) when you mouse-over the tags in your post. They turn from DarkBlue-on-LightBlue to LightBlue-on-DarkBlue. Try it to see the effect.
You might find the tools at http://www.easyrgb.com/ give you some ideas.
Related
I have made a very basic algorithm which extracts only the red / green / blue pixels of the image and displays them. However, it works well on some images and produces unexpected results in some. Like when I want to keep only green , it also keeps turquoise.
Turquoise is a shade of green but it is not what I want to display. I only want things that are 'visually' green.
Here is a sample output that shows what has gone wrong:
The algorithm picked up the turquoiose color of the flower pot on which the dog sits. The original image is here.
My algorithm is below (for the green one.) All the algorithms are akin to each other.
void keepGreen() {
for (int i = 0; // iterate over the pixels of the image
i < img.pixels.length;
i++) {
float inputRed = red(img.pixels[i]); // extract red
float inputGreen = green(img.pixels[i]); // extract green
float inputBlue = blue(img.pixels[i]); // extract blue
int pixel = -1;
float outputRed = -1;
float outputGreen = -1;
float outputBlue = -1;
if(inputRed <= inputGreen*0.9 && inputBlue <= inputGreen*0.9){ // check if the pixel is visually green
outputRed = inputRed; // yes, let it stay
outputGreen = inputGreen;
outputBlue = inputBlue;
}else{ // no, make it gray
int mostProminent =(int) max(inputRed, inputGreen, inputBlue);
int leastProminent =(int) min(inputRed, inputGreen, inputBlue);
int avg = (int) ((mostProminent + leastProminent) / 2);
outputRed = avg;
outputGreen = avg;
outputBlue = avg;
pixel = color(avg, avg, avg);
}
img.pixels[i] = color(outputRed, outputGreen, outputBlue); // set the pixel to the new value
}
img.updatePixels(); // update the image
image(img, WIDTH/2, HEIGHT/2, calculatedWidth, calculatedHeight); // display
}
How can I avoid those errors ?
Experiment with raising the red and blue thresholds individually, i.e inputGreen * 0.8 instead of inputGreen * 0.9 Use a tool like Instant Eyedropper or Pixel Picker to verify the RGB values in those colors that you don't want, and use that as feedback to set the thresholds for elimination of the colors that you don't want.
You might also want to consider the luminance level in your calculations. The pixels being picked up on the flower pot are darker than the other pixels on the flower pot.
Just because Blue is less than Green doesn't mean the pixel doesn't look green. For example, turquoise might be red=50, blue=200, green=150. Perhaps you need to (also) gray out pixels that have substantial green in their own right, regardless of red/blue.
I am new to Matlab and to Image Processing as well. I am working on separating background and foreground in images like this
I have hundreds of images like this, found here. By trial and error I found out a threshold (in RGB space): the red layer is always less than 150 and the green and blue layers are greater than 150 where the background is.
so if my RGB image is I and my r,g and b layers are
redMatrix = I(:,:,1);
greenMatrix = I(:,:,2);
blueMatrix = I(:,:,3);
by finding coordinates where in red, green and blue the values are greater or less than 150 I can get the coordinates of the background like
[r1 c1] = find(redMatrix < 150);
[r2 c2] = find(greenMatrix > 150);
[r3 c3] = find(blueMatrix > 150);
now I get coordinates of thousands of pixels in r1,c1,r2,c2,r3 and c3.
My questions:
How to find common values, like the coordinates of the pixels where red is less than 150 and green and blue are greater than 150?
I have to iterate every coordinate of r1 and c1 and check if they occur in r2 c2 and r3 c3 to check it is a common point. but that would be very expensive.
Can this be achieved without a loop ?
If somehow I came up with common points like [commonR commonC] and commonR and commonC are both of order 5000 X 1, so to access this background pixel of Image I, I have to access first commonR then commonC and then access image I like
I(commonR(i,1),commonC(i,1))
that is expensive too. So again my question is can this be done without loop.
Any help would be appreciated.
I got solution with #Science_Fiction answer's
Just elaborating his/her answer
I used
mask = I(:,:,1) < 150 & I(:,:,2) > 150 & I(:,:,3) > 150;
No loop is needed. You could do it like this:
I = imread('image.jpg');
redMatrix = I(:,:,1);
greenMatrix = I(:,:,2);
blueMatrix = I(:,:,3);
J(:,:,1) = redMatrix < 150;
J(:,:,2) = greenMatrix > 150;
J(:,:,3) = blueMatrix > 150;
J = 255 * uint8(J);
imshow(J);
A greyscale image would also suffice to separate the background.
K = ((redMatrix < 150) + (greenMatrix > 150) + (blueMatrix > 150))/3;
imshow(K);
EDIT
I had another look, also using the other images you linked to.
Given the variance in background colors, I thought you would get better results deriving a threshold value from the image histogram instead of hardcoding it.
Occasionally, this algorithm is a little to rigorous, e.g. erasing part of the clothes together with the background. But I think over 90% of the images are separated pretty well, which is more robust than what you could hope to achieve with a fixed threshold.
close all;
path = 'C:\path\to\CUHK_training_cropped_photos\photos';
files = dir(path);
bins = 16;
for f = 3:numel(files)
fprintf('%i/%i\n', f, numel(files));
file = files(f);
if isempty(strfind(file.name, 'jpg'))
continue
end
I = imread([path filesep file.name]);
% Take the histogram of the blue channel
B = I(:,:,3);
h = imhist(B, bins);
h2 = h(bins/2:end);
% Find the most common bin in the *upper half*
% of the histogram
m = bins/2 + find(h2 == max(h2));
% Set the threshold value somewhat below
% the value corresponding to that bin
thr = m/bins - .25;
BW = im2bw(B, thr);
% Pad with ones to ensure background connectivity
BW = padarray(BW, [1 1], 1);
% Find connected regions in BW image
CC = bwconncomp(BW);
L = labelmatrix(CC);
% Crop back again
L = L(2:end-1,2:end-1);
% Set the largest region in the orignal image to white
for c = 1:3
channel = I(:,:,c);
channel(L==1) = 255;
I(:,:,c) = channel;
end
% Show the results with a pause every 16 images
subplot(4,4,mod(f-3,16)+1);
imshow(I);
title(sprintf('Img %i, thr %.3f', f, thr));
if mod(f-3,16)+1 == 16
pause
clf
end
end
pause
close all;
Results:
Your approach seems basic but decent. Since for this particular image the background is composed of mainly blue so you be crude and do:
mask = img(:,:,3) > 150;
This will set those pixels which evaluate to true for > 150 to 0 and false to 1. You will have a black and white image though.
imshow(mask);
To add colour back
mask3d(:,:,1) = mask;
mask3d(:,:,2) = mask;
mask3d(:,:,3) = mask;
img(mask3d) = 255;
imshow(img);
Should give you the colour image of face hopefully, with a pure white background. All this requires some trial and error.
I need to determine the amount/quality of color in an image in order to compare it with other images and recommend a user (owner of the image) maybe he needs to print it in black and white and not in color.
So far I'm analyzing the image and extracting some data of it:
The number of different colors I find in the image
The percentage of color in the whole page (color pixels / total pixels)
For further analysis I may need other characteristic of these images. Do you know what else is important (or I'm missing here) in image analysis?
After some time I found a missing characteristic (very important) which helped me a lot with the analysis of the images. I don't know if there is a name for that but I called it the average color of the image:
When I was looping over all the pixels of the image and counting each color I also retrieved the information of the RGB values and summarized all the Reds, Greens and Blues of all the pixels. Just to come up with this average color which, again, saved my life when I wanted to compare some kind of images.
The code is something like this:
File f = new File("image.jpg");
BufferedImage im = ImageIO.read(f);
int tot = 0;
int red = 0;
int blue= 0;
int green = 0;
int w = im.getWidth();
int h = im.getHeight();
// Going over all the pixels
for (int i=0;i<w;i++){
for (int j=0;j<h;j++){
int pix = im.getRGB(i, j); //
if (!sameARGB(pix)) { // Compares the RGB values
tot+=1;
red+=pix.getRed();
green+=pix.getGreen();
blue+=pix.getBlue();
}
}
}
And you should get the results like this:
// Percentage of color on the image
double per = (double)tot/(h*w);
// Average color <-------------
Color c = new Color((double)red/tot,(double)green/tot,(double)blue/tot);
How do you use DwmGetColorizationColor?
The documentation says it returns two values:
a 32-bit 0xAARRGGBB containing the color used for glass composition
a boolean parameter that is true "if the color is an opaque blend" (whatever that means)
Here's a color that i like, a nice puke green:
You can notice the color is greeny, and the translucent title bar (against a white background) shows the snot color very clearly:
i try to get the color from Windows:
DwmGetColorizationColor(dwCcolorization, bIsOpaqueBlend);
And i get
dwColorization: 0x0D0A0F04
bIsOpaqueBlend: false
According to the documentation this value is of the format AARRGGBB, and so contains:
AA: 0x0D (13)
RR: 0x0A (10)
GG: 0x0F (15)
BB: 0x04 (4)
This supposedly means that the color is (10, 15, 4), with an opacity of ~5.1%.
But if you actually look at this RGB value, it's nowhere near my desired snot green. Here is
(10, 15, 4) with zero opacity (the original color), and
(10,15,4) with 5% opacity against a white/checkerboard background:
Rather than being Lime green, DwmGetColorizationColor returns an almost fully transparent black.
So the question is: How to get glass color in Windows Vista/7?
i tried using DwmGetColorizationColor, but that doesn't work very well.
A person with same problem, but a nicer shiny picture to attract you squirrels:
So, it boils down to –
DwmGetColorizationColor is completely
unusable for applications attempting
to apply the current color onto an
opaque surface.
i love this guy's screenshots much better than mine. Using his screenshots as a template, i made up a few more sparklies:
For the last two screenshots, the alpha blended chip is a true partially transparent PNG, blending to your browser's background. Cool! (i'm such a geek)
Edit 2: Had to arrange them in rainbow color. (i'm such a geek)
Edit 3: Well now i of course have to add Yellow.
Undocumented/Unsupported/Fragile Workarounds
There is an undocumented export from DwmApi.dll at entry point 137, which we'll call DwmGetColorizationParameters:
HRESULT GetColorizationParameters_Undocumented(out DWMCOLORIZATIONPARAMS params);
struct DWMCOLORIZATIONPARAMS
{
public UInt32 ColorizationColor;
public UInt32 ColorizationAfterglow;
public UInt32 ColorizationColorBalance;
public UInt32 ColorizationAfterglowBalance;
public UInt32 ColorizationBlurBalance;
public UInt32 ColorizationGlassReflectionIntensity;
public UInt32 ColorizationOpaqueBlend;
}
We're interested in the first parameter: ColorizationColor.
We can also read the value out of the registry:
HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM
ColorizationColor: REG_DWORD = 0x6614A600
So you pick your poison of creating appcompat issues. You can
rely on an undocumented API (which is bad, bad, bad, and can go away at any time)
use an undocumented registry key (which is also bad, and can go away at any time)
See also
Is there a list of valid parameter combinations for GetThemeColor / Visual Styles API
How does Windows change Aero Glass color?
DWM - Colorization Color Handling Using DWMGetColorizationColor
Retrieving Aero Glass base color for opaque surface rendering
i've been wanting to ask this question for over a year now. i always knew that it's impossible to answer, and that the only way to get anyone to actually pay attention is to have colorful screenshots; developers are attracted to shiny things. But on the downside it means i had to put all kinds of work into making the lures.
Colorization color != the base color chosen. It's misleading, I know.
But I'm confused. The image you borrowed was from my post entitled "Retrieving Aero Glass base color for opaque surface rendering". Is this not what you want to do? I also indicated in the post the registry location in which all the color information is stored (HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM) for retrieval purposes.
Edited 8/26
DwmGetColorizationColor (dwmapi.dll) returns the "colorization color", which is a blend of various colors (incl. your selected base color) and shader logic to achieve the overall glass effect.
All the color information you need/want can be found in the registry key noted above. The base color, the colors used in blending, and the resulting colorization color are all there.
(The key above is present on Windows Vista and above.)
I believe I have solved the Aero Color. The color given by ColorizationColor is in fact AARRGGBB but it is not being used in the way that you think at all. And in order to solve the final color, you also need to get the Color Intensity as shown here: http://www.codeproject.com/Articles/610909/Changing-Windows-Aero-Color
First step is to parse AARRGGBB. Then take the resulting RGB and convert to HSV. The pure Hue plus Saturation at full brightness is the base color. Now overlay Value as a grayscale at Alpha over top of pure Hue and Saturation to get the Aero color. Then overlay that color over the frame color: rgb(235, 235, 235) at Intensity to get the final Composite Aero color result.
Lastly, I've also provided an example of how to extract a useable toolbar color that matches the Aero frame color, but will always work with black text and other basic Aero features. This is accomplished by limiting Intensity to 35%.
Here is the math:
function dwmToRgb() {
// Input Values
var colorizationColor = "a84f1b1b"; // dwmcolor.clrColor = ColorizationColor
var colorizationColorBalance = 60; // dwmcolor.nIntensity = ColorizationColorBalance
var F = 235; // Frame base grayscale color when Transparency is disabled
// Parse the input values
var A = Math.round(parseInt(colorizationColor.substr(0,2),16)/2.55)/100;
var R1 = parseInt(colorizationColor.substr(2,2), 16);
var G1 = parseInt(colorizationColor.substr(4,2), 16);
var B1 = parseInt(colorizationColor.substr(6,2), 16);
var I = colorizationColorBalance/100;
// Solve for HSV Value and pure Hue+Sat
var V = Math.max(R1, G1, B1);
var R2 = R1*255/V;
var G2 = G1*255/V;
var B2 = B1*255/V;
// Aero Frame Pure Hue: Overlay Value # Alpha over pure Hue+Sat
var R3 = Math.round(V+(R2-V)-((R2-V)*A));
var G3 = Math.round(V+(G2-V)-((G2-V)*A));
var B3 = Math.round(V+(B2-V)-((B2-V)*A));
var hexRGB3 = "#" + ((1 << 24) + (R3 << 16) + (G3 << 8) + B3).toString(16).slice(1);
// Aero Frame Composite Color: Overlay RGB3 # Intensity over Frame base color
var R4 = Math.round(R3+(F-R3)-((F-R3)*I));
var G4 = Math.round(G3+(F-G3)-((F-G3)*I));
var B4 = Math.round(B3+(F-B3)-((F-B3)*I));
var hexRGB4 = "#" + ((1 << 24) + (R4 << 16) + (G4 << 8) + B4).toString(16).slice(1);
// Aero Toolbar Color: Overlay RGB3 # max 35% Intensity over Frame base color
if (I > 0.35) { I5 = 0.35;} else { I5 = I;}
var R5 = Math.round(R3+(F-R3)-((F-R3)*I5));
var G5 = Math.round(G3+(F-G3)-((F-G3)*I5));
var B5 = Math.round(B3+(F-B3)-((F-B3)*I5));
var hexRGB5 = "#" + ((1 << 24) + (R5 << 16) + (G5 << 8) + B5).toString(16).slice(1);
How does A0F040 look to you?
OP Edit: This is how 0xA0F040 looks to me:
This should be a simple question, but I haven't been able to find a way to make it work.
Essentially, I have a silly localhost page that I use in my webdevelopment. When I am surfing between our development server and my local version of the C# code (redirected from the dev url via host file) I have been known to sometimes forget what 'dev.foo.com' points at - local or server.
So I created a page which will run locally as my default web page's default page, so I can easily identify my localhost from the server.
This page does a lot of things randomly (including generating a character's starting stats for D&D), including setting a random background color. I do this by generating 3 random numbers between 0 and 255, and setting them as the RGB value for the body background color in CSS.
Given the 3 ints R, G, and B, how do I determine R2, G2, and B2 such that the second color will have high contrast with the first? I like having the page have random background colors (it keeps me from getting used to the look of the landing page) but I also like to be able to read the text.
You need a difference in brightness for text to be readable, as color vision itself has too low resolution.
So as an algorithm I'd suggest the following:
Pick a random background color.
Then decide whether it is a light or a dark color. For example you could check whether the average of the three primary colors is greater or equal 128.
For a light color use black text, for a dark one white text.
Update: Here is an example image I made while playing with the split_evenly example of the Rust crate plotters. It shows the colors in Palette99:
"Contrast" is a loaded word. If you just care about being able to read the text, then one easy way is to work in a luminance-based color space like HSL, and pick foreground and background colors with big differences in luminance.
The conversion between HSL and RGB is well-known--see Wikipedia for the details.
If you're talking about actual color contrast, it's not nearly as cut-and-dried (there are a lot of perceptual factors that, as far as I know, haven't been reduced to a single colors space), but I suspect you don't need that level of sophistication.
Check out this PHP solution: Calculating Color Contrast with PHP by Andreas Gohr. It can be ported to any language of course.
He also has a very nice demonstration of his contrast analyzer where you can find some minimal contrast levels to work with.
You can use method GetBrightness() on Color class. It returns a float value from 0.0 (brightness of black) to 1.0 (white).
A simple solution would be:
var color1 = new Color.FromArgb(r1, g1, b1);
var brightness = color1.GetBrightness();
var color2 = brightness > 0.5 ? Color.Black : Color.White;
I did something like this in a Palm OS application. This is what I came up with. It doesn't give you "high contrast" colors but it gives you a background color that's different enough from the text color to be quite readable:
// Black background is a special case. It's fairly likely to occur and
// the default color shift we do isn't very noticeable with very dark colors.
if (backColor.r < 0x20 && backColor.g < 0x20 && backColor.b < 0x20)
{
textColor.r = backColor.r + 0x20;
textColor.g = backColor.g + 0x20;
textColor.b = backColor.b + 0x20;
}
else
{
textColor.r = backColor.r + ((backColor.r < 128) ? 0x10 : -0x10);
textColor.g = backColor.g + ((backColor.g < 128) ? 0x10 : -0x10);
textColor.b = backColor.b + ((backColor.b < 128) ? 0x10 : -0x10);
}
You might not need to do black as a special case for your purposes - Palm's color handling is a bit funky (16-bit color).
These answers are more or less suggesting to use one of the two or three color choices based on whether the color is bright or dark.
I use a bit different approach and it worked elegantly in my case. Here is the implementation.
int color = your_color;
contrastColor = Color.rgb(255-(color >> 16)&0xFF, 255-(color >> 8)&0xFF, 255- color&0xFF);
It's simple and wonderful.
If you flip all the bits, you will get the "opposite" color which would be pretty good contrast.
I believe it's the ~ operator in C#:
R2 = ~R1;
G2 = ~G1;
B2 = ~B1;
Thanks to #starblue !
Here is C# code that I use
public static string GetContrastBlackOrWhiteColorAsHtmlColorCode(Color c)
{
System.Drawing.Color color = System.Drawing.ColorTranslator.FromHtml("transparent");
try
{
if (c.R >= 128 && c.G >= 128 && c.B >= 128)
{
return System.Drawing.ColorTranslator.ToHtml(Color.Black);
}
else
{
return System.Drawing.ColorTranslator.ToHtml(Color.White);
}
}
catch (Exception)
{
}
return System.Drawing.ColorTranslator.ToHtml(color);
}
For best contrast use this code
function lumdiff($R1,$G1,$B1,$R2,$G2,$B2){
$L1 = 0.2126 * pow($R1/255, 2.2) +
0.7152 * pow($G1/255, 2.2) +
0.0722 * pow($B1/255, 2.2);
$L2 = 0.2126 * pow($R2/255, 2.2) +
0.7152 * pow($G2/255, 2.2) +
0.0722 * pow($B2/255, 2.2);
if($L1 > $L2){
return ($L1+0.05) / ($L2+0.05);
}else{
return ($L2+0.05) / ($L1+0.05);
}
}
function get_the_contrast($c1, $c2) {
return (lumdiff(hexdec(substr($c1,0,2)),
hexdec(substr($c1,2,2)),hexdec(substr($c1,4,2)),
hexdec(substr($c2,0,2)),hexdec(substr($c2,2,2)),
hexdec(substr($c2,4,2))));
}
The method above ( AVG(red,green,blue) > 128 ) is not realy good.
private Color GetContrastingColor(Color color)
{
int r = color.R > 0 ? 256 - color.R : 255;
int g = color.G > 0 ? 256 - color.G : 255;
int b = color.B > 0 ? 256 - color.B : 255;
return System.Drawing.Color.FromArgb(r, g, b);
}