图像滤镜晕影调节算法研究

最后更新于:2022-04-01 06:46:38

## 本文对滤镜中常见的晕影,晕角效果的实现做了研究,具体如下: ## 1 晕影调整算法 所谓晕影就是给图像四个角添加暗影效果,这暗影向图像中心逐渐淡化。我们使用如下公式来实现: 假设图像宽度高度分别为w,h: ~~~ double d = Math.Sqrt((i - w / 2) * (i - w / 2) + (j - h / 2) * (j - h / 2)); double dmax = 1.0 / Math.Sqrt(w * w / 4 + h * h / 4); double lum = 0.75 / (1.0 + Math.Exp((d * dmax - cRadius) * cGradient)) + cLight; //eg:double lum = 0.75 / (1.0 + Math.Exp((d * dmax - 0.85) * 5)) + 0.35; r = (int)((double)r * lum); g = (int)((double)g * lum); b = (int)((double)b * lum); ~~~ 注释: cRadius (cRadius=0.73)这个参数控制晕影的半径,值越大,半径越大; cLight (cLight=0.25)控制中心圆形区域内的像素亮度,值越大,图像越亮; cGradient (cGradient=20)这个参数控制中心区域与晕影过渡部分的梯度,值越小,过渡越自然,越不明显; 上述算法实现的是圆形晕影。 有了晕影图像之后,我们采用K比例混合算法来实现晕影强度的可调性,假设晕影图像为S(n,m),原图为X(n,m),效果图为Y(n,m),晕影强度因子为K,K属于[0,1],混合公式如下:                     Y(n,m)=K*X(n,m)+(1-K)*S(n,m) 这样就实现了晕影效果从无到有的调节过程。 ## 2 晕影调节快速算法 晕影调节的快速算法主要是改进晕影图像的生成过程。我们可以按照自己的需求使用PS制作出一张晕影效果图,来代替算法生成晕影图像的过程,这样就可以节省算法生成的时间了,之后的调节过程不变。 当然,这个算法的缺点就是晕影的半径,过渡程度和亮度无法调整。 目前,这里给出Instagram里使用的晕角模板: [![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-05_568b33284f3ba.png)](http://www.zealpixel.com/data/attachment/portal/201509/26/081917r0qevid2d1q3e3tt.png)     在Instagram中,是使用这个模板与目标图像执行“柔光”混合图层算法,得到晕角效果的,然后使用1中的K比例混合算法,来快速调节。 最后给出android 中C代码,可以直接使用。 ## 附录 Android C Code with RGB565 ~~~ void THaloEffect(int* srcData, int width, int height) { int gray = 0, green = 0, blue = 0, red = 0, i = 0, j = 0, alpha = 0xFF << 24; for(j = 0; j < height; j++) { for(i = 0; i < width; i++) { gray = srcData[i + j * width]; red = ((gray >> 16) & 0xFF); green = ((gray >> 8) & 0xFF); blue = (gray & 0xFF); double d = sqrt((i - width / 2) * (i - width / 2) + (j - height / 2) * (j - height / 2)); double dmax = 1.0 / sqrt(width * width / 4 + height * height / 4); //double lum = 0.75 / (1.0 + Math.Exp((d * dmax - 0.73) * 20)) + 0.25; double lum = 0.75 / (1.0 + exp((d * dmax - 0.73) * 20)) + 0.25; red = (int)((double)red * lum); red = CheckRange(red); green = (int)((double)green * lum); green = CheckRange(green); blue = (int)((double)blue * lum); blue = CheckRange(blue); srcData[i + j * width] = alpha | (red << 16) | (green << 8) | blue; } } }; void THaloEffect_F(int* srcData, int* mask, int width, int height, int ratio) { int gray = 0,green = 0,blue = 0,red = 0,i = 0, mRed = 0, mGreen = 0, mBlue = 0, alpha = 0xFF << 24; int length = width * height; for (i = 0; i < length; i++) { gray = srcData[i]; red = ((gray >> 16) & 0xFF); green = ((gray >> 8) & 0xFF); blue = (gray & 0xFF); gray = mask[i]; mRed = ((gray >> 16) & 0xFF); mGreen = ((gray >> 8) & 0xFF); mBlue = (gray & 0xFF); mRed = ModeSmoothLight(red, mRed); mGreen = ModeSmoothLight(green, mGreen); mBlue = ModeSmoothLight(blue, mBlue); red = (mRed * ratio + (100 - ratio) * red) / 100; green = (mGreen * ratio + (100 - ratio) * green) / 100; blue = (mBlue * ratio + (100 - ratio) * blue) / 100; srcData[i] = alpha | (red << 16) | (green << 8) | blue; } }; ~~~
';