Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Actionscript 3 在Flash编译目标中高效地异或两个图像_Actionscript 3_Flash_Shader_Haxe_Pixel Bender - Fatal编程技术网

Actionscript 3 在Flash编译目标中高效地异或两个图像

Actionscript 3 在Flash编译目标中高效地异或两个图像,actionscript-3,flash,shader,haxe,pixel-bender,Actionscript 3,Flash,Shader,Haxe,Pixel Bender,我需要对两个BitmapData对象进行异或运算 我用Haxe编写,使用flash.*库和AS3编译目标 我研究过HxSL和PixelBender,它们似乎都没有按位异或运算符,也没有任何其他可用于创建异或的按位运算符(但我是否遗漏了一些明显的东西?我会接受任何答案,只要它给出了一种只使用HxSL或PixelBlender中可用的整数/浮点运算符和函数进行位异或的方法) 我能找到的Flash中的预定义过滤器或着色器似乎都不能对两个图像进行异或(但是,我是否遗漏了一些明显的东西?异或可以与其他过滤

我需要对两个
BitmapData
对象进行异或运算

我用Haxe编写,使用
flash.*
库和AS3编译目标

我研究过HxSL和PixelBender,它们似乎都没有按位异或运算符,也没有任何其他可用于创建异或的按位运算符(但我是否遗漏了一些明显的东西?我会接受任何答案,只要它给出了一种只使用HxSL或PixelBlender中可用的整数/浮点运算符和函数进行位异或的方法)

我能找到的Flash中的预定义过滤器或着色器似乎都不能对两个图像进行异或(但是,我是否遗漏了一些明显的东西?异或可以与其他过滤器组合使用)

我找不到比XOR drawmode更适合将东西绘制到其他东西上的东西(但这并不意味着它不存在!如果它存在的话,这也会起作用!)

目前我唯一能找到的方法是在图像上逐像素循环,但即使在速度很快的机器上,每幅图像也需要几秒钟的时间,而我在其他图像处理操作中使用的过滤器的速度要快上百倍


有没有更快的方法?

有一些可能的选项,具体取决于您想要实现的目标(例如,是每个通道的XOR还是仅仅是非黑色的任何像素?)

  • 有一个可以为您提供有关这两个位图的大量信息。您可以在比较之前输入数据

  • 另一个选项是使用与将两幅图像绘制到相同的
    BitmapData
    实例中。这将显示两幅图像之间的差异(相当于Photoshop中的差异混合模式)

  • 如果您需要检查任何像素是否为非黑色,则可以尝试先运行一个,然后使用上述两幅图像的差分混合模式绘制结果

  • 你这样做是为了图像处理还是像每像素点击检测


    首先,我要看一看,看看有什么可以玩。

    有一些可能的选项,这取决于您想要实现的目标(例如,是每个通道的XOR还是任何非黑色像素?)

  • 有一个可以为您提供有关这两个位图的大量信息。您可以在比较之前输入数据

  • 另一个选项是使用与将两幅图像绘制到相同的
    BitmapData
    实例中。这将显示两幅图像之间的差异(相当于Photoshop中的差异混合模式)

  • 如果您需要检查任何像素是否为非黑色,则可以尝试先运行一个,然后使用上述两幅图像的差分混合模式绘制结果

  • 你这样做是为了图像处理还是像每像素点击检测

    首先,我要看一看,看看有什么可以玩。

    编辑: 再仔细研究一下,我发现在我的机器上,删除循环中的条件和额外的向量访问可以将速度提高100毫秒左右

    这是前面的XOR循环:

    // Original Vector XOR code:
    for (var i: int = 0; i < len; i++) {
        // XOR.
        result[i] = vec1[i] ^ vec2[i];
    
        if (ignoreAlpha) {
            // Force alpha of FF so we can see the result.
            result[i] |= 0xFF000000;
        }
    }
    
    确认它是正确的:

    // Do it for each RGBA channel.
    // Each channel is assumed to be 8bits.
    function XOR(x, y){
        var result = 0;
        var bitCount = 8;   // log2(x) + 1
        for (var n = 0; n < bitCount; n++) {
            var pow2 = pow(2, n);
    
            var x1 = mod(floor(x / pow2), 2);
            var y1 = mod(floor(y / pow2), 2);
    
            var z1 = mod(x1 + y1, 2);
            result += pow2 * z1;
        }
    
        console.log('XOR(%s, %s) = %s', x, y, result);
        console.log('%s ^ %s = %s', x, y, (x ^ y));
    
        return result;
    }
    
    // Split out these functions so it's
    // easier to convert to PixelBender.
    function mod(x, y){
        return x % y;
    }
    
    function pow(x, y){
        return Math.pow(x, y);
    }
    
    function floor(x){
        return Math.floor(x);
    }
    
    // Test the manual XOR is correct.
    XOR(255, 85);   // 170
    XOR(170, 85);   // 255
    XOR(170, 170);  // 0
    
    然后,我使用一系列宏展开循环,将JavaScript转换为PixelBender:

    // Bitwise algorithm was adapted from the "mathematical equivalents" formula on Wikipedia:
    // http://en.wikipedia.org/wiki/Bitwise_operation#Mathematical_equivalents
    
    // Macro for 2^n (it needs to be done a lot).
    #define POW2(n) pow(2.0, n)
    
    // Slight optimisation for the zeroth case - 2^0 = 1 is redundant so remove it.
    #define XOR_i_0(x, y) ( mod( mod(floor(x), 2.0) + mod(floor(y), 2.0), 2.0 ) )
    // Calculations for a given "iteration".
    #define XOR_i(x, y, i) ( POW2(i) * ( mod( mod(floor(x / POW2(i)), 2.0) + mod(floor(y / POW2(i)), 2.0), 2.0 ) ) )
    
    // Flash doesn't support loops.
    // Unroll the loop by defining macros that call the next macro in the sequence.
    // Adapted from: http://www.simppa.fi/blog/category/pixelbender/
    // http://www.simppa.fi/source/LoopMacros2.pbk
    #define XOR_0(x, y) XOR_i_0(x, y)
    #define XOR_1(x, y) XOR_i(x, y, 1.0) + XOR_0(x, y)
    #define XOR_2(x, y) XOR_i(x, y, 2.0) + XOR_1(x, y)
    #define XOR_3(x, y) XOR_i(x, y, 3.0) + XOR_2(x, y)
    #define XOR_4(x, y) XOR_i(x, y, 4.0) + XOR_3(x, y)
    #define XOR_5(x, y) XOR_i(x, y, 5.0) + XOR_4(x, y)
    #define XOR_6(x, y) XOR_i(x, y, 6.0) + XOR_5(x, y)
    #define XOR_7(x, y) XOR_i(x, y, 7.0) + XOR_6(x, y)
    
    // Entry point for XOR function.
    // This will calculate the XOR the current pixels.
    #define XOR(x, y) XOR_7(x, y)
    
    // PixelBender uses floats from 0.0 to 1.0 to represent 0 to 255
    // but the bitwise operations above work on ints.
    // These macros convert between float and int values.
    #define FLOAT_TO_INT(x) float(x) * 255.0
    #define INT_TO_FLOAT(x) float(x) / 255.0
    
    evaluatePixel
    函数中当前像素的每个通道的异或:

    void evaluatePixel()
    {
        // Acquire the pixel values from both images at the current location.
        float4 frontPixel = sampleNearest(inputImage, outCoord());
        float4 backPixel = sampleNearest(diffImage, outCoord());
    
        // Set up the output variable - RGBA.
        pixel4 result = pixel4(0.0, 0.0, 0.0, 1.0);
    
        // XOR each channel.
        result.r = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.r), FLOAT_TO_INT(backPixel.r)) );
        result.g = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.g), FLOAT_TO_INT(backPixel.g)) );
        result.b = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.b), FLOAT_TO_INT(backPixel.b)) );
    
        // Return the result for this pixel.
        dst = result;
    }
    

    ActionScript解决方案 2.BitmapData.getVector() 我发现最快的解决方案是从两幅图像中提取一个
    向量
    ,然后在ActionScript中执行XOR

    对于相同的两个3200x1400,这大约需要480-500毫秒

    package diff
    {
        import flash.display.Bitmap;
        import flash.display.DisplayObject;
        import flash.display.IBitmapDrawable;
        import flash.display.BitmapData;
        import flash.geom.Rectangle;
        import flash.utils.ByteArray;
    
    
        /**
         * @author Coridyn
         */
        public class BitDiff
        {
    
            /**
             * Perform a binary diff between two images.
             * 
             * Return the result as a Vector of uints (as used by BitmapData).
             * 
             * @param   image1
             * @param   image2
             * @param   ignoreAlpha
             * @return
             */
            public static function diffImages(image1: DisplayObject,
                                              image2: DisplayObject,
                                              ignoreAlpha: Boolean = true): Vector.<uint> {
    
                // For simplicity get the smallest common width and height of the two images
                // to perform the XOR.
                var w: Number = Math.min(image1.width, image2.width);
                var h: Number = Math.min(image1.height, image2.height);
                var rect: Rectangle = new Rectangle(0, 0, w, h);
    
                var vec1: Vector.<uint> = BitDiff.getVector(image1, rect);
                var vec2: Vector.<uint> = BitDiff.getVector(image2, rect);
    
                var resultVec: Vector.<uint> = BitDiff.diffVectors(vec1, vec2, ignoreAlpha);
                return resultVec;
            }
    
    
            /**
             * Extract a portion of an image as a Vector of uints.
             * 
             * @param   drawable
             * @param   rect
             * @return
             */
            public static function getVector(drawable: DisplayObject, rect: Rectangle): Vector.<uint> {
                var data: BitmapData = BitDiff.getBitmapData(drawable);
                var vec: Vector.<uint> = data.getVector(rect);
                data.dispose();
                return vec;
            }
    
    
            /**
             * Perform a binary diff between two streams of pixel data.
             * 
             * If `ignoreAlpha` is false then will not normalise the 
             * alpha to make sure the pixels are opaque.
             * 
             * @param   vec1
             * @param   vec2
             * @param   ignoreAlpha
             * @return
             */
            public static function diffVectors(vec1: Vector.<uint>,
                                               vec2: Vector.<uint>,
                                               ignoreAlpha: Boolean): Vector.<uint> {
    
                var larger: Vector.<uint> = vec1;
                if (vec1.length < vec2.length) {
                    larger = vec2;
                }
    
                var len: Number = Math.min(vec1.length, vec2.length),
                    result: Vector.<uint> = new Vector.<uint>(len, true);
    
                var alphaMask = 0;
                if (ignoreAlpha) {
                    // Force alpha of FF so we can see the result.
                    alphaMask = 0xFF000000;
                }
    
                // Assume same length.
                for (var i: int = 0; i < len; i++) {
                    // XOR.
                    result[i] = alphaMask | (vec1[i] ^ vec2[i]);
                }
    
                if (vec1.length != vec2.length) {
                    // Splice the remaining items.
                    result = result.concat(larger.slice(len));
                }
    
                return result;
            }
    
        }
    
    }
    
    4.BitmapData.getPixels() 我的最后一个测试是尝试迭代两个
    字节数组
    像素数据(非常类似于上面的
    向量
    解决方案)。这个实现也花费了大约1200ms

    for (var y: int = 0; y < h; y++) {
        for (var x: int = 0; x < w; x++) {
            sourcePixel = bd1.getPixel32(x, y);
            resultPixel = sourcePixel ^ bd2.getPixel(x, y);
            result.setPixel32(x, y, resultPixel);
        }
    }
    
    /**
     * Extract a portion of an image as a Vector of uints.
     * 
     * @param   drawable
     * @param   rect
     * @return
     */
    public static function getByteArray(drawable: DisplayObject, rect: Rectangle): ByteArray {
        var data: BitmapData = BitDiff.getBitmapData(drawable);
        var pixels: ByteArray = data.getPixels(rect);
        data.dispose();
        return pixels;
    }
    
    
    /**
     * Perform a binary diff between two streams of pixel data.
     * 
     * If `ignoreAlpha` is false then will not normalise the 
     * alpha to make sure the pixels are opaque.
     * 
     * @param   ba1
     * @param   ba2
     * @param   ignoreAlpha
     * @return
     */
    public static function diffByteArrays(ba1: ByteArray,
                                          ba2: ByteArray,
                                          ignoreAlpha: Boolean): ByteArray {
    
        // Reset position to start of array.
        ba1.position = 0;
        ba2.position = 0;
    
        var larger: ByteArray = ba1;
        if (ba1.bytesAvailable < ba2.bytesAvailable) {
            larger = ba2;
        }
    
        var len: Number = Math.min(ba1.length / 4, ba2.length / 4),
            result: ByteArray = new ByteArray();
    
        // Assume same length.
        var resultPixel:uint;
        for (var i: uint = 0; i < len; i++) {
            // XOR.
            resultPixel = ba1.readUnsignedInt() ^ ba2.readUnsignedInt();
            if (ignoreAlpha) {
                // Force alpha of FF so we can see the result.
                resultPixel |= 0xFF000000;
            }
    
            result.writeUnsignedInt(resultPixel);
        }
    
        // Seek back to the start.
        result.position = 0;
        return result;
    }
    
    /**
    *提取图像的一部分作为UINT向量。
    * 
    *@param可绘制
    *@param rect
    *@返回
    */
    公共静态函数getByteArray(drawable:DisplayObject,rect:Rectangle):ByteArray{
    变量数据:BitmapData=BitDiff.getBitmapData(可绘制);
    变量像素:ByteArray=data.getPixels(rect);
    data.dispose();
    返回像素;
    }
    /**
    *在两个像素数据流之间执行二进制差异。
    * 
    *如果'ignoreAlpha'为false,则不会使
    *alpha以确保像素不透明。
    * 
    *@param ba1
    *@param ba2
    *@param ignoreAlpha
    *@返回
    */
    公共静态函数diffbytearray(ba1:ByteArray,
    ba2:拜蒂雷,
    ignoreAlpha:布尔):ByteArray{
    //将位置重置为阵列的开始位置。
    ba1.position=0;
    ba2.0位=0;
    var较大:ByteArray=ba1;
    if(ba1.bytesavable
    编辑: 再仔细研究一下,我发现在我的机器上,删除循环中的条件和额外的向量访问可以将速度提高100毫秒左右

    这是前面的XOR循环:

    // Original Vector XOR code:
    for (var i: int = 0; i < len; i++) {
        // XOR.
        result[i] = vec1[i] ^ vec2[i];
    
        if (ignoreAlpha) {
            // Force alpha of FF so we can see the result.
            result[i] |= 0xFF000000;
        }
    }
    
    确认它是正确的:

    // Do it for each RGBA channel.
    // Each channel is assumed to be 8bits.
    function XOR(x, y){
        var result = 0;
        var bitCount = 8;   // log2(x) + 1
        for (var n = 0; n < bitCount; n++) {
            var pow2 = pow(2, n);
    
            var x1 = mod(floor(x / pow2), 2);
            var y1 = mod(floor(y / pow2), 2);
    
            var z1 = mod(x1 + y1, 2);
            result += pow2 * z1;
        }
    
        console.log('XOR(%s, %s) = %s', x, y, result);
        console.log('%s ^ %s = %s', x, y, (x ^ y));
    
        return result;
    }
    
    // Split out these functions so it's
    // easier to convert to PixelBender.
    function mod(x, y){
        return x % y;
    }
    
    function pow(x, y){
        return Math.pow(x, y);
    }
    
    function floor(x){
        return Math.floor(x);
    }
    
    // Test the manual XOR is correct.
    XOR(255, 85);   // 170
    XOR(170, 85);   // 255
    XOR(170, 170);  // 0
    
    然后,我使用一系列宏展开循环,将JavaScript转换为PixelBender:

    // Bitwise algorithm was adapted from the "mathematical equivalents" formula on Wikipedia:
    // http://en.wikipedia.org/wiki/Bitwise_operation#Mathematical_equivalents
    
    // Macro for 2^n (it needs to be done a lot).
    #define POW2(n) pow(2.0, n)
    
    // Slight optimisation for the zeroth case - 2^0 = 1 is redundant so remove it.
    #define XOR_i_0(x, y) ( mod( mod(floor(x), 2.0) + mod(floor(y), 2.0), 2.0 ) )
    // Calculations for a given "iteration".
    #define XOR_i(x, y, i) ( POW2(i) * ( mod( mod(floor(x / POW2(i)), 2.0) + mod(floor(y / POW2(i)), 2.0), 2.0 ) ) )
    
    // Flash doesn't support loops.
    // Unroll the loop by defining macros that call the next macro in the sequence.
    // Adapted from: http://www.simppa.fi/blog/category/pixelbender/
    // http://www.simppa.fi/source/LoopMacros2.pbk
    #define XOR_0(x, y) XOR_i_0(x, y)
    #define XOR_1(x, y) XOR_i(x, y, 1.0) + XOR_0(x, y)
    #define XOR_2(x, y) XOR_i(x, y, 2.0) + XOR_1(x, y)
    #define XOR_3(x, y) XOR_i(x, y, 3.0) + XOR_2(x, y)
    #define XOR_4(x, y) XOR_i(x, y, 4.0) + XOR_3(x, y)
    #define XOR_5(x, y) XOR_i(x, y, 5.0) + XOR_4(x, y)
    #define XOR_6(x, y) XOR_i(x, y, 6.0) + XOR_5(x, y)
    #define XOR_7(x, y) XOR_i(x, y, 7.0) + XOR_6(x, y)
    
    // Entry point for XOR function.
    // This will calculate the XOR the current pixels.
    #define XOR(x, y) XOR_7(x, y)
    
    // PixelBender uses floats from 0.0 to 1.0 to represent 0 to 255
    // but the bitwise operations above work on ints.
    // These macros convert between float and int values.
    #define FLOAT_TO_INT(x) float(x) * 255.0
    #define INT_TO_FLOAT(x) float(x) / 255.0
    
    evaluatePixel
    函数中当前像素的每个通道的异或:

    void evaluatePixel()
    {
        // Acquire the pixel values from both images at the current location.
        float4 frontPixel = sampleNearest(inputImage, outCoord());
        float4 backPixel = sampleNearest(diffImage, outCoord());
    
        // Set up the output variable - RGBA.
        pixel4 result = pixel4(0.0, 0.0, 0.0, 1.0);
    
        // XOR each channel.
        result.r = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.r), FLOAT_TO_INT(backPixel.r)) );
        result.g = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.g), FLOAT_TO_INT(backPixel.g)) );
        result.b = INT_TO_FLOAT ( XOR(FLOAT_TO_INT(frontPixel.b), FLOAT_TO_INT(backPixel.b)) );
    
        // Return the result for this pixel.
        dst = result;
    }
    

    ActionScript解决方案 2.