How to detect if shading or tinting exists on an image? - javascript

I want to count solid colors available on an image for silkscreen printing, and limit to maximum of 10 colors per design such how teespring did.
I've tried numbers of techniques to count unique colors using javascript (colorthief) and imagemagick. However the results are not suitable for this purpose because it also takes into account all colors exists on shading or tinting.
Example for image above, colorthief returning 9 unique colors. But if set the limit to 100, it returned as below.
var palette = colorThief.getPalette(image, 100);
So i would like to know how to detect the design if it has less than 10 colors or not?

I can't tell from your question whether you like or dislike what teespring or ColorThief does or what the problem is, or why you ask for 100 colours when you want 10, or if you think the 100 colours are wrong, or right... so I'll just try and suggest ways of getting the colours and you can see if you like them or not. As you are open to other tools, I'll choose ImageMagick which is available for OSX, Linux and Windows.
So, starting with your image, you can ask ImageMagick, at the command line, to choose its idea of the 10 best colours, and then to make them into a swatch of just those colours and resize it up from 10px by 1px to 500 pixels so you can see it:
convert motor.png -colors 10 -unique-colors -scale 500x swatch.png
Or, you could ImageMagick to quantise in the YIQ colorspace, like this:
convert motor.png -quantize YIQ -colors 10 -unique-colors -scale 500x swatch.png
Or, if you want the colour selection algorithm to ignore variations in saturation when choosing colours, you could go to HSL colorspace and fix the Saturation at say 50% leaving the Hues and Lightnesses unaffected and then go back to RGB colorspace and choose colours as above but now with fixed Saturation:
convert motor.png -colorspace hsl -channel G -fx 0.5 +channel -colorspace RGB -colors 10 -unique-colors -scale 500x swatch.png

Related

Get pixel ARGB color by Photoshop Javascript

I want to write some PS Javascript code to get a pixel's ARGB color value. A function which would look like:
function getPixelARGB(doc, x, y);
I searched for a while and found a method by Mike Hale in this site: a link
The answer proposed by Mike Hale works fine, the only problem is that it can't get the alpha value(opacity) of the selected pixel, which is what I want to know.
Anybody have any idea on how to get the ARGB value of a selected pixel by PS script? Thanks in advance.
Ok, if you want to support Photoshop CS2, I have something that will work, but is quite hacky - to say the least.
The basic idea is to get ImageMagick to do it on behalf of Photoshop - and that is probably quicker than anything accessing individual pixels in Photoshop's ExtendScript anyway. So, the ImageMagick command to see pixels in text/human-readable form is this:
convert out.png txt:
# ImageMagick pixel enumeration: 256,256,255,srgba
0,1: (255,0,0,0.996078) #FF0000FE srgba(255,0,0,0.996078)
1,1: (255,0,0,0.996078) #FF0000FE srgba(255,0,0,0.996078)
2,1: (255,0,0,0.996078) #FF0000FE srgba(255,0,0,0.996078)
3,1: (255,0,0,0.996078) #FF0000FE srgba(255,0,0,0.996078)
You can see the transparency is FE or 0.996078 for this row.
So, if you want 1 pixel, say the one at 128,128, you would do this:
convert out.png -crop 1x1+128+128 -depth 8 txt:
# ImageMagick pixel enumeration: 1,1,255,srgba
0,0: (255,0,0,0.498039) #FF00007F srgba(255,0,0,0.498039)
and it has an opacity of 7F or 0.498039.
So, to realise what you want to do, your putative function getPixelARGB(doc, x, y) will have to do the following steps:
1. duplicate document `doc`
2. save duplicate as `PNG` (to preserve transparency) on somewhere like `/tmp`
3. invoke ImageMagick - see below
4. read result - see below
So, how do you invoke ImageMagick and read its output? You can use this:
app.system("convert /tmp/tmp.png -crop 1x1+128+128 -depth 8 txt: > /tmp/result.txt")
var w = new File("/tmp/result.txt");
w.open('r');
var str = "";
while(!w.eof)
str += w.readln();
w.close();
alert(str);
I can tell you briefly how to do it, but I don't have time to write the code this very minute - maybe over the next couple of days if you are lucky. So, hopefully your Extendscript skills are reasonable.... :-)
The issue is that the Color Sampler doesn't pass back transparency, just RGB values. So, the technique will be to force the transparency into the RGB values so you can use them. Here are the steps:
Duplicate the document - because we are going to be a bit destructive
Select all & copy merged (Cmd-A,Shift+Cmd+C)
Flatten (Layer->Flatten Image)
Fill with black (Edit->Fill->Black)
Paste (the layer we copy merged)
Lock transparent pixels on pasted layer (top of layers palette - first checkerboard icon on left)
Fill with white (Edit->Fill->White)
Add a color sampler at the pixel position you want
Read sampler's red value (or green, or blue - they are all the same) and that is the transparency
Most of the Extendscript for the above is fairly simple, the only two harder bits are setting the transparent pixels to locked, which you do like this:
docLay[l].transparentPixelsLocked = true;
and the samplers - where you might be well advised to clear all existing samplers (as only max 4 are permitted)
var sampler = doc.colorSamplers.add([64, 64]);
I have made a little animated GIF here that shows you the process. I start with a red->transparent gradient image. Note at the end when I have the color dropper tool running, you will see the greyscale values in the Color Info window change as I move up and down the image with the mouse, these reflect the original transparency.
I might as well go for a third method while I am thinking about this... :-)
If you create a gradient image which is solid red to transparent, like this:
then load it into Photoshop and select the Color Sampler tol and move it around, you will see in the Info window, that Photoshop reports it as pure red wherever you move the sampler - basically ignoring the transparency.
Now, create a new layer and fill it with black, and then in the Layers window, drag the new black layer below the transparent one - leave the blending mode as normal and opacity and fill at 100%. It will look like this:
Now move the Color Sampler around and you will see the Red RGB value is directly inversely proportional to the opacity - and now the GOOD NEWS - you can get the red channel with Extendscript! So, the technique would be to get the red pixel's RGB value, then put the layer behind and get the red pixel's value again and the difference between the two is proportional to the opacity.
I guess if you filled with white instead of black, the red channel would be directly proportional to the opacity.

How to filter out hue errors in images

I've been running a hue difference algorithm on some images. Hue difference generally means difference in color, and only color, regardless of contrast:
But, I've noticed a nasty effect with some images:
As you can see, cyan and yellow appeared out of nowhere. To be totally sure, I have run a test where the hue in the image was set to 1 and lightness to 0.5:
The broken colors really seem to be near black/white pixels on almost every image. I use this rgb/hsl algorighm.
During every operation on images before, colorless pixels (lightness = 1 or 0 OR saturation = 0) were treated differently (their undefined color did not affect the calculation).
My questions about the problem:
Are the colors real, or is it a bug in RGB/HSL
Either way, is it possible to filtrate them out?

Select options based on percentage

I need an efficient method to select options based on percentages.
For example, assume we have four colors: black, blue, red and white.
Now, I'm going to create an array filled with colors, except, I need to select them based on the following percentages:
Black - 80% chance of selection
Blue - 70% chance of selection
Red - 30% chance of selection
White - 5% chance of selection
I thought of assigning a range between 1 and 100 to each color and then generating a random number between. This however means the % of all colors has to add up to 100%, which, might not be avoidable really.
Code not necessary but would love some algorithms that can be implemented via JavaScript to accomplish this.
EDIT:
Based on Patrice Levesque's answer, I created this test. While I haven't verified the statistics of it, it visually represents what I'm after. As usual, I over-thought the problem. Other answers are more than welcome.
You just need to normalize your values; get the total “percentage” (in your instance, 80 + 70 + 30 + 5 → 185) and pick a number between 1 and that total; in your case, 1-80 would be black, 81-150 would be blue, 151-180 would be red and 181-185 white.

Scale for web colors

I'm using google map to display historical events and would like to color the markers based on the decade an event occurs. The event are between 1800 and 2000 (so about 20 different decades). I'd like to scale scale from yellow to orange to red. Any ideas?
tldr = want to scale from yellow to red in 20 steps in web rgb
EDIT: dudes - this is what i'm doing after reading this: How to get hex color value rather than RGB value?
http://jsfiddle.net/p6ek6/3/
Use HSL instead, since you can simply adjust the first parameter H for the color. Something around 0 to 50 should give you a nice red-yellow gradient.
Red example: hsl(0, 100, 50%);
Yellow example: hsl(50, 100, 50%);
This is 100% subjective. There is no scale.
Your best bet is to copy color schemes from other professionally produced maps or find color scheme inspiration elsewhere.
I suggest using National Geographic or just go out in nature to get inspired about color schemes.
In your situation, try to think about all the colors you see during fall with leaves falling off trees.
I hope you don't have to print this on a color printer, or this gets even more complicated.

Is there a way to compare 2 colors in JS, like 'If Color A is darker than #202020'

The background color for one of my pages is set pulled from the background color the users set as their twitter background color. I have a page that has a rounded box with a black border. The border doesnt look good if the background color is dark, so i'd like to remove the border of the background is darker than an arbitrary hex color.
The way I was thinking about doing this was using a regex to pull the 3 RGB values and summing them, and comparing that to my reference color. Is there a better, way to accomplish this?
You could write a function that converts between RGB and HSL or HSV, and use the lightness or brightness value.
Wikipedia has the math for HSV -> RGB conversion, but not the other way.
http://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
You could also probably pull some JS from this page.
http://www.csgnetwork.com/csgcolorsel4.html
You may also need take in account perceptual brightness of colors (i.e. bright-blue #0000FF looks much darker than bright-red #FF0000 which in turn is much-much darker than #00FF00).
So I'd split the color value into separate bytes and then multiply each by some coefficient:
function getPerceptualBrightness(color) {
var r = parseInt(color.substring(0,2),16);
var g = parseInt(color.substring(2,4),16);
var b = parseInt(color.substring(4,6),16);
return r*2 + g*3 + b;
}
var green_b = getPerceptualBrightness('00A000');
var blue_b = getPerceptualBrightness('0000FF');
if (green_b > blue_b)
{
alert("Green is brighter though it's numerical value is smaller");
}
This may be less precise than converting to HSL but the latter feels like an overkill for the task...
If the rounded corners are images, this is better treated as a photoshop problem. Save for web/png-24/transparency dither.
If I understand your problem correctly it's not just an issue of light and dark but of hue too. Those corners are dithered to a background that doesn't match these alternate ones. By that I mean the rounded edges are slowly faded from the border to the background color so the jagged pixel edges don't appear to be as jarring.
An arbitrary light/dark solution where you average the three and compare would only work well with fairly extreme lights and darks I would imagine but with a png transparency dither they'll soft-blend into any background automatically. There are workarounds for IE 6 if you have to support it.
You may be able to use the luminance of the color. jPaq offers this function. Still, I am not sure that this is what you are looking for. Here is Wikipedia's definition of luminance: http://en.wikipedia.org/wiki/Luminance.

Categories

Resources