图片去黑底

前文【让粒子可以在白色背景显示 [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。

时间: 2024-08-25 12:26:51

图片去黑底的相关文章

让粒子可以在白色背景显示 [Blending Shader 实操]

Unity3D 提供了粒子特效的各种shader,今天要说的是 Additive(因为项目最初就是用了Additive 发生了问题.. ε=ε=ε=┏(゜ロ゜;)┛) Additive Particle Shader 其Blending 方式是 Blend SrcAlpha one.至于Blend 的操作可以看这篇文章 [转] SHADER BLENDING,此处不再详述. 其原理很简单,其实就是在原图的基础上使用加法将颜色进行叠加.[注:Blend SrcAlpha one的方式(Blend

android 图片加载优化,避免oom问题产生

1,及时回收bitmap,在activity的onstop()和onDestory()里面调用如下代码进行bitmap的回收: // 先判断是否已经回收 if(bitmap != null && !bitmap.isRecycled()){ // 回收并且置为null bitmap.recycle(); bitmap = null; } System.gc(); 2,对oom异常的捕获:出现异常不能让程序就那么崩掉吧,所以对程序中中设计bitmap的操作都要检测oom异常进而进行处理: B

Canvas---Canvas图像处理、图片查看器实现思路整理、拖动边界控制

没想到一个图片查看器花了我这么多时间,而且没做好. 现在整理下思路,然后把不足的地方记一下,日后请教他人. 基本思路: 一.图片查看器功能---缩放 要实现自由缩放,先要实现图片对canvas的自适应,就是给你一张大图片,你能够把它合理缩放后恰好绘制在canvas中. 具体做法是:例如:图片为500*500,canvas为240*320,那就取缩放宽度为240,长度为240/500*500,利用缩放宽度与长度,绘制图片即可. 然后是自由缩放,这时,你的缩小放大对象只要是一个矩形就好,然后图片去适

利用POI操作不同版本word文档中的图片以及创建word文档

我们都知道要想利用java对office操作最常用的技术就应该是POI了,在这里本人就不多说究竟POI是什么和怎么用了.先说本人遇到的问题,不同于利用POI去向word文档以及excel文档去写入数据和向外导出数据并且保存到数据库中这些类似的操作,由于业务上的需要需要利用POI去读取word中的图片,并且去把图片去保存为一个file文件.查了Apache公司提供的api帮助文档,再网友的一些线索,本人也总结了几中对不同word版本(.doc或者是.docx结尾)对于文件中所含图片的操作方式,希望

利用POI操作不同版本号word文档中的图片以及创建word文档

我们都知道要想利用java对office操作最经常使用的技术就应该是POI了,在这里本人就不多说到底POI是什么和怎么用了. 先说本人遇到的问题,不同于利用POI去向word文档以及excel文档去写入数据和向外导出数据而且保存到数据库中这些类似的操作,因为业务上的须要须要利用POI去读取word中的图片,而且去把图片去保存为一个file文件.查了Apache公司提供的api帮助文档,再网友的一些线索,本人也总结了几中对不同word版本号(.doc或者是.docx结尾)对于文件里所含图片的操作方

未知高度的div自适应图片高度

<div style="background-image: url(http://your-image.jpg);"> <img src="http://your-image.jpg" style="opacity:0;" /></div> 用图片去占位,把div高度撑开就可以显示背景图片 同时改变背景图和图片的宽高就可以做到div高度自适应背景图的高度啦

Android之图片加载框架Fresco基本使用(一)

PS:Fresco这个框架出的有一阵子了,也是现在非常火的一款图片加载框架.听说内部实现的挺牛逼的,虽然自己还没研究原理.不过先学了一下基本的功能,感受了一下这个框架的强大之处.本篇只说一下在xml中设置属性的相关用法. 0.引入Fresco以及相关注意事项. 1.PlaceHolderImage占位图 2.FailureImage加载失败时显示的图片 3.RetryImage重新加载的图片 4.ProgressBarImage加载时显示的进度图片 5.BackgroundImage背景图 6.

Java使用图片自定义登录窗体

一.问题概述 Java是一门面向对象的编程语言,从出版至今,Java对其自身不断改进,Java的图形界面编程也做的越来越好,从AWT到更高级的Swing.但是,我们的需求永远是无法满足的,有时候我们需要自定义窗体,特别是一张漂亮的图片做一个窗体,那就再好不过了.那么,今天我就把用图片自定义应用窗体的方法分享给大家. 二.实现方法 1.用图片自定义应用窗体效果图: 图1 Java使用图片自定义应用窗体效果图 2.创建一个类继承Swing中JFrame,然后定义一个BufferedImage变量,用

android 应用开发对大图片的处理

一,下载 android下载大图片(例如微博长图片)会出现OOM down掉问题 解决这个问题的办法是下载图片时先得到图片的宽度和高度,如果超出规定限制则对图片进行缩放 关键参数 1. BitmapFactory.Options.inJustDecodeBounds inJustDecodeBounds:boolean类型,如果设为true,则进行辩解判断,并不申请bitmap内存 2.BitmapFactory.Options.inJustDecodeBounds.outWidth和outHe