zoukankan      html  css  js  c++  java
  • 图片去黑底

    前文【让粒子可以在白色背景显示 [BLENDING SHADER 实操]】说到最后的效果 有点BUG, 在一些过渡的地方有些黑边。 这个问题倒是和算法无关,是和图片本身有关系。 下面是效果对比图:

    有黑边 没黑边(完美)

    其原因是做图的时候,为了方便做图, 开始是不会直接用"透明"这个概念做图,而是将图做成黑色底,然后最后将黑底转为Alpha=0 的颜色,所以 透明图的RGBA是(0,0,0,1)。 而这种做法对 Additive 是没影响的。但是对于我这个Shader 却是有问题了。

    在网上也有人遇到过类似的问题:(渲染tga格式的序列帧,这种黑边怎么优化呀

    其根本原因是没有使用 Additive 的叠加方式(使用了就没问题,会有一种光了一点点的感觉,当然在PS上没办法看到Additive效果)

    而图片去黑的方法也有很多,使用PS也行,在AE 中也有个叫UnMult的插件。

    然而同事反应 用PS 太麻烦了(虽然有Action),还是需要手动做几步操作,而且纯黑白的图效果不太好。

     所以我干脆就使用C#写了个插件(仅限PNG格式)

    首先得明白去黑底的原理

    去黑底的图片分两种
    1.纯黑白(没有其他RGB颜色的图)

    2.一种色有除黑白外其他颜色的图片

    无论是那种图,其去黑底的原理都是 “越黑的像素越透明”。只是实现的细节上有区别。

    对于

    1.纯黑白的处理就简单多了,所有像素设置成Rgba(1,1,1, (src.r+src.g+src.b)/3) 即可。
    2.多彩色的图片,不能使用纯黑白的处理,否则所有图都会变成黑白,其原理是找出原像素点中RGB分量中最高的值 maxV =Max(src.r,src.g,src.b),一般其透明度就是该值maxV。
    因为其他值相对maxV比较少,所以rgb 分别加上 255-maxV 的差值,其原理是将该像素点"变亮"了,从而取消了黑底对该像素点的影响。而黑底将转化为透明度

    而使用多彩色图片转换的算法对纯黑白的支持也不太好, 有可能会残留灰底,其原因是 有可能在美工做图时 没有真正地使用"纯灰度",也就是说 rgb 的分值不是相等的,这里对2种图片分别做了处理,在工具中使用 /F 参数是针对纯黑白的图处理。

    具体代码如下:

    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    namespace ImageBlackToAlpha
    {
        class Program
        {
            static byte Max(params byte[] values)
            {
                if (values == null || values.Length == 0)
                    return 0;
                var max = values[0];
                for (var i = 1; i < values.Length; ++i)
                {
                    max = Math.Max(max, values[i]);
                }
                return max;
            }
    
            static byte Min(params byte[] values)
            {
                if (values == null || values.Length == 0)
                    return 0;
                var min = values[0];
                for (var i = 1; i < values.Length; ++i)
                {
                    min = Math.Min(min, values[i]);
                }
                return min;
            }
    
            static void Main(string[] args)
            {
                if (args.Count() < 2)
                {
                    Console.WriteLine("Usage: "ImageBlackToAlpha" [+ source] [destination [/F]]");
                    Console.WriteLine(" source        InputPngPath ");
                    Console.WriteLine(" destination   OutputPngPath");
                    Console.WriteLine(" /F  Forces all RGB to White(254,254,254)");
    
                    return;
                }
    
                var toWhite = false;
                var image = Image.FromFile(args[0]);
                var bitmap = new Bitmap(image);
                var save = new Bitmap(bitmap.Width, bitmap.Height);
    
                if (args.Count() == 3)
                {
                    toWhite = args[2] == "/F" || args[2] == "/f";
                }
    
                for (var x = 0;x< bitmap.Width;++x)
                {
                    for(var y = 0; y < bitmap.Height; ++y)
                    {
                        var clr = bitmap.GetPixel(x, y);
    
                        if (toWhite)
                        {
                            // 只支持 纯黑白贴图
                            var alpha = (0 + clr.R + clr.G + clr.B) / 3;
                            alpha = Math.Min(clr.A, alpha);
                            //因为 纯白(RGB)而Alpha小于255 会出现 全透明的问题 所以不能使用 255//bug?
                            clr = Color.FromArgb(alpha, 254, 254, 254);
                        }
                        else
                        {
                            var max = Max(clr.R, clr.G, clr.B);
                            //因为 纯白(RGB)而Alpha小于255 会出现 全透明的问题 所以不能使用 255//bug?
                            var sub = 254 - max;
                            var alpha = Math.Min(clr.A, max);
                            clr = Color.FromArgb(alpha, clr.R + sub, clr.G + sub, clr.B + sub);
                        }
                        save.SetPixel(x, y, clr);
                    }
                }
                
                save.MakeTransparent(Color.Transparent);
                save.Save(args[1], ImageFormat.Png);
            }
        }
    }

    效果图:

     注:在测试过程中发现rgb(1,1,1)[RGB32(255,255,255)] 的时候,无论透明度设置成多少,该像素依然是全透明,不清楚这是PNG的 Feature 还是 System.Drawing.Imaging 处理的问题,这里统一使用了 254 代替255 避开了这个BUG。

  • 相关阅读:
    cocos2dx中的精灵CCSprite
    Mark Russinovich 的博客:Windows Azure 主机更新:原因、时间和方式
    cocos2d-x中的尺寸之三
    cocos2d-x中的尺寸之二
    cocos2d-x中的尺寸之一
    cocos2d-x中的导演、场景、层和精灵
    宣布正式发布 Windows Azure 上的 Oracle 软件以及 Windows Azure Traffic Manager 更新
    Hello China操作系统STM32移植指南(三)
    Hello China操作系统STM32移植指南(二)
    diff_mysql_table_exec.py
  • 原文地址:https://www.cnblogs.com/godzza/p/7428080.html
Copyright © 2011-2022 走看看