people of the internet!
I'm making a program that needs to try and find the closest RGB match of lots of pixels, using Jimp.
Say if you had a color that was slightly purple, I would want to change it to the purple that I have in my table, here:
var colors = [
[0,0,255,0],
[1,255,165,0],
[2,0,0,255],
[3,255,192,203],
[4,165,42,42],
[5,255,255,255],
[6,0,0,0],
[7,230,230,350],
[8,255,255,0],
[9,0,0,0],
]
(the first number in one of these arrays can be ignored, the rest are just R, G, and B)
So if I had a red like (255,7,1) I would like to match that to the red in my table, being (255,0,0)
I have tried something, but rather it was very dumb and didn't work, so I will spare you the details.
Can anybody help me? Thanks!
RGB is a 3-dimensional space. Consider a color as a point in 3d space, you should find most closest distance between two points by using 3d pythagoras.
const colors = [
[0,0,255,0],
[1,255,165,0],
[2,0,0,255],
[3,255,192,203],
[4,165,42,42],
[5,255,255,255],
[6,0,0,0],
[7,230,230,350],
[8,255,255,0],
[9,0,0,0],
]
function get_closest_color(colors, [r2, g2, b2]) {
const [[closest_color_id]] = (
colors
.map(([id, r1,g1,b1]) => (
[id, Math.sqrt((r2-r1)**2 + (g2-g1)**2 + (b2-b1)**2)]
))
.sort(([, d1], [, d2]) => d1 - d2)
);
return colors.find(([id]) => id == closest_color_id);
}
const closest_color = get_closest_color(colors, [230, 200,0]);
console.log(closest_color);
If I undestand your question correctly you can do something like this
const colors = [
[0,0,255,0],
[1,255,165,0],
[2,0,0,255],
[3,255,192,203],
[4,165,42,42],
[5,255,255,255],
[6,0,0,0],
[7,230,230,350],
[8,255,255,0],
[9,0,0,0],
]
const findClosestColor = (color, colors) =>
colors.reduce((res, c) => {
const distance = [1,2,3].reduce((sum, i) => sum + Math.abs(c[i] - color[i]), 0)
if(distance > res.distance){
return res;
}
return {
closest: c,
distance
}
}, {closest: null, distance: 9999} ).closest
console.log(findClosestColor([0, 255,7,1], [[1,0,0,200], [2,255,0,0], [3, 128,128,128]]))
Use the function(s) from here to find the color with the smallest E distance
Color difference/similarity% between two values with JS
Related
I have 2 array with same length
a=[1,2,3,4]
b=[5,6,7,8]
I want to find product between 2 arrays.
My exact question is : Is there any way to find product without using this way
(a[0]*b[0] + a[1]*b[1]+ a[2]*b[2]+ a[3]*b[3] )
Example:
a=[1,2,3,4] b=[5,6,7,8] a=[1,2,3,4] => sum of a =>10 b=[5,6,7,8] => sum of b=> 26 a+b = 10+26 => 36.
Here we can get sum without doing this (a[0]+b[0] + a[1]+b[1] + a[2]+b[2] +a[3]+b[3])
Like this i want to get product between two arrays
Something like this should work:
function multiplyArrays(firstArray, secondArray){
if (firstArray.length !== secondArray.length)
return;
let total = 0;
for (let i = 0; i < firstArray.length; i++)
total += firstArray[i] * secondArray[i];
return total;
}
You can't actually do multiplication without multiplication.
You can hide the * sign under some library, such as Lodash.
Here are both solutions. And lodash without * sign.
Live Demo:
const arr1 = [1,2,3];
const arr2 = [4,5,6];
const sumProductJS = arr1.reduce((r,v,i) => r+v*arr2[i], 0);
const sumProductLodash = _.zipWith(arr1, arr2, _.multiply).reduce(_.add);
console.log('Vanila:', sumProductJS);
console.log('Lodash:', sumProductLodash);
.as-console-wrapper { max-height: 100% !important; top: 0 }
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
Is there any way to find the product of two vectors without multiplying their component values?
Answer: No
Forumlae
The first formula for calculating the scalar product of two vectors in the same vector space sums the product of their vector components:
a.b = Σ aibi ... for i = 1 to n
This is the formula presented in the post as a base line. A JavaScript implementation example:
const dotProduct = (v1, v2) => {
let sigma;
if( v1.length == v2.length) {
sigma = v1.reduce( (sigma, Vi, i) => sigma += Vi * v2[i], 0);
}
return sigma;
}
The second formula for scalar product is
a.b = ║a║ ║b║ cosθ
meaning take the product of the length of the first vector, the length of the second, and the cosine of the angle between them.
The length of a vector is the square root of the sum of the squares of its components (Pythagorous in n dimensions). So each length calculation involves summing the square of a vector's components anyway: the dot product of a vector with itself, before taking the square root.
The formula for the cosine of the angle between two vectors uses the equivalence of the two formula:
cos(θ) = a.b / (║a║ ║b║)
requiring the dot product to be calculated first.
Hence computing the second formula value has no advantage over using the first formula directly, and may introduce computational inaccuracies because of additional steps taken to obtain square root values.
See also "Finding vector length for higher dimensions" and "cosine of angle between two vectors";
_If the question arises because of issues encountered with matrix multiplication you may wish to search using terms such as "large matrix multiplication by computer". While not familiar with the field the topic has certainly been investigated.
I am mapping through an array and want the output to be the following:
Array.from([1,2,3,4,5,6,7,8,9,10]).map((number, index) => console.log(index))
// 0-white 1-black 2-black 3-white 4-white 5-black 6-black 7-white 8-white 9-black
How can I do this using the index of Array.map?
For context, I am mapping through a list of items to display on a two column grid. I need to use JS, therefore the index needs to infer the correct color and can't use CSS in this scenario.
I can't for the life of me figure out the math logic to get the color correct.
One way to do this is to XOR the lowest 2 bits of index, that will give you a pattern of 0,1,1,0 which can then be translated into black and white:
result = Array.from([1,2,3,4,5,6,7,8,9,10])
.map((_, index) => (index & 1) ^ (index >> 1 & 1) ? 'black' : 'white')
console.log(result)
Some thing like
const pattern = ["white", "black", "black", "white"];
Array.from([1,2,3,4,5,6,7,8,9,10]).map((_, i) => {
console.log(i, pattern[i % pattern.length])
})
I have an svg image that I want to duplicate n number of times on the screen. Each time I want to change its position (x and y). For example, I would like to use one svg to create a 3x3 square of the duplicated svg.
How can this be achieved?
I figured it out and what I did was
const duplicateHtml = (element, quantity) => {
const html = new Array(quantity)
.fill('')
.map(() => {
return element.innerHTML;
})
// joing all the elements and returning a string
.join('');
return (element.innerHTML = html);
};
duplicateHtml(document.querySelector('.svg-images'),3);
I have a json response that returns an object with different vehicles. Each product has a hexcode value as an attribute that related to the vehicle color:
[ { "name":"Ford", "hexCode": "4B1A1F"},
{ "name":"BMW", "hexCode": "FFFFFF"},
{ "name":"Fiat", "hexCode":"000000"}
]
What i would like to do is be able to determine from the hexcodes, which one would be the darkest color, since not all manufacturers will use #000000 for black.
Is this possible either through some sort or regex or JS?
since not all manufacturers will use #000000 for black.
Once you define what darkest really means for you things will get easier. The fact your source data is inaccurate does not help at first glance, yet it still should be possible to use it for your needs. As all you really care here is the the luminance, not the color itself, it should be worth a shot to convert the value of provided color to gray-scale and then pick up the one closest to 0x00 as the darkest one.
Don't use regex if you are already using Javascript. Just assign the json to a variable and javascript will parse it, then convert each color to HSL and find the minimum by L value.
HSL is a color scheme that defines colors by Hue, Saturation, and Lightness, so you would get an objective measure of how 'dark' your color is.
You need to compare the luminance (Y) value for the RGB colors given in hex to find the lowest. The formula is;
Y = 0.299R + 0.587G + 0.114B
So you may do as follows;
function getY(hexValue){
return hexValue.match(/[0-9a-fA-F]{2}/g)
.map(h => parseInt("0x"+h))
.reduce((r,c,i) => (r[3] += r[i]*c, r),[0.299,0.587,0.114,0])[3];
}
var data = [ { "name":"Ford", "hexCode": "4B1A1F"},
{ "name":"BMW", "hexCode": "FFFFFF"},
{ "name":"Fiat", "hexCode":"000000"}
],
result = data.map(d => Object.assign({},d, {Y: getY(d.hexCode)}))
.reduce((p,c) => p.Y <= c.Y ? p : c);
console.log(result);
I'm wondering what the best way to approach this problem is...
I have an array of user defined colors that get pushed onto a stack as rgb values. I want to find a second color for each user-defined color. These second colors must be completely unique from the user-defined array, but can be completely random and do not need to have any visual relationship with any of the user colors.
Would generating random rgb values and testing it against the stack be fast, since it is highly unlikely that random numbers would find the same color on the first try. Or would simply starting at 255,254,253 and substracting 1 from each value, then testing it against the stack be better, also very unlikely and less operations. Or any other idea?
Here's some code to start off:
var colors = [];
function getRandUniqColor()
{
var r = getRGBString(),
g = getRGBString(),
b = getRGBString(),
rgb = r + g + b;
if ( colors.indexOf(rgb) == -1 )
{
colors.push(rgb);
return {
r: r,
g: g,
b: b
}
}
else
{
return getRandUniqColor()
}
}
function getRGBString()
{
var num = Math.floor( Math.random() * 255 ).toString();
while (num.length < 3)
{
num = '0' + num;
}
return num;
}
Just call getRandUniqColor(), and you'll get an object literal of RGB values.
Note: If there'll be a lot of colors involved, you should not use a recursive function.
...and here's the fiddle: http://jsfiddle.net/wV6Mw/
I would suggest generating random RGB values (combine three random numbers) and then create a function that measures the color difference between your generated random color and the ones in your data structure. If your generated color is too close to one you already have, generate a new one. You will have to decide how "different" you want the random color to be from what you already have, but a difference of only a few points in R, G an B won't be discernibly different so you should be looking for some minimum separation in at least one channel.
Searching for "calculate rgb color difference" gives you a bunch of references on how to calculate a meaningful difference between two color values. This link from that search has a specific equation and here's a previous question on SO about color differences.
You can also generate complementary colors from what you already have if you just want different colors and don't need/want truly random colors.
You could generate a random color like this in either data form or hex string form:
// generate r,g,b data structure like {r: 255, g: 30, b: 09}
function generateRandomColorData() {
function randomColorVal() {
return(Math.floor(Math.random() * 256));
}
return {r:randomColorVal(), g: randomeColorVal(), b: randomColorVal()};
}
// generate hex string color value like FF4409
function generateRandomColorHex() {
function randomColorVal() {
var val = Math.floor(Math.random() * 256).toString(16);
if (val.length < 2) {
val = "0" + val;
}
return(val);
}
return(randomColorVal() + randomColorVal() + randomColorVal());
}
As others have said, the easiest way would probably be to just create random colors and check for collisions.
If you are filling up the color space a lot (users selecting millions of colors) then another way would be to create a color cube of 256^3 bits, and let "1" represent the used colors. Then you could start from position 0 and use the first "0" as your generated color, the next "0" as the second and so on. The data structure would be just over 2 MB of ram.
But random is probably the way to go.