此篇文章只讨论图像处理部分,AI换脸暂不讨论。上图左边手机拍摄效果,右图是自己通过算法实现。
不同角度和亮度,不同参数的效果对比。
提亮图像
由于不同手机或图片的亮度信息不同,这里咱们先加了亮度调整,但是又不能平均加亮,这样会导至图片丢失很多细节,所以选择非线性提亮。
for(int i = 0; i < _Light; i++)
{
col = pow(col, (1 - col/3.0));
}
非线性提亮方法有很多,大家下载工程后可自行发挥。
减少图像般色级别
提取象素明度信息,以明度为附加参数,减少色阶
fixed4 col = tex2D(_MainTex, i.uv);
fixed lum = luminance(col);
col.rgb = floor((col.rgb * _quantizationLevels) + lum) / _quantizationLevels;
边缘提取
使用Sobel算子提取信息,拿到当前象素周围9个象素UV,然后采样得到象素信息,卷积拿到边缘信息。最后与边缘阀值比较,当前象素是否为边缘处理。
float bottomLeftIntensity = tex2D(_MainTex, i.bLR.xy).r;
float bottomRightIntensity = tex2D(_MainTex, i.bLR.zw).r;
float topLeftIntensity = tex2D(_MainTex, i.tLR.xy).r;
float topRightIntensity = tex2D(_MainTex, i.tLR.zw).r;
float leftIntensity = tex2D(_MainTex, i.leftRight.xy).r;
float rightIntensity = tex2D(_MainTex, i.leftRight.zw).r;
float topIntensity = tex2D(_MainTex, i.topBottom.xy).r;
float bottomIntensity = tex2D(_MainTex, i.topBottom.zw).r;
float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;
float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;
float mag = length(float2(h, v));
float thresholdTest = 1.0 - step(_threshold, mag);
图像混合
边缘信息后与减色阶后的图像混合得到最终颜色,漫画脸的颜色是固定的偏暖黄色,所以这里还要加一个颜色叠加,让最后的颜色看起来和脸部是相近色。
float3 finalCol = col * thresholdTest;
finalCol = you * finalCol;
finalCol = 1 - (1 - finalCol) * (1 - _Color.rgb);
return float4(finalCol, 1);
C#代码部分
这个算法共两个Pass,提亮图像为一个Pass,减少色阶+边缘提取+图像混合为一个Pass,所以我们要先生成一个RenderTexture用来存提亮后的图像,然后以在这个图像上做相应处理。
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (material != null)
{
material.SetFloat("_quantizationLevels", quantizationLevels);
material.SetFloat("_threshold", threshold);
material.SetColor("_Color", col);
material.SetFloat("_radius", radius);
material.SetFloat("_Light", lighten);
RenderTexture buffer0 = RenderTexture.GetTemporary(src.width, src.height, 0);
buffer0.filterMode = FilterMode.Bilinear;
Graphics.Blit(src, buffer0, material, 0);
Graphics.Blit(buffer0, dest, material, 1);
RenderTexture.ReleaseTemporary(buffer0);
}
else
{
Graphics.Blit(src, dest);
}
}
工程代码 加 微信号:ITComputerGraph
更多精彩内容,关注公众号《IT木子李》