如何对位图数据进行洗牌?

3

我被要求制作一个程序,该程序可以获取一张图片,读取位图数据然后随机化图片。

我尝试了简单地将“字符串”按每个“空格”进行分割并打乱顺序,但是图片会损坏。你有什么好的想法吗?

我可以使用Cocoa、ActionScript 3、JavaScript或PHP实现这个程序。

基本上只要我能在Mac上使用,我的客户就很满意 :)


这个概念基本上是将原始位图切割成一个虚拟的网格,例如10x10个块。然后使用循环遍历单元格并创建一个新的位图来采样给定的单元格。在此过程结束时,您将拥有一堆位图,它们共同组成您的原始位图,您可以分别移动和重新排列它们。 - Marty
哦,就像我们小时候玩的那个翻转方块游戏一样。这并不像我想象的那么容易,但还是相当简单的,现在我会投入到代码中去的 =)谢谢。 - Ricardo Cerqueira
如果你遇到了问题,请更新你的问题并附上你最终使用的代码,让我知道 - 我很乐意从那里帮助你解决问题。 - Marty
1
谢谢你,伙计,但现在不需要了 :) 我已经成功地将图像分成了瓷砖,现在我只需要让它们随机排列。我正在使用ActionScript3来完成这个任务,明天我会完成代码。感谢你的帮助 :) - Ricardo Cerqueira
请务必将解决方案发布为此问题的答案,以帮助未来的访问者。 - Marty
一旦完成,我会立即做到的 :) - Ricardo Cerqueira
2个回答

0

使用JavaScript对图像进行逐个平铺的洗牌解决方案:http://fiddle.jshell.net/upgradellc/53wKG/show/ 编辑:http://jsfiddle.net/upgradellc/53wKG/

  /* Script copyright Max @ www.upgradeyour.com - if it is used or modified, this message must remain intact! */
            $( document ).ready( function() {
                var imgData1 = 'img_url_or_base64';
                new ImageShuffler( imgData1, 3 );
                new ImageShuffler( imgData1, 5 );
                new ImageShuffler( imgData1, 10 );
            } );
            function ImageShuffler( imgUrl, numberOfSquares, elementToAddTo ) {
                var that = this;
                this.url = imgUrl;
                this.numberOfSquares = numberOfSquares;
                this.elementToAddTo = elementToAddTo || $( 'body' );
                this.holder = $( '<div></div>' ).appendTo( $( this.elementToAddTo ) )[0];
                this.c1 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
                this.c2 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
                this.img = $( '<img src="' + this.url + '">' ).prependTo( $( this.holder ) )[0];
                this.img.onload = function() {
                    that.doShuffleImage()
                };
            }
            ImageShuffler.prototype.doShuffleImage = function() {
                this.widthOfSquares = Math.ceil( this.img.width / this.numberOfSquares );
                this.heightOfSquares = Math.ceil( this.img.height / this.numberOfSquares );
                var extrax = (this.img.width - this.widthOfSquares * this.numberOfSquares);
                var extray = (this.img.height - this.heightOfSquares * this.numberOfSquares);
                var width = this.removeExtraPixels( this.img.width, extrax, this.widthOfSquares );
                var height = this.removeExtraPixels( this.img.height, extray, this.heightOfSquares );
                this.c1.width = this.c2.width = width;
                this.c1.height = this.c2.height = height;

                this.c1c = this.c1.getContext( '2d' );
                this.c2c = this.c2.getContext( '2d' );
                this.c1c.drawImage( this.img, 0, 0, this.img.width, this.img.height );
                var tlc = this.c1c.getImageData( this.img.width - 1, this.img.height - 1, 1, 1 ).data;
                this.c1c.fillStyle = "rgb(" + tlc[0] + "," + tlc[1] + "," + tlc[2] + ");";
                this.c1c.fillRect( 0, 0, this.c1.width, this.c1.height );
                this.c1c.drawImage( this.img, 0, 0, this.img.width, this.img.height );
                this.shuffleAll();
            };
            ImageShuffler.prototype.shuffleAll = function() {
                this.c2c.putImageData( this.c1c.getImageData( 0, 0, this.c1.width, this.c1.height ), 0, 0 );
                //this.c1c.getImageData( 0, 0, this.img.width, this.img.height );
                var timesToShuffle = Math.pow( this.numberOfSquares, 2 );
                for( var count = 0; count < timesToShuffle; count++ ) {
                    p1 = {x: rand( this.c2.width, this.widthOfSquares ), y: rand( this.c2.height, this.heightOfSquares )};
                    p2 = {x: rand( this.c2.width, this.widthOfSquares ), y: rand( this.c2.height, this.heightOfSquares )};
                    if( p1.x + this.widthOfSquares < this.c2.width ) {
                        this.swapTile( p1.x, p1.y, p2.x, p2.y );
                    }
                }
            };
            ImageShuffler.prototype.swapTile = function( x1, y1, x2, y2 ) {
                tile1 = this.c2c.getImageData( x1, y1, this.widthOfSquares, this.heightOfSquares );
                tile2 = this.c2c.getImageData( x2, y2, this.widthOfSquares, this.heightOfSquares );
                this.c2c.putImageData( tile1, x2, y2 );
                this.c2c.putImageData( tile2, x1, y1 );
            };

            ImageShuffler.prototype.removeExtraPixels = function( currentLength, extraPixels, sizeOfSquare ) {
                if( extraPixels < 0 ) {
                    return currentLength + (-1 * extraPixels);
                }
                if( extraPixels > 0 ) {
                    return currentLength + sizeOfSquare - extraPixels;
                }
                return currentLength;
            };

            //returns a random number below max which is a multiple of increment
            function rand( max, increment ) {
                return Math.floor( Math.random() * Math.ceil( max / increment ) ) * increment;
            }

在JavaScript中对图像中的所有像素进行洗牌的解决方案: http://jsfiddle.net/upgradellc/2LJwH/1/
        /* Script copyright Max @ www.upgradeyour.com - if it is used or modified, this message must remain intact! */
        $( document ).ready( function() {
            var imgData1 = '/img/logo.png';
            new ImageShuffler( imgData1 );
        } );
        function ImageShuffler( imgUrl, elementToAddTo ) {
            var that = this;
            this.url = imgUrl;
            this.elementToAddTo = elementToAddTo || $( 'body' );
            this.holder = $( '<div></div>' ).appendTo( $( this.elementToAddTo ) )[0];
            console.log( this.holder );
            this.c1 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
            this.c2 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
            this.img = $( '<img src="' + this.url + '">' ).prependTo( $( this.holder ) )[0];
            this.img.onload = function() {
                that.doShuffleImage()
            };
        }
        ImageShuffler.prototype.doShuffleImage = function() {
            this.c1.width = this.c2.width = this.img.width;
            this.c1.height = this.c2.height = this.img.height;
            this.c1c = this.c1.getContext( '2d' );
            this.c2c = this.c2.getContext( '2d' );
            this.c1c.drawImage( this.img, 0, 0, this.img.width, this.img.height );
            this.c2c.putImageData( shuffleArray( this.c1c.getImageData( 0, 0, this.img.width, this.img.height ) ), 0, 0 );
        };

        //shuffles the data array
        function shuffleArray( arr ) {
            var length = arr.data.length;
            for( x = 0; x < length; x++ ) {
                var p1x = rand( length, 4 ), p2x = rand( length, 4 );
                var p1r = arr.data[p1x];
                var p1g = arr.data[p1x + 1];
                var p1b = arr.data[p1x + 2];
                var p1a = arr.data[p1x + 3];
                for( i = 0; i < 3; i++ ) {
                    arr.data[p2x + i] = arr.data[p1x + i];
                }
                arr.data[p2x] = p1r;
                arr.data[p2x + 1] = p1g;
                arr.data[p2x + 2] = p1b;
                arr.data[p2x + 3] = p1a;
            }
            return arr;
        }

        //returns a random number below max which is a multiple of increment
        function rand( max, increment ) {
            return Math.floor( Math.random() * Math.ceil( max / increment ) ) * increment;
        }

谢谢,我开始用Flash做这个,但你的解决方案也很不错 :D - Ricardo Cerqueira

0

这是我的ActionScript 3解决方案,但对于大型图像,程序运行速度相当慢,因此可能需要进行一些优化,尽管处理速度仍将根据图像大小而异。

  1. 显示原始位图。
  2. 从原始图像中读取和存储位图数据(像素颜色)到2D向量中。
  3. 将2D向量压平以混淆数据,然后恢复2D向量。
  4. 使用来自2D向量的混淆数据绘制和显示位图数据。

enter image description here

package 
{
    //Imports
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;

    //Class
    [SWF(width = "1150", height = "600", frameRate = "60", backgroundColor = "0x000000")]
    public class Main extends Sprite 
    {
        //Asset
        [Embed(source = "../assets/AdobeFlashLogo.png")]  // 500 x 500 pixels
        private var Image:Class;

        //Properties
        private var originalImage:Bitmap;

        //Constructor
        public function Main():void 
        {
            init();         
        }

        //Init
        private function init():void
        {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            displayOriginalImage();
            displayShuffledImage();
        }

        //Display Original Image
        private function displayOriginalImage():void
        {
            originalImage = new Image() as Bitmap;          
            originalImage.x = originalImage.y = 50;

            addChild(originalImage);
        }

        //Display Shuffled Image
        private function displayShuffledImage():void
        {
            var pixelData:Vector.<Vector.<uint>> = shufflePixelData(getPixelData(originalImage));

            var shuffledImageData:BitmapData = new BitmapData(originalImage.width, originalImage.height);

            for (var i:uint = 0; i < originalImage.width; i++)
            {
                for (var j:uint = 0; j < originalImage.height; j++)
                {
                    shuffledImageData.setPixel32(i, j, pixelData[i][j]);
                }
            }

            var shuffledImage:Bitmap = new Bitmap(shuffledImageData);
            shuffledImage.x = originalImage.x + originalImage.width + 50;
            shuffledImage.y = originalImage.y;

            addChild(shuffledImage);
        }

        //Get Pixel Data
        private function getPixelData(image:Bitmap):Vector.<Vector.<uint>>
        {
            var result:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>;

            for (var i:uint = 0; i < originalImage.width; i++)
            {
                result[i] = new Vector.<uint>;

                for (var j:uint = 0; j < originalImage.height; j++)
                {
                    result[i][j] = originalImage.bitmapData.getPixel32(i, j);
                }
            }

            return result;
        }

        //Shuffle Pixel Data
        private function shufflePixelData(pixelData:Vector.<Vector.<uint>>):Vector.<Vector.<uint>>
        {
            var i:uint;
            var j:uint;

            var imageWidth:uint = pixelData.length;
            var imageHeight:uint = pixelData[0].length;

            var flatData:Vector.<uint> = new Vector.<uint>;

            for (i = 0; i < imageWidth; i++)
            {
                for (j = 0; j < imageHeight; j++)
                {
                    flatData.push(pixelData[i][j]);
                }
            }   

            var shuffledData:Vector.<uint> = new Vector.<uint>;
            var totalPixels:uint = imageWidth * imageHeight;
            var randomIndex:uint;

            for (i = 0; i < totalPixels; i++)
            {
                randomIndex = Math.random() * flatData.length;
                shuffledData.push(flatData.splice(randomIndex, 1)[0]);              
            }

            var result:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>

            for (i = 0; i < imageWidth; i++)
            {
                result[i] = new Vector.<uint>;

                for (j = 0; j < imageHeight; j++)
                {
                    result[i][j] = shuffledData.shift();
                }
            }

            return result;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接