热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

透明像素-PremultipliedAlpha的秘密

PremultipliedAlpha的秘密我得承认题目有点标题党的意思,自从Flash播放器采用了BitmapData以来,Flash采用一种叫做PremultipledAlpha的技术来存储透明
Premultiplied Alpha的秘密

我得承认题目有点标题党的意思,自从Flash播放器采用了BitmapData以来,Flash采用一种叫做Premultipled Alpha的技术来存储透明的像素。但是它还是有点...为了避免你觉得我啰里巴索你可以直接去检查示例程序, check out the demo right away 如果没看懂,呵呵......

"Premultiplied" alpha技术意味着不仅像素的Alpha信息存储在通道里,而且已经扩张到红,蓝,绿通道里,在实际应用中这意味着如果你保存着 #fff8000橙色,而将其透明度设置为50%,那么实际设置保存的是#80803f00.这意味着颜色通道中的任意像素值都不会比Alpha通道中的值来的大

这样做的原因是出于性能的考虑,图像处理算法在复合两张图片的时候总是需要将ALPHA通道的信息复合到各个颜色通道,因此如果你需要处理很多的图像复合时候,这样的做法就节省了很多的时间,而不需要对每个像素重新进行复合,正如我们所知道的Flash的日常处理中有很多时候都在处理复合,比如重合两张反锯齿的直线时就会有复合,有了这样的处理之后Flash的速度就很快了。

但是也有一个问题,像素是以32位的整数值存储的,也就是说每个通道有8位或者256种可能的值,另一方面像素的计算通常是以浮点数学的方式进行的,也就是说可能的值要远大的多,如果通常以浮点处理那很好,但是有些情况下你不得不将浮点的值回写到像素信息,也就是说比如43.7回写的时候就会圆整为44或者更糟的43回写到像素值里面

通常情况下这种小的误差不会对应用造成很大的麻烦,但是一旦你开始处理小的像素值,那么错误就会被基类放大,,例如如果你将一个像素的ALPHA值设置为16那么每一个像素都会被乘上一个因子16/256=0.0625,因此灰色像素就会变成128*0.0625=8 暗像素64就会变成4,但是稍微亮一点的像素如67也会变成4,注意没有小数这是圆整后的结果,你会发现颜色种类减少了,从原来的256×256×256减少到8*8*8,严重的问题

如果你将ALPHA值保持设置为8那么不会有太大的问题,如果你增大ALPHA值,那么灾难就出现了,大量的颜色信息由于进度原因会丢失,而且无法修复。

为了解释清楚到底是怎么回事我设置了一个Demo demo that visualizes the amount of information loss来解释。它先将图像的Alpha通道设置为一个选定值,然后再设置回255,你所观察到的现象正好说明了,当Alpha值很小的时候会有些海报斑驳效果,即使你将像素设置为254,你也会发现颜色丢失的现象(复选 观察数据丢失复选框)该复选框会对比颜色丢失和未丢失的情况,由于有的时候丢失不是很明显,DEMO将该丢失放大了以增强了对比度


那要怎样才能保存颜色信息呢,你只有慢慢来,效率和质量不可兼得么,将Alpha信息和像素分开存储,也就是说你维护着三张Bitmap一张存储颜色信息,一张存储Alpha值,第三章存储两者复合后的结果。


 




The Dirty Secrets of Premultiplied Alpha

Okay, I'm exaggerating. Several years after BitmapData was introduced to the Flash player it's not really a secret anymore that Flash uses a feature called premultiplied alpha when it stores transparent pixels. But it is a bit dirty after all. In case you want to skip the following nerd talk you can check out the demo right away - but don't cry if you don't understand what it is telling you.

"Premultiplied" alpha means that the alpha information of a pixel is not only stored in the alpha channel itself, but it is already "multiplied" into the red, green and blue channel. In Flash practice this means that if you have a nice orange #fff8000 and reduce the alpha to 50% it will be stored as #80803f00. This means that each value of the color channels will never be bigger than that of the alpha channel.

The reason to do this is performance. The image processing algorithm to composite two bitmaps always requires that the alpha channels are being multplied into the color information, so if you have a tool that needs to do a lot of compositing it simply saves you a good amount of time if you don't have to do these multiplications for every pixel. And as we know Flash is all about compositing things (whenever you overlap two antialiased lines some serious composting takes place) and Flash is pretty fast with this.

But there is a problem. Pixels are stored as 32 bit integer values, this means each channel has a range of 8 bit or 256 possible values. On the other hand calculations with pixels usually are done in floating point mathematics which means that the range of possible in-between values can be much higher. As long as you stay within floating point that's cool, but unfortunatly at some point you have to write those values back into a bitmap which means that if you have a result of 43.7 it will be rounded to 44 or even worse to 43.

Normally these little errors do not cause much trouble. But once you start dealing with small alpha values the error accumulates. An example: when you set the alpha value of a pixel to 16 all color values will be multiplied with a factor of 16/256 = 0.0625. So a gray pixel of 128 will become 128 * 0.0625 = 8, a darker pixel of 64 will become 64 * 0.0625 = 4. But a slightly lighter pixel of maybe 67 will become 67 * 0.0625 = 4.1875 - yet there are no decimals in integer pixels which means it will also become 4. The effect that you will get posterization - setting your alpha channel to 8 means that you also reduce your color channels to 8 levels, this means instead = 256*256*256 different colors you will end up with a maximum of 8*8*8 = 512 different colors.

Well, as long as you keep your alpha at 8 you will not notice any difference but once you increase the alpha the desaster becomes obvious. Getting back from alpha 8 to alpha 255 means multiplying each channel by 16. This means that our old 64 pixel which was reduced to 4 becomes 4*16 = 64. Now that's great - same value as before! But the 67 pixel had also been reduced to 4 which means 4*16 = 64 - that's 3 smaller than 67. This means this information is lost forever and cannot be restored. And the eye can be quite unforgiving when it comes to certain subtle shades.

In order to show you the extend of this effect I've built a demo that visualizes the amount of information loss that happens: It first reduces an image's alpha channel to a chosen value and then sets the alpha back to 255. What you will see is that for small alpha values there is some nasty posterization happening. But even if you just reduce the alpha to 254 the image will suffer information loss, you can see that by switching on the "show data loss" checkbox. What this does is to take a difference between the original and the restored image. Since the loss can be small there is an automatic multiplication involved to increase the contrast.

So what can you do when you have to preserve the image information? Well, you have to take the slow road and always keep the alpha channel separate from the image. This means that you maintain three bitmaps - one is used to store the RGB information, one stores the alpha channel and the third one is used to be displayed on screen by joining both of them together.



 
推荐阅读
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • Android实战——jsoup实现网络爬虫,糗事百科项目的起步
    本文介绍了Android实战中使用jsoup实现网络爬虫的方法,以糗事百科项目为例。对于初学者来说,数据源的缺乏是做项目的最大烦恼之一。本文讲述了如何使用网络爬虫获取数据,并以糗事百科作为练手项目。同时,提到了使用jsoup需要结合前端基础知识,以及如果学过JS的话可以更轻松地使用该框架。 ... [详细]
  • 本文介绍了Python对Excel文件的读取方法,包括模块的安装和使用。通过安装xlrd、xlwt、xlutils、pyExcelerator等模块,可以实现对Excel文件的读取和处理。具体的读取方法包括打开excel文件、抓取所有sheet的名称、定位到指定的表单等。本文提供了两种定位表单的方式,并给出了相应的代码示例。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
author-avatar
shanshanhongxing
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有