ctx.globalCompositeOperation =
당신은 합성 방법을 사용하여 "곱"동적 범위를 잃지 않도록, 아래 RGBA 포맷 fillRect 할() 및 색상을 정의하는 의해 시도 대답은 frnt입니다. 0.6의 알파는 원래 마스크의 대비를 크게 줄입니다.
블렌딩 옵션이 많지만 이미지를 흰색으로 보이게하고 싶지 않고 어둠을 추가하고 싶다면 블렌드 모드 "곱하기"를 사용하십시오.이 방법을 사용하면 최상의 명암비를 얻을 수 있습니다.
ctx.fillStyle = ??? // the background colour you want
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); // fill canvas with colour. This is now the destination
// Destination pixels get multiplied by source pixels
// nC = dC * (sC/255); (seperate for each channel RGB. no effect on alpha)
// where nC is the new colour, dC is destination colour and, sC is source colour;
// White pixels make no change, all others reduce the the colour
ctx.globalCompositeOperation = "multiply";
// draw the image over the top.
ctx.drawImage(img, 0, 0, canvas.width, cvtx.canvas.height);
ctx.globalCompositeOperation = "source-over"; // reset to default
최고 품질
이 더 좋은 방법이 있지만이 픽셀 데이터를 가져오고이 곱하기 전에 각 픽셀에 광자의 수를 일을 포함한다. 이렇게하면 원래 마스크에 더 가까운 일치를 얻을 수 있습니다. 수식은 nC =Math.sqrt(dC * dC * (sC * sC/(255*255)));
입니다. 여기서 nC
은 새 색이고 dC
은 대상 색이며 sC
은 원본 색입니다. 알파를 무시하고 각 채널 RGB에 적용합니다.
// r,g,b are the background colour
// img is a loaded image to convert
var r = ?, g = ?, b = ?;
// create canvas and context for image
var c = document.createElement("canvas");
c.width = img.width;
c.height = img.height;
var ctx = c.getContext("2d");
// draw image onto the canvas
ctx.drawImage(img, 0,0);
// get the pixel data
var data = ctx.getImageData(0,0,c.width,c.height);
var d = data.data;
// Convert background colour to photon count and normalise
r = r * r/(255 * 255);
g = g * g/(255 * 255);
b = b * b/(255 * 255);
var i = 0, len = d.length;;
// for each pixel do the multiply using photon counts
while(i < len){
d[i] = Math.sqrt(d[i] * d[i++] * r);
d[i] = Math.sqrt(d[i] * d[i++] * g);
d[i] = Math.sqrt(d[i] * d[i++] * b);
i ++;
}
// put the image data back onto the canvas.
ctx.putImageData(data,0,0);
알파 합성물을 통해.
알파 합성물을 사용해도 곱셈 효과가 아닐 수 있습니다. 간단한 방법과 광자 계산 방법 두 가지가 있습니다. 두 가지 방법은 배경색이 알파 값이 255라고 가정하고 그 값으로 만을 사용한다고 가정하십시오.
간단한 방법으로 픽셀의 알파를 얻습니다. 알파 채널을 설정하고 캔버스 소스 오버 (기본) 혼합 기능을 사용한 경우 어떻게 수행됩니까?광자 카운트 색상 모델을 사용하는 이유 (가 고품질의 전문 믹싱을 수행하는 방법)
// assume you have got the pixel data etc.. see above snipets
var amount = ?; // the mixing amount
var i = 0, len = d.length;;
// for each pixel do the alpha blend
while(i < len){
var rr = d[i]; // get source channels
var gg = d[i + 1];
var bb = d[i + 2];
var alpha = (rr + gg + bb)/(3 * 255); // calculate alpha by finding the mean
// alpha is inverted but also need to clamp alpha as floating point may give a value too high so clamp and invert
alpha = Math.min(1, 1 - alpha);
alpha *= amount; // set the mix amount
var aInv = 1 - alpha; // invert again
// each channel is the sum of background and image colour time their respective mix amounts
d[i++] = aInv * r + alpha * rr;
d[i++] = aInv * g + alpha * gg;
d[i++] = aInv * b + alpha * bb;
d[i++] = 255; // in this case alpha is always 255
}
// put the image data back onto the canvas.
ctx.putImageData(data,0,0);
그리고 올바른 방법
// assume you have got the pixel data etc.. see above snipets
var amount = ?; // the mixing amount
// Convert background colour to photon count and normalise
r = r * r/(255 * 255);
g = g * g/(255 * 255);
b = b * b/(255 * 255);
var i = 0, len = d.length;;
// for each pixel do the alpha blend using photon counts
while(i < len){
var rr = d[i]; // get source channels
var gg = d[i + 1];
var bb = d[i + 2];
rr *= rr;
gg *= gg;
bb *= bb;
var alpha = (rr * + gg + bb)/(3 * 255 * 255); // calculate alpha by finding the mean in photon space
// alpha is inverted but also need to clamp alpha as floating point may give a value too high so clamp and invert
alpha = Math.min(1, 1 - alpha);
alpha *= amount; // set the mix amount
var aInv = 1 - alpha; // invert again
// each channel is the sum of background and image colour time their respective mix amounts
d[i++] = Math.sqrt(aInv * r + alpha * rr);
d[i++] = Math.sqrt(aInv * g + alpha * gg);
d[i++] = Math.sqrt(aInv * b + alpha * bb);
d[i++] = 255; // in this case alpha is always 255
}
// put the image data back onto the canvas.
ctx.putImageData(data,0,0);
.
내가 사용하는 색상 모델은 장치 디스플레이에서 방출되는 광자 수를 기반으로합니다. 각 색상 채널은 0에서 255까지의 값을 보유하지만이 값은 모니터의 실제 출력과 일치하지 않으며 카메라 (입력 장치)에서 캡처 한 광자 수를 나타내지 않습니다. 그것들은 광자 플럭스의 제곱근입니다. 간단한 선형 평균을 사용하여 색상을 혼합하고 이것을 고려하지 않으면 결과 색상이 어둡게 될 것입니다 (이미지의 색상이 높을 때 특히 현저합니다) 대비 곡선이 넓어집니다. 최상의 결과를 위해 픽셀을 직접 조작 할 때는 항상 r, g, b 값을 제곱하고 혼합, 블렌딩 등을 수행하십시오. 준비가되면 결과의 제곱근을 계산하여 값을 다시 로그 표현으로 변환하십시오.
이 동영상은 우리가 색상의 불투명도를 줄일 수 있도록, RGBA로 진수로 변환 된 밝은 빨간색 배경을 채우기 위해 fillRect 할을 사용한 오버 여기에 더 자세히 Computer Color is Broken
에 설명합니다. 0.8에서 1로 변경해보십시오. 그리고 이미지를 배경색과 병합하려면 투명해야합니다. – frnt
@Kaiido가 말한 것과 같이 코드에 이것을 추가합니다. ctx.globalAlpha = 0.6; – frnt