zhangxinxu / quiz

小测答题收集区
536 stars 43 forks source link

JS基础测试44期 #64

Open zhangxinxu opened 4 years ago

zhangxinxu commented 4 years ago

题目 已知颜色数据: var arrRGBA = [255,255,255,255,255,255,0,255,…];

按照 RGBA 不断循环。

请把和白色 (255,255,255,255)容差范围在10以内的颜色转变成透明。

大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式(1积分)。

```js
// 你的JS代码写在这里
 ```

本期小测会以要点形式进行回复。

xxf1996 commented 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 ]
Seasonley commented 4 years ago

搜到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 ]

LuckyRabbitFeet commented 4 years ago

容差是个什么概念?想了半天没想清楚,最后沿用了色差的概念。

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
}
sghweb commented 4 years ago
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
  }
}
livetune commented 4 years ago

先将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)
sunyongming commented 4 years ago
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)
ziven27 commented 4 years ago

请把和白色 (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));
guqianfeng commented 4 years ago
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));
zer0fire commented 4 years ago

二楼老哥好样的,就应该首先应该先搞清楚容差是个什么东西再写的,一知半解猜出来可不好,附上答案

  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)) 
liyongleihf2006 commented 4 years ago

容差概念我是看的 @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
    }
  }
}