打印

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

引用:
原帖由 sfsuvival 于 2010-04-03 01:57 发表


double的精确度已经很高
会否你在处理运算时做了些减低精确度的动作?

我用你给的源码写了个试试
两种方法输出的数字一样,没有问题

import java.util.Random;

public class TestRange {
        public sta ...
我觉得没有,而且我尽量减少除法的,所以上下同时比一般多乘了次255,才有(src * alpha * 255 + dest * beta * (255 - alpha)) / (alpha * 255 + beta * 255 - alpha * beta)

而且也应该与非算法部分无法,我在这2个算法相互替换写法,结果还是有异常

总之就是锯齿部分有差别

还有

http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/
http://www.w3.org/TR/2004/WD-SVG12-20041027/rendering.html

这2个不同版本,应该选择哪个,按照目测ps里colordodge是2004的,softlight是2009的

而且Subtractive/LinearBurn在SVG没有实现怎么办

[ 本帖最后由 haibara 于 2010-04-03 20:55 编辑 ]
引用:
原帖由 sfsuvival 于 2010-04-04 05:59 发表

既然你觉得是算法的问题
可以像我那样抽出来试试
也许会发现问题所在...

我上面写的java测试过没有问题
也许你可以对比一下?
这个问题既然隐藏得这么好
没有完整源码很难推测哪里有问题...


既然这种立 ...
昨天与soul1000测试了下,结果发现整数我做了提前优化的关系,即我做了当alpha,beta等于0,255时,化简了公式,所以与浮点产生了差别

对于colordodge,softlight,那就以ps为标准,本来想提供选项SVG 2004,SVG 2009的

BlendComposite是有Subtractive的

case SUBTRACT:
                    return new Blender() {
                        @Override
                        public void blend(int[] src, int[] dst, int[] result) {
                            result[0] = Math.max(0, src[0] + dst[0] - 256);
                            result[1] = Math.max(0, src[1] + dst[1] - 256);
                            result[2] = Math.max(0, src[2] + dst[2] - 256);
                            result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
                        }
                    };

                    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;

1st计算出2nd需要的result,问题是2nd里的alpha,在我这里应该是result的alpha,它原来是自定义的预乘系数
引用:
原帖由 sfsuvival 于 2010-04-05 01:16 发表
http://www.java2s.com/Code/Java/ ... ndCompositeDemo.htm
这是你找到的BlendComposite源码来源?




2nd里的alpha应该是指整张图层的opacity
不是指像素内的alpha值
现在DirectMuxer设所有 ...
是,来自官方的swinglabs,http://swingx.dev.java.net/

那算法里面的alpha,是自定义的图层alpha,如果写成我这里的情况,应该是结构图的alpha吧

明天测试看减法

[ 本帖最后由 haibara 于 2010-04-05 12:25 编辑 ]
还有个大问题

目前按照SVG来的alpha blending虽然目测与ps的normal一样

但实际取读字节数据,有发现相当多的点的RGB不同呀

这个我烦恼了很长时间了
public int lineardodge() {
                Ra = Math.min(1D, Sa + Da);
                return (int) (Ra * 255);
        }

        public int lineardodge(int src, int dest) {
                Sc = Math.min(1D, (src / 255D) + (dest / 255D));
                Dc = dest / 255D;
                Sca = Sa * Sc;
                Dca = Da * Dc;
                return (int) ((Sca + Dca * (1 - Sa)) / Ra * 255);
        }

        public int linearburn() {
                Ra = Sa + Da - Sa * Da;
                return (int) (Ra * 255);
        }

        public int linearburn(int src, int dest) {
                Sc = Math.max(0D, (src / 255D) + (dest / 255D) - 1D);
                Dc = dest / 255D;
                Sca = Sa * Sc;
                Dca = Da * Dc;
                return (int) ((Sca + Dca * (1 - Sa)) / Ra * 255);
        }

以上猜测虽然目测很象PS了,但是总有小部分不一样

下面我看IM的源码写了lineardodge

        private final long QuantumRange = 65535L;
        private final double QuantumScale = 1D / 65535L;
        private final double MagickEpsilon = 1.0e-10;

        public int lineardodge() {               
                  Sa=1D-QuantumScale*alpha;
                  Da=1D-QuantumScale*beta;
                  gamma=RoundToUnity(Sa+Da-Sa*Da);
                  return (int) (QuantumRange*(1D-gamma));  
        }

        public int lineardodge(int src, int dest) {
                  gamma=1D/(Math.abs(gamma) <= MagickEpsilon ? 1D : gamma);
                  return (int) (gamma*(src*Sa+dest*Da));
        }

        private double RoundToUnity(double value) {
                return (value < 0D ? 0D : (value > 1D) ? 1D : value);
        }

我觉得应该是等价的,但是合成出来差太多了,不知怎么搞的

IM源码:
static inline void CompositeLinearDodge(const MagickPixelPacket *p,
  const MagickRealType alpha,const MagickPixelPacket *q,
  const MagickRealType beta,MagickPixelPacket *composite)
{
  MagickRealType
    Da,
    gamma,
    Sa;

  Sa=1.0-QuantumScale*alpha;  /* simplify and speed up equations */
  Da=1.0-QuantumScale*beta;
  gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
  /*
    Operation performed directly - not need for sub-routine.
  */
  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
  composite->red=gamma*(p->red*Sa+q->red*Da);
  composite->green=gamma*(p->green*Sa+q->green*Da);
  composite->blue=gamma*(p->blue*Sa+q->blue*Da);
  if (q->colorspace == CMYKColorspace)
    composite->index=gamma*(p->index*Sa+q->index*Da);
}

[ 本帖最后由 haibara 于 2010-04-06 22:58 编辑 ]
引用:
原帖由 sfsuvival 于 2010-04-07 00:23 发表

看不懂你为何将部分blending先算到Sc内...


你这个是每通道16位的定义
每通道8位的话
QuantumRange = 255
QuantumScale = 1 / 255
MagickEpsilon = 1.0e-6

参考:
http://www.imagemagick.org/RMagick/ ...
因为我看blendcomposite是先混合出result再与dest进行blending的

奇怪,我搜索的怎么是那样的(/www/api/MagickCore/magick-type_8h.html),不过即使换成8位,结果仍然很大不同

[ 本帖最后由 haibara 于 2010-04-07 07:15 编辑 ]
引用:
原帖由 sfsuvival 于 2010-04-08 19:23 发表


不是指这段吧...

我找不到其它先混合出result再与dest进行blending的地方...

IM可能还有其它处理
只用CompositeLinearDodge做不到效果...
case SUBTRACT:
                    return new Blender() {
                        @Override
                        public void blend(int[] src, int[] dst, int[] result) {
                            result[0] = Math.max(0, src[0] + dst[0] - 256);
                            result[1] = Math.max(0, src[1] + dst[1] - 256);
                            result[2] = Math.max(0, src[2] + dst[2] - 256);
                            result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
                        }
                    };

这部是是linearburn

                    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;

这部是alpha blending


不过,其实不要紧,我搞定了


public int lineardodge() {
                Ra = RoundToUnity(Sa + Da);
                return (int) (Ra * 255);
        }

        public int lineardodge(int src, int dest) {
                Sc = src / 255D;
                Dc = dest / 255D;
                Sca = Sa * Sc;
                Dca = Da * Dc;
                return (int) (RoundToUnity(Sca + Dca) / Ra * 255);
        }

        public int linearburn() {
                Ra = Sa + Da - Sa * Da;
                return (int) (Ra * 255);
        }

        public int linearburn(int src, int dest) {
                Sc = src / 255D;
                Dc = dest / 255D;
                Sca = Sa * Sc;
                Dca = Da * Dc;
                return (int) (RoundToUnity(Sca + Dca - Sa * Da) / Ra * 255);
        }

目测与PS一样了,linearburn把f=Sc+Dc-1代入SVG那个公式,并设x,y,z=1(我猜的)
lineardodge其实就是plus,只不过原来没做区间验证,所以有问题,不过我看不懂公式怎么计算出Sa + Da的?

[ 本帖最后由 haibara 于 2010-04-08 21:15 编辑 ]
sfsuvival, 我想问你的PSD是怎么做

如何正确解析TXT中的合成关系?有什么公式吗
opacity:指的是当前图层的opacity吧
查看积分策略说明

快速回复主题

选项

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

当前时区 GMT+8, 现在时间是 2024-04-26 06:36

Processed in 0.016313 second(s), 6 queries.