Open zhangxinxu opened 4 years ago
不知道容差需不需要计算alpha
通道的……
let arrRGBA = [255, 255, 255, 255, 255, 255, 0, 255, 255, 250, 251, 246]
/**
* 将和白色在颜色容差以内的颜色变为透明
* @param {number[]} colors 颜色列表
* @param {number} delta 颜色容差
*/
function clearTolerance (colors, delta = 10) {
let colorNum = Math.floor(colors.length / 4)
for (let i = 0; i < colorNum; i++) {
let color = colors.slice(i * 4, (i + 1) * 4)
let deltaNum = 0 // 当前颜色容差值
color.forEach(channel => {
if (255 - channel > deltaNum) {
deltaNum = 255 - channel
}
})
if (deltaNum <= delta) {
colors.splice(i * 4 + 3, 1, 0)
}
}
}
clearTolerance(arrRGBA)
console.log(arrRGBA) // [ 255, 255, 255, 0, 255, 255, 0, 255, 255, 250, 251, 0 ]
搜到2种计算方式。
similar = Math.sqrt((r2 - r1) (r2 - r1) + (g2 - g1) (g2 - g1) + (b2 - b1) * (b2 - b1)) JS检测PNG图片是否有透明背景、抠图等相关处理
function fillColorHypot([...arr], [r, g, b, a], distance) { for (let i = arr.length - 4; i >= 0; i -= 4) { let [r1, b1, g1, a1] = arr.slice(i, i + 4); Math.hypot(r1 - r, g1 - g, b1 - b, a1 - a) <= distance && arr.splice(i, 4, 0, 0, 0, 0); } return arr; } let arrRGBA = [255, 255, 255, 255, 255, 255, 0, 255, 255, 250, 251, 246] let output = fillColorHypot(arrRGBA, [255, 255, 255, 255], 10); console.log(output);//[ 0, 0, 0, 0, 255, 255, 0, 255, 255, 250, 251, 246 ]
色差=两种颜色对应通道色阶差的正最大值-两种颜色对应通道色阶差的负最小值,如果没有正值或负值,则正最大值或负最大值以0计。实际上也就是某种颜色偏离取样色的最大范围(包括正向和负向)。 举个例子:10,40,100;80,20,200。 对应通道色阶差的正最大值=40-20=20; 对应通道色阶差的负最小值=100-200=-100; 那么,色差=20-(-100)=20+100=120 PS容差的概念及使用
function fillColorHypot([...arr], bgColor, distance) { for (let i = arr.length - 4; i >= 0; i -= 4) { let deltas = arr.slice(i, i + 4).map((v, i) => v - bgColor[i]); let [max, min] = [Math.max(...deltas), Math.min(...deltas)]; if (max < 0) max = 0; if (min > 0) min = 0; Math.abs(max-min) <= distance && arr.splice(i, 4, 0, 0, 0, 0); } return arr; } let arrRGBA = [255, 255, 255, 255, 255, 255, 0, 255, 255, 250, 251, 246] let output = fillColorHypot(arrRGBA, [255, 255, 255, 255], 10); console.log(output);//[ 0, 0, 0, 0, 255, 255, 0, 255, 0, 0, 0, 0 ]
容差是个什么概念?想了半天没想清楚,最后沿用了色差的概念。
var arrRGBA = [
255, 255, 255, 255,
255, 255, 0, 255,
255, 246, 128, 231,
154, 222, 167, 0,
1, 1, 1, 1,
255, 255, 251, 255,
254, 254, 254, 255
]
const baseColor = { r: 255, g: 255, b: 255, a: 255 }
converter(arrRGBA, baseColor)
console.log(arrRGBA)
function converter(arr, referColor, delta = 10) {
let index = 0
let count = Math.floor(arr.length / 4)
for (let i = 0; i < count; i++) {
let rgb = {
r: arr[0 + index],
g: arr[1 + index],
b: arr[2 + index]
}
let Lab = XYZToLAB(RGBToXYZ(rgb))
let referLab = XYZToLAB(RGBToXYZ(referColor))
let d = deltaE94(Lab, referLab)
if (d > delta) {
arr[3 + index] = 0
}
index = index + 4
}
}
function RGBToXYZ(rgb) {
const { r, g, b } = rgb
let var_R = r / 255
let var_G = g / 255
let var_B = b / 255
var_R > 0.04045
? (var_R = Math.pow((var_R + 0.055) / 1.055, 2.4))
: (var_R = var_R / 12.92)
var_G > 0.04045
? (var_R = Math.pow((var_G + 0.055) / 1.055, 2.4))
: (var_G = var_G / 12.92)
var_B > 0.04045
? (var_R = Math.pow((var_B + 0.055) / 1.055, 2.4))
: (var_B = var_B / 12.92)
var_R = var_R * 100
var_G = var_G * 100
var_B = var_B * 100
const xyz = {
x: var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805,
y: var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722,
z: var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505
}
return xyz
}
function XYZToLAB(xyz) {
const ReferenceX = 94.811
const ReferenceY = 100.0
const ReferenceZ = 107.304
let var_X = xyz.x / ReferenceX
let var_Y = xyz.y / ReferenceY
let var_Z = xyz.z / ReferenceZ
var_X > 0.008856
? (var_X = Math.pow(var_X, 1 / 3))
: (var_X = 7.787 * var_X + 16 / 116)
var_Y > 0.008856
? (var_X = Math.pow(var_Y, 1 / 3))
: (var_Y = 7.787 * var_Y + 16 / 116)
var_Z > 0.008856
? (var_X = Math.pow(var_Z, 1 / 3))
: (var_Z = 7.787 * var_Z + 16 / 116)
Lab = {
L: 116 * var_Y - 16,
a: 500 * (var_X - var_Y),
b: 200 * (var_Y - var_Z)
}
return Lab
}
function deltaE94(Lab, referLab) {
let xC1 = Math.sqrt(Math.pow(Lab.a, 2) + Math.pow(Lab.b, 2))
let xC2 = Math.sqrt(Math.pow(referLab.a, 2) + Math.pow(referLab.b, 2))
let xDL = referLab.L - Lab.L
let xDC = xC2 - xC1
let xDE = Math.sqrt(
(Lab.L - referLab.L) * (Lab.L - referLab.L) +
(Lab.a - referLab.a) * (Lab.a - referLab.a) +
(Lab.b - referLab.b) * (Lab.b - referLab.b)
)
let xDH = xDE * xDE - xDL * xDL - xDC * xDC
if (xDH > 0) {
xDH = Math.sqrt(xDH)
} else {
xDH = 0
}
xSC = 1 + 0.045 * xC1
xSH = 1 + 0.015 * xC1
xDC = xDC / xSC
xDH = xDH / xSH
const DeltaE94 = Math.sqrt(
Math.pow(xDL, 2) + Math.pow(xDC, 2) + Math.pow(xDH, 2)
)
return DeltaE94
}
看了楼上2位的答案之后 坐下来又想了想,转换为灰度值进行比较,是不是也算是容差呢?
const baseColor = { r: 255, g: 255, b: 255, a: 255 }
converter(arrRGBA, baseColor)
console.log(arrRGBA)
function converter(arr, referColor, delta = 10) {
let index = 0
let count = Math.floor(arr.length / 4)
for (let i = 0; i < count; i++) {
let rgb = {
r: arr[0 + index],
g: arr[1 + index],
b: arr[2 + index]
}
let d = Math.abs(RGBToGray(rgb) - RGBToGray(referColor))
if (d > delta) {
arr[3 + index] = 0
}
index = index + 4
}
}
function RGBToGray(rgb) {
return (rgb.r + rgb.g + rgb.b) / 3
}
let arrColor = [255,255,255,255,255,255,0,255,255,255,251,255,255,255,241,255,255,255,243,255,255,255,252,255,255,255,249,255]
for(var i=0;i<arrColor.length;i+=4){
let colors = arrColor.slice(i,i+4)
let isLimits = colors.some(item=>{
return 255-item>=10
})
if(!isLimits){
arrColor[i+3]=0
}
}
先将RGBA转成RGB,再计算容差
// 默认背景颜色为白色, 将RGBA转为RGB
function RGBA2RGB (rgba_color, background_color = [255, 255, 255]) {
var bgArray = background_color;
var rgbaArr = rgba_color;
var a = rgbaArr[3] / 255;
var r = bgArray[0] * (1 - a) + rgbaArr[0] * a;
var g = bgArray[1] * (1 - a) + rgbaArr[1] * a;
var b = bgArray[2] * (1 - a) + rgbaArr[2] * a;
return [r, g, b];
}
// 获取容差
function getTolerance (color1, color2) {
color1 = RGBA2RGB(color1)
color2 = RGBA2RGB(color2)
return Math.sqrt(
(color2[0] - color1[0]) * (color2[0] - color1[0]) +
(color2[1] - color1[1]) * (color2[1] - color1[1]) +
(color2[2] - color1[2]) * (color2[2] - color1[2]))
}
var arrRGBA = [255, 255, 250, 255, 255, 255, 0, 255, 245, 245, 245, 255];
for (let i = 0; i < arrRGBA.length / 4; i++) {
const color1 = [arrRGBA[i * 4], arrRGBA[i * 4 + 1], arrRGBA[i * 4 + 2], arrRGBA[i * 4 + 3]]
const tolerance = getTolerance(color1, [255, 255, 255, 255])
if (tolerance < 10) {
arrRGBA[i * 4 + 0] = 0
arrRGBA[i * 4 + 1] = 0
arrRGBA[i * 4 + 2] = 0
arrRGBA[i * 4 + 3] = 0
}
}
console.log(arrRGBA)
var arrRGBA = [255,255,255,1,253,251,254,1,251,252,255,1,255,131,210,1,098,111,231,1,255,222,243,1];
function setColor(color, delta) {
for (let i = 0 ;i < color.length; i = i+4) {
var num = (255-color[i]) + (255-color[i+1]) + (255-color[i+2])
if(num < delta) {
color[i+3] = 0
}
}
}
setColor(arrRGBA, 10)
console.log(arrRGBA)
请把和白色 (255,255,255,255)容差范围在10以内的颜色转变成透明
我没有理解到这个容差的逻辑。 目前的理解是 RGB 三个颜色与 255 的差值都小于10 为满足条件。
const arrRGBA = [
250,250,250,1,
255,250,255,1,
250,255,255,1,
255,255,250,1,
255,240,255,1,
240,255,255,1,
255,255,240,1
];
const getNewRGBA=function(arrColor=[]) {
let isNeedChangeCounter = 0;
return arrColor.map((item, key) => {
const isRGBColor = (key + 1) % 4 !== 0;
// 如果是 Alpha 位置,并且前面三个校验通过
if (!isRGBColor && isNeedChangeCounter === 3) {
// 重置计数器,并改变成透明
isNeedChangeCounter = 0;
return 0;
}
// 重置计数器
if (!isRGBColor) {
isNeedChangeCounter = 0;
}
// 如果当前色值都满足条件,计数器加1
if (isRGBColor && ((255 - item) < 10)) {
isNeedChangeCounter++;
}
return item;
});
}
console.log(getNewRGBA(arrRGBA));
let arrRGBA = [
255, 255, 255, 255,
255, 255, 0, 255,
245, 245, 245, 255,
230, 250, 240, 255,
]
function getResult(rgbaArr, delta = 10) {
if(rgbaArr.length % 4 !== 0){
return;
}
let result = [];
for (let i = 0; i < rgbaArr.length; i += 4) {
let [r, g, b, a] = [rgbaArr[i], rgbaArr[i + 1], rgbaArr[i + 2], rgbaArr[i + 3]];
if (r >= 255 - delta && g >= 255 - delta && b >= 255 - delta && a >= 255 - delta) {
result.push(r, g, b, 0);
} else {
result.push(r, g, b, a);
}
}
return result;
}
console.log(getResult(arrRGBA));
二楼老哥好样的,就应该首先应该先搞清楚容差是个什么东西再写的,一知半解猜出来可不好,附上答案
function ColorTolerance1(arr, bgc, distance) {
const [bgcr, bgcg, bgcb] = bgc
for(let i = 0; i < arr.length; i += 4) {
let [r, g, b, a] = arr.slice(i, i + 4)
let result = Math.sqrt((bgcr - r) ** 2 + (bgcg - g) ** 2 + (bgcb - b) ** 2)
if(result < distance) {
arr[i + 3] = 0
}
}
return arr
}
function ColorTolerance2(arr, bgc, distance) {
for(let i = 0; i < arr.length; i += 4) {
let cache = arr.slice(i, i + 4).map((item, idx) => item - bgc[idx])
let [ max, min ] = [ Math.max(...cache), Math.min(...cache) ]
max = max < 0 ? 0 : max
min = min > 0 ? 0 : min
let result = Math.abs(max - min)
if(result < distance) {
arr[i + 3] = 0
}
}
return arr
}
var arrRGBA = [255,255,255,255,255,255,0,255,255,255,255,255,255,255,0,255,255,255,255,255,255,255,0,255]
console.log(ColorTolerance1(arrRGBA, [255, 255, 255], 10))
console.log(ColorTolerance2(arrRGBA, [255, 255, 255], 10))
容差概念我是看的 @Seasonley 查找的概念😄
var arrRGBA = [
255, 255, 255, 255,
255, 255, 000, 255,
138, 222, 246, 255,
224, 224, 224, 255,
254, 254, 254, 254
];
cutout(arrRGBA)
console.log(arrRGBA)//[0,0,0,0,255,255,0,255,138,222,246,255,224,224,224,255,0,0,0,0]
function cutout(arr, tolerance = 10) {
var base = [255, 255, 255, 255]
for (var i = 0; i < arrRGBA.length; i += 4) {
var max = Math.max(sub(i), sub(i + 1), sub(i + 2), 0)
var min = Math.min(sub(i), sub(i + 1), sub(i + 2), 0)
if (max - min <= tolerance) {
transparent(i)
}
}
function sub(i) {
return arr[i] - base[i % 4]
}
function transparent(i) {
for (var j = 0; j < 4; j++) {
arr[i + j] = 0
}
}
}
题目 已知颜色数据: var arrRGBA = [255,255,255,255,255,255,0,255,…];
按照 RGBA 不断循环。
请把和白色 (255,255,255,255)容差范围在10以内的颜色转变成透明。
大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式(1积分)。
本期小测会以要点形式进行回复。