变亮模式跟变暗模式是相对的,它是通过混合色与基色的相关数值进行比较,选择较大的数值作为结果色。因此结果色会更亮,同时颜色也会变化。(位置互换不发生变化)
void layerblend_lightness(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++)
d3[cw + c] = d1[cw + c] > d2[cw + c] ? d1[cw + c] : d2[cw + c];
}
}
}
滤色模式与正片叠底模式相对。它的计算公式是:255 - 混合色的补色 * 基色补色 / 255。得到的数据会比混合及基色更大,因此结果色会更亮。从计算公式也可以看出基色或混合色任何一项为255也就是白色,结果色数值就是255为白色。任何一项数值为0,也就是为黑色的话,结果色就跟数值不为0的一致。
void layerblend_screen(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++)
d3[cw + c] = 255 - (255.0f - d1[cw + c]) * (255.0f - d2[cw + c]) / 255;
}
}
}
颜色减淡是通过混合色及基色的各通道颜色值进行对比,减少二者的对比度使基色的变亮来反映混合色。它的计算公式:结果色 = 基色 + (混合色 * 基色) / (255 - 混合色)。混合色为黑色,结果色就等于基色,混合色为白色结果色就为白色。基色为黑色结果色就为黑色.
void layerblend_color_light(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++){
int res = 0;
if (d2[cw + c] == 0)
res = 255;
else
res = d1[cw + c] + (1.0f * d1[cw + c] * d2[cw + c]) / (255.0f - d2[cw + c]);
d3[cw + c] = saturate_cast(res);
}
}
}
}
颜色线性减淡是通过查看每个通道的颜色信息,并通过增加亮度使基色变亮以反映混合色。它的计算公式:结果色 = 基色 + 混合色,其中基色与混合色的数值大于255,系统就默认为最大值也就是255。由公式可以分析出混合色为黑色结果色就等于基色,混合色为白色结果色就为白色。基色也一样。我们颠倒混合色及基色的位置,结果色也不会变化。(位置互换不发生变化)
void layerblend_color_linear_light(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++){
d3[cw + c] = saturate_cast(d1[cw + c] + d2[cw + c]);
}
}
}
}
浅色模式比较好理解:它是通过计算混合色与基色所有通道的数值总和,哪个数值大就选为结果色。因此结果色只能在混合色与基色中选择,不会产生第三种颜色。与深色模式刚好相反。
叠加模式比较特别,它是通过分析基色个通道的数值,对颜色进行正片叠加或滤色混合,结果色保留基色的明暗对比,因此结果色以基色为主导。
计算公式:
基色 < = 128:结果色 = 混合色 * 基色 / 128;基色 > 128:结果色 = 255 - (255 - 混合色)* (255 - 基色) / 128。
void layerblend_overlay(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++){
int res = 0;
res = ((d1[cw + c] <= 128) ? (1.0f * d2[cw + c] * d1[cw + c] / 128):(255 - (255.0f - d2[cw + c]) * (255.0f - d1[cw + c]) / 128));
d3[cw + c] = saturate_cast(res);
}
}
}
}
柔光模式是较为常用的模式,它是根据混合色的通道数值选择不同的公式计算混合色。数值大于128的时候,结果色就比基色稍亮;数值小于或等于128,结果色就比基色稍暗。柔光模式是以基色为主导,混合色只相应改变局部明暗。其中混合色为黑色,结果色不会为黑色,只比结果色稍暗,混合色为中性色,结果色跟基色一样。
计算公式:
混合色 <=128:结果色 = 基色 + (2 * 混合色 - 255) * (基色 - 基色 * 基色 / 255) / 255;
混合色 >128: 结果色 = 基色 + (2 * 混合色 - 255) * (Sqrt(基色/255)*255 - 基色)/255。
如果基色=混合色,则可优化为256的表smoothlight,公式变形如下:
res = x + (2x-255)*(x-x*x/255)/255;
res = x+(2x-255)*(255*sqrt(x/255)-x)/255;
void layerblend_soft_light(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++){
int res = 0,temp1,temp2;
temp1 = ((int)((float)d1[cw + c]+((float)d2[cw + c]+(float)d2[cw + c]-255.0f)*((sqrt((float)d1[cw + c]/255.0f))*255.0f-(float)d1[cw + c])/255.0f));
temp2 = ((int)((float)d1[cw + c]+((float)d2[cw + c]+(float)d2[cw + c]-255.0f)*((float)d1[cw + c]-(float)d1[cw + c]*(float)d1[cw + c]/255.0f)/255.0f));
res = d2[cw + c] > 128 ? temp1 : temp2;
d3[cw + c] = saturate_cast(res);
}
}
}
}
强光模式跟叠加模式十分类似,只是在计算的时候需要通过混合色来控制,混合色的数值小于或等于128的时候,颜色会变暗;混合色的数值大于128的时候,颜色会变亮。混合色为白色,结果色就为白色;混合色为黑色,结果为黑色。混合色起到主导作用。
计算公式:
混合色 <= 128:结果色 = 混合色 * 基色 / 128;
混合色 > 128 :结果色 = 255 - (255 - 混合色) * (255 - 基色) / 128.
void layerblend_strong_light(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++){
int res = 0;
res = d2[cw + c] <= 128.0f ? ((float)d2[cw + c] * d1[cw + c] / 128.0f):(255.0f - (255.0f - d2[cw + c]) * (255.0f - d1[cw + c]) / 128.0f);
d3[cw + c] = saturate_cast(res);
}
}
}
}
亮光模式是通过增加或减少对比度是颜色变暗或变亮,具体取决于混合色的数值。混合色比中性灰色暗,结果色就相应的变暗,混合色比中性灰色亮,结果色就相应的变亮。有点类似颜色加深或颜色减淡。
计算公式:
A---基色;B—混合色
C=A-(255-A)*(255-2B)/2B 当混合色>128时
C=A+[A*(2B-255)]/[255-(2B-255)
void layerblend_hight_light(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++){
int res = 0;
if (d2[cw + c] <= 128)
res = d2[cw + c] == 0 ? d1[cw + c] : (d1[cw + c] - (255.0f - d1[cw + c])*(255.0f -2.0f * d2[cw + c]) / (2.0f * d2[cw + c]));
else
res = d2[cw + c] == 255 ? d1[cw + c] : d1[cw + c]+ (d1[cw + c]*(2.0f * d2[cw + c]-255.0f))/(255.0f - (2.0f * d2[cw + c] - 255.0f));
d3[cw + c] = saturate_cast(res);
}
}
}
}
线性光(linear light)
线性光:通过减少或增加亮度,来使颜色加深或减淡。具体取决于混合色的数值。混合色数值比中性灰色暗的时候进行相应的加深混合;混合色的数值比中性灰色亮的时候进行减淡混合。这里的加深及减淡时线性加深或线性减淡。
计算公式:结果色 = 2 * 混合色 + 基色 -255。数值大于255取255。
void layerblend_linear_light(Mat &base,Mat &blend,Mat &dst)
{
if (base.rows != blend.rows ||
base.cols != blend.cols ||
base.type() != blend.type())
return;
dst = Mat::zeros(base.rows,base.cols,base.type());
for (int h = 0;h < base.rows;h ++)
{
uchar *d1 = base.ptr(h);
uchar *d2 = blend.ptr(h);
uchar *d3 = dst.ptr(h);
for (int w = 0;w < base.cols;w ++)
{
int cw = w * base.channels();
for (int c = 0;c < base.channels();c ++){
int res = 2 * d2[cw + c] + d1[cw + c] - 255;
d3[cw + c] = saturate_cast(res);
}
}
}
}
点光模式:它会根据混合色的颜色数值替换相应的颜色。如果混合色数值小于中性灰色,那么就替换比混合色亮的像素;相反混合色的数值大于中性灰色,则替换比混合色暗的像素,因此混合出来的颜色对比较大。
计算公式:
基色 < 2 * 混合色 - 255:结果色 = 2 * 混合色 - 255;
2 * 混合色 - 255 < 基色 < 2 * 混合色 :结果色 = 基色;
基色 > 2 * 混合色:结果色 = 2 * 混合色。