打印

[讨论] Kirikiri2系统的txt分割型立绘的合成问题

要命,要重写了,用ImageMagick肯定不行了

blend(dest, min(1.0, dest ÷ ( 1.0 - src ) ), α)

这可不是一般alpha blending...

        private static int blendNormal(int dest, int src, int alpha) {
                return (src * alpha + dest * (255 - alpha)) / 255;
        }

        private static int blendColorDodge(int dest, int src, int alpha) {
                return blendNormal(dest, Math.min(255, dest / (255 - src)), alpha);
        }

src不会等于1.0?

[ 本帖最后由 haibara 于 2010-03-20 22:46 编辑 ]
sfsuvival, 我想问下,一般blending后最终图象的alpha怎么处理的

是与src的alpha一样,还是process(src alpha,dest alpha)这样的?

我想把alpha处理固定下来,把上面所有的blending模式加到directmuxer里面去

[ 本帖最后由 haibara 于 2010-03-20 14:17 编辑 ]
private static int blendColorDodge(int dest, int src, int alpha) {
                return blendNormal(dest, src == 255 ? src : Math.min(255, (dest << 8) / (255 - src)), alpha);
        }

为什么dest要x256?

[ 本帖最后由 haibara 于 2010-03-21 20:52 编辑 ]
引用:
原帖由 sfsuvival 于 2010-03-22 02:41 发表
...我对图像处理的认识不深
这只是研究出来的结果
我也不知道那些合成模式的原理...


这个可能是因为有用min
所以即使dest ÷ ( 1.0 - src ) 是无限大也不管了...


老实说我弄不清什么是alpha blending.. ...
我比较认同αo是255的opaque,而非来源f(alpha,alpha)


也就是你给的文章的Alpha blending

java官方的desktop的BlendComposite也是这个实现(预乘alpha是个浮点参数,对像素做这样的操作,result做前期blend处理,在AlphaBlending中result是否等于src?),而java的标准库里的AlphaComposite就比较晕头转向了

                    blender.blend(srcPixel, dstPixel, result);

                    // mixes the result with the opacity
                    dstPixels[x] = ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 |
                                   ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 |
                                   ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) <<  8 |
                                    (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF;



而BlendComposite的COLOR_DODGE是这样的
public void blend(int[] src, int[] dst, int[] result) {
                            result[0] = src[0] == 255 ? 255 :
                                Math.min((dst[0] << 8) / (255 - src[0]), 255);
                            result[1] = src[1] == 255 ? 255 :
                                Math.min((dst[1] << 8) / (255 - src[1]), 255);
                            result[2] = src[2] == 255 ? 255 :
                                Math.min((dst[2] << 8) / (255 - src[2]), 255);
                            result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
                        }

与kr2doc区别就在dest要x256

x256我看与ps效果是一样的,不乘明显错误

[ 本帖最后由 haibara 于 2010-03-22 11:19 编辑 ]
引用:
原帖由 sfsuvival 于 2010-03-22 16:04 发表


我也有这样想过
不过这样的话Alpha blending后的图和没有alpha一样(整张图的alpha都是255=整张图不透明=alpha没有用)
事件图合成还可以这样做
但立绘合成就麻烦了
合成后该透明的地方不透明了
我看见一些文 ...
以extractdata为例,它alpha blending就当alpha none,只保留rgb...

最后关于alpha blending,还是MS看的爽眼,实在不高兴折腾了
http://msdn.microsoft.com/en-us/library/dd183393%28VS.85%29.aspx

至于dest ÷ ( 1.0 - src )等价rgb int是(dest/255)/(1-src/255)*255=dest/(1-src/255)=dest*255/(255-src)(原先是我自己乘除法搞错了,不过为什么不是255呢)
GIMP+1可能是防0,但是java那个本来就判断src是否等于255的。。。

[ 本帖最后由 haibara 于 2010-03-23 00:31 编辑 ]
引用:
原帖由 sfsuvival 于 2010-03-23 12:35 发表


M$这个不是和维基alpha compositing的公式一样吗?

当SourceConstantAlpha=0xFF (合成时不需要改整张图的opacity)
Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) ...
好麻烦。还是用这个好了


刚才看了IM的实现,我的妈呀,大概是SVG标准那个实现

00088 static inline void MagickPixelCompositeOver(const MagickPixelPacket *p,
00089   const MagickRealType alpha,const MagickPixelPacket *q,
00090   const MagickRealType beta,MagickPixelPacket *composite)
00091 {
00092   MagickRealType
00093     gamma;
00094
00095   if (alpha == TransparentOpacity)
00096     {
00097       *composite=(*q);
00098       return;
00099     }
00100   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
00101   composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
00102   gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
00103   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
00104   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
00105   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
00106   if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
00107     composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
00108 }


00038 static inline MagickRealType MagickOver_(const MagickRealType p,
00039   const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
00040 {
00041   MagickRealType
00042     pixel;
00043
00044   pixel=(1.0-QuantumScale*alpha)*p+(1.0-QuantumScale*beta)*q*QuantumScale*alpha;
00045   return(pixel);
00046 }

[ 本帖最后由 haibara 于 2010-03-23 23:29 编辑 ]
alpha = deltaPixel[i + 3] & 0xff;
                                        beta = basicPixel[i + 3] & 0xff;
                                        resultPixel = (byte) blend(basicPixel & 0xff, deltaPixel & 0xff, alpha);
                                        resultPixel[i + 1] = (byte) blend(basicPixel[i + 1] & 0xff, deltaPixel[i + 1] & 0xff, alpha);
                                        resultPixel[i + 2] = (byte) blend(basicPixel[i + 2] & 0xff, deltaPixel[i + 2] & 0xff, alpha);
                                       

        private static int blend(int dest, int src, int alpha) {
                return dest + (src - dest) * alpha / 255;
        }

若基本图无alpha,或者是opaque alpha,这个就够了

[ 本帖最后由 haibara 于 2010-03-25 07:09 编辑 ]
alpha = deltaPixel[i + 3] & 0xff;
                                        beta = basicPixel[i + 3] & 0xff;
                                        gramma = alpha + beta - alpha * beta / 255;
                                        if (gramma == 0) {
                                                delta = 1;
                                        } else {
                                                delta = gramma;
                                        }
                                        resultPixel = (byte) (composite(deltaPixel & 0xff, basicPixel & 0xff, alpha, beta) / delta);
                                        resultPixel[i + 1] = (byte) (composite(deltaPixel[i + 1] & 0xff, basicPixel[i + 1] & 0xff, alpha, beta) / delta);
                                        resultPixel[i + 2] = (byte) (composite(deltaPixel[i + 2] & 0xff, basicPixel[i + 2] & 0xff, alpha, beta) / delta);
                                        resultPixel[i + 3] = (byte) gramma;

        private static int composite(int src, int dest, int alpha, int beta) {
                return src * alpha + dest * beta - dest * alpha * beta / 255;
        }

按照svg那个来完整的是这样,不过速度居然差不多,vm优化的厉害

[ 本帖最后由 haibara 于 2010-03-25 00:45 编辑 ]
引用:
原帖由 sfsuvival 于 2010-03-25 18:41 发表
im的好像和svg不同
翻了一下
如果图是8位/色彩通道
TransparentOpacity = QuantumRange = 255
QuantumScale = 1/255
MagickEpsilon = 2.0*1.1920928955078125e-07
MagickRealType = double
im合成后的α是alp ...
我程序已经改成svg的src-over,M$的AC_SRC_OVER,维基的alpha compositing

        private static int blend(int src, int dest, int alpha) {
                if (alpha == 0) {
                        return dest;
                }
                if (alpha == 255) {
                        return src;
                }
                return dest + (src - dest) * alpha / 255;
        }

        private static int blend(int src, int dest, int alpha, int beta) {
                if (alpha == 0) {
                        return dest;
                }
                if (alpha == 255 || beta == 0) {
                        return src;
                }
                if (beta == 255) {
                        return blend(src, dest, alpha);
                }
                return (src * alpha * 255 + dest * beta * 255 - dest * alpha * beta) / (alpha * 255 + beta * 255 - alpha * beta);
        }

[ 本帖最后由 haibara 于 2010-03-26 14:49 编辑 ]
引用:
原帖由 sfsuvival 于 2010-03-26 22:37 发表
看不到有什么问题
用java实现svg的src-over/M$的AC_SRC_OVER/维基的alpha compositing
应该就是这样...

blending是需要2张图
但blend mode是一张图的属性
haibara你是怎样处理?
看PS是用src的blend mode将sr ...
我不太懂ps

directmuxer合成模式从差分图那边取

目前还有个问题:

我测试
整数的算法(alpha blending),即
(src * alpha * 255 + dest * beta * (255 - alpha)) / (alpha * 255 + beta * 255 - alpha * beta);
浮点数的算法(complex composite的normal),即
Sa = alpha / 255D;
Da = beta / 255D;
Sc = src / 255D;
Dc = dest / 255D;
Sca = Sa * Sc;
Dca = Da * Dc;
Ra = Sa + Da - Sa * Da;
(Sca + Dca * (1 - Sa)) / Ra * 255

目测看边缘锯齿差别很大,为什么,精度?

[ 本帖最后由 haibara 于 2010-04-02 12:01 编辑 ]
查看积分策略说明

快速回复主题

选项

[完成后可按 Ctrl+Enter 发布]  预览帖子  恢复数据  清空内容

当前时区 GMT+8, 现在时间是 2024-04-25 20:56

Processed in 0.014198 second(s), 6 queries.