Sắp xếp lại các pixel trong ảnh để không thể nhận ra và sau đó lấy lại


86

Tạo một chương trình có thể sắp xếp lại các pixel trong ảnh để không thể nhận ra nó. Tuy nhiên, chương trình của bạn sẽ có thể chuyển đổi nó trở lại hình ảnh gốc.

Bạn có thể viết hai hàm - để mã hóa và giải mã, tuy nhiên một hàm được áp dụng nhiều lần sẽ cho ảnh gốc (ví dụ trong toán học - f(x) = 1 - x) là một phần thưởng.

Ngoài ra sản xuất một số mô hình trong đầu ra cũng cho tiền thưởng.

Hình ảnh có thể được biểu diễn dưới dạng mảng 1D / 2D hoặc đối tượng hình ảnh nếu ngôn ngữ của bạn hỗ trợ nó. Lưu ý rằng bạn chỉ có thể thay đổi thứ tự pixel!

Sẽ hợp lý khi chọn làm mã người chiến thắng tạo ra hình ảnh ít nhận dạng hơn, tuy nhiên tôi không biết cách đo chính xác, tất cả các cách tôi có thể tưởng tượng đều có thể bị lừa. Do đó, tôi đã chọn câu hỏi này để trở thành cuộc thi phổ biến - hãy để người dùng chọn câu trả lời hay nhất!

Hình ảnh thử nghiệm 1 (800 x 422 px): Hình ảnh thử nghiệm 2 (800 x 480 px): Vui lòng cung cấp với hình ảnh đầu ra mã.


Câu hỏi là một cách rất dài để nói "Viết một thuật toán mã hóa cho hình ảnh, với đầu ra là một hình ảnh."
David Richerby

3
@DavidR Richby, sử dụng cùng pixel / màu. Năm pixel đen trong "hình ảnh đơn giản" -> năm pixel đen trong "hình ảnh mật mã".
Daniel Beck

2
@ user2992539 Được rồi, trong trường hợp đó bạn có thể muốn tuyên bố rõ ràng rằng cái này được sử dụng làm bộ ngắt kết nối. Mặt khác, chỉ cần nói rằng đó là một phần thưởng không có ý nghĩa lắm.
Martin Ender

3
Câu hỏi này khiến tôi nghĩ về bản đồ mèo của Arnold . Tôi không nghĩ nó khá phù hợp cho mục đích này nhưng cũng thú vị theo cách tương tự - lặp lại bản đồ đủ lần sẽ đưa bạn trở lại hình ảnh ban đầu.
trichoplax

4
Bây giờ ở nơi khác trên mạng Stack Exchange: Security.SE của tất cả các nơi
Doorknob

Câu trả lời:


58

Python 2.7 (với PIL) - Không có giả danh

Tôi chia hình ảnh thành 2 khối 2 (bỏ qua phần còn lại) và xoay mỗi khối 180 độ, sau đó tôi làm tương tự với 3 khối 3, sau đó 4, v.v. cho đến một số tham số BLKSZ. Sau đó, tôi làm tương tự cho BLKSZ-1, rồi BLKSZ-2, tất cả các cách quay trở lại xuống 3, sau đó 2. Phương thức này tự đảo ngược chính xác; hàm xắp xếp lại là hàm xáo trộn.

:

from PIL import Image
import math

im = Image.open("ST1.png", "r")
arr = im.load() #pixel data stored in this 2D array

def rot(A, n, x1, y1): #this is the function which rotates a given block
    temple = []
    for i in range(n):
        temple.append([])
        for j in range(n):
            temple[i].append(arr[x1+i, y1+j])
    for i in range(n):
        for j in range(n):
            arr[x1+i,y1+j] = temple[n-1-i][n-1-j]


xres = 800
yres = 480
BLKSZ = 50 #blocksize
for i in range(2, BLKSZ+1):
    for j in range(int(math.floor(float(xres)/float(i)))):
        for k in range(int(math.floor(float(yres)/float(i)))):
            rot(arr, i, j*i, k*i)
for i in range(3, BLKSZ+1):
    for j in range(int(math.floor(float(xres)/float(BLKSZ+2-i)))):
        for k in range(int(math.floor(float(yres)/float(BLKSZ+2-i)))):
            rot(arr, BLKSZ+2-i, j*(BLKSZ+2-i), k*(BLKSZ+2-i))

im.save("ST1OUT "+str(BLKSZ)+".png")

print("Done!")

Tùy thuộc vào kích thước khối, bạn có thể thực hiện tính toán xóa tất cả sự tương đồng với hình ảnh gốc: (BLKSZ = 50) nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Hoặc làm cho tính toán hiệu quả: (BLKSZ = 10) nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


6
Âm thanh như kết quả tốt nhất sẽ là nếu BLKSZ sẽ có khoảng một nửa kích thước hình ảnh. Dù sao, tôi thích thuật toán và đối với BLKSZ nhỏ, nó trông giống như một nghệ thuật hiện đại! Mát mẻ!
Somnium

11
Tôi luôn upvote python.
qwr

Thay vì tranh giành tất cả các giá trị từ 2 đến 50, có lẽ bạn chỉ nên sử dụng các số nguyên tố?
Neil

@Neil Có lẽ sau đó nó sẽ trông ngẫu nhiên hơn và ít tính nghệ thuật hơn.
Somnium

Các BLKSZ = 10cảnh quan là thực sự mát mẻ!
wchargein

52

C #, Winform

Chỉnh sửa Thay đổi cách bạn điền vào mảng tọa độ, bạn có thể có các mẫu khác nhau - xem bên dưới

Bạn có thích loại mô hình này?

Phong cảnh

trừu tượng

Thêm:

Hét lên Gào thét

Trao đổi ngẫu nhiên chính xác một lần tất cả các pixel ở nửa trên với tất cả các pixel ở nửa dưới. Lặp lại quy trình tương tự để xắp xếp lại (tiền thưởng).

Scramble.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.IO;

namespace Palette
{
    public partial class Scramble : Form
    {
        public Scramble()
        {
            InitializeComponent();
        }

        public struct Coord
        {
            public int x, y;
        }

        private void Work(Bitmap srcb, Bitmap outb)
        {
            int w = srcb.Width, h = srcb.Height;
            Coord[] coord = new Coord[w * h];

            FastBitmap fsb = new FastBitmap(srcb);
            FastBitmap fob = new FastBitmap(outb);
            fsb.LockImage();
            fob.LockImage();
            ulong seed = 0;
            int numpix = 0;
            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; numpix++, x++)
                {
                    coord[numpix].x = x;
                    coord[numpix].y = y;
                    uint color = fsb.GetPixel(x, y);
                    seed += color;
                    fob.SetPixel(x, y, color);
                }
            fsb.UnlockImage();
            fob.UnlockImage();
            pbOutput.Refresh();
            Application.DoEvents();

            int half = numpix / 2;
            int limit = half;
            XorShift rng = new XorShift(seed);
            progressBar.Visible = true;
            progressBar.Maximum = limit;

            fob.LockImage();
            while (limit > 0)
            {
                int p = (int)(rng.next() % (uint)limit);
                int q = (int)(rng.next() % (uint)limit);
                uint color = fob.GetPixel(coord[p].x, coord[p].y); 
                fob.SetPixel(coord[p].x, coord[p].y, fob.GetPixel(coord[half+q].x, coord[half+q].y)); 
                fob.SetPixel(coord[half+q].x, coord[half+q].y, color); 
                limit--;
                if (p < limit)
                {
                    coord[p]=coord[limit];
                }
                if (q < limit)
                {
                    coord[half+q]=coord[half+limit];
                }
                if ((limit & 0xfff) == 0)
                {
                    progressBar.Value = limit;
                    fob.UnlockImage();
                    pbOutput.Refresh();
                    fob.LockImage();
                }
            }
            fob.UnlockImage();
            pbOutput.Refresh();
            progressBar.Visible = false; 
        }

        void DupImage(PictureBox s, PictureBox d)
        {
            if (d.Image != null)
                d.Image.Dispose();
            d.Image = new Bitmap(s.Image.Width, s.Image.Height);  
        }

        void GetImagePB(PictureBox pb, string file)
        {
            Bitmap bms = new Bitmap(file, false);
            Bitmap bmp = bms.Clone(new Rectangle(0, 0, bms.Width, bms.Height), PixelFormat.Format32bppArgb);
            bms.Dispose(); 
            if (pb.Image != null)
                pb.Image.Dispose();
            pb.Image = bmp;
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.InitialDirectory = "c:\\temp\\";
            openFileDialog.Filter = "Image Files(*.BMP;*.JPG;*.PNG)|*.BMP;*.JPG;*.PNG|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    string file = openFileDialog.FileName;
                    GetImagePB(pbInput, file);
                    pbInput.Tag = file;
                    DupImage(pbInput, pbOutput);
                    Work(pbInput.Image as Bitmap, pbOutput.Image as Bitmap);
                    file = Path.GetDirectoryName(file) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(file) + ".scr.png";
                    pbOutput.Image.Save(file);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
                }

            }
        }
    }

    //Adapted from Visual C# Kicks - http://www.vcskicks.com/
    unsafe public class FastBitmap
    {
        private Bitmap workingBitmap = null;
        private int width = 0;
        private BitmapData bitmapData = null;
        private Byte* pBase = null;

        public FastBitmap(Bitmap inputBitmap)
        {
            workingBitmap = inputBitmap;
        }

        public BitmapData LockImage()
        {
            Rectangle bounds = new Rectangle(Point.Empty, workingBitmap.Size);

            width = (int)(bounds.Width * 4 + 3) & ~3;

            //Lock Image
            bitmapData = workingBitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
            pBase = (Byte*)bitmapData.Scan0.ToPointer();
            return bitmapData;
        }

        private uint* pixelData = null;

        public uint GetPixel(int x, int y)
        {
            pixelData = (uint*)(pBase + y * width + x * 4);
            return *pixelData;
        }

        public uint GetNextPixel()
        {
            return *++pixelData;
        }

        public void GetPixelArray(int x, int y, uint[] Values, int offset, int count)
        {
            pixelData = (uint*)(pBase + y * width + x * 4);
            while (count-- > 0)
            {
                Values[offset++] = *pixelData++;
            }
        }

        public void SetPixel(int x, int y, uint color)
        {
            pixelData = (uint*)(pBase + y * width + x * 4);
            *pixelData = color;
        }

        public void SetNextPixel(uint color)
        {
            *++pixelData = color;
        }

        public void UnlockImage()
        {
            workingBitmap.UnlockBits(bitmapData);
            bitmapData = null;
            pBase = null;
        }
    }

    public class XorShift
    {
        private ulong x; /* The state must be seeded with a nonzero value. */

        public XorShift(ulong seed)
        {
            x = seed;
        }

        public ulong next()
        {
            x ^= x >> 12; // a
            x ^= x << 25; // b
            x ^= x >> 27; // c
            return x * 2685821657736338717L;
        }
    }
} 

Scramble.designer.cs

namespace Palette
{
    partial class Scramble
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.panel = new System.Windows.Forms.FlowLayoutPanel();
            this.pbInput = new System.Windows.Forms.PictureBox();
            this.pbOutput = new System.Windows.Forms.PictureBox();
            this.progressBar = new System.Windows.Forms.ProgressBar();
            this.btnOpen = new System.Windows.Forms.Button();
            this.panel.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pbInput)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.pbOutput)).BeginInit();
            this.SuspendLayout();
            // 
            // panel
            // 
            this.panel.AutoScroll = true;
            this.panel.AutoSize = true;
            this.panel.Controls.Add(this.pbInput);
            this.panel.Controls.Add(this.pbOutput);
            this.panel.Dock = System.Windows.Forms.DockStyle.Top;
            this.panel.Location = new System.Drawing.Point(0, 0);
            this.panel.Name = "panel";
            this.panel.Size = new System.Drawing.Size(748, 306);
            this.panel.TabIndex = 3;
            // 
            // pbInput
            // 
            this.pbInput.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.pbInput.Location = new System.Drawing.Point(3, 3);
            this.pbInput.MinimumSize = new System.Drawing.Size(100, 100);
            this.pbInput.Name = "pbInput";
            this.pbInput.Size = new System.Drawing.Size(100, 300);
            this.pbInput.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
            this.pbInput.TabIndex = 3;
            this.pbInput.TabStop = false;
            // 
            // pbOutput
            // 
            this.pbOutput.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.pbOutput.Location = new System.Drawing.Point(109, 3);
            this.pbOutput.MinimumSize = new System.Drawing.Size(100, 100);
            this.pbOutput.Name = "pbOutput";
            this.pbOutput.Size = new System.Drawing.Size(100, 300);
            this.pbOutput.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
            this.pbOutput.TabIndex = 4;
            this.pbOutput.TabStop = false;
            // 
            // progressBar
            // 
            this.progressBar.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.progressBar.Location = new System.Drawing.Point(0, 465);
            this.progressBar.Name = "progressBar";
            this.progressBar.Size = new System.Drawing.Size(748, 16);
            this.progressBar.TabIndex = 5;
            // 
            // btnOpen
            // 
            this.btnOpen.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.btnOpen.Location = new System.Drawing.Point(12, 429);
            this.btnOpen.Name = "btnOpen";
            this.btnOpen.Size = new System.Drawing.Size(53, 30);
            this.btnOpen.TabIndex = 6;
            this.btnOpen.Text = "Start";
            this.btnOpen.UseVisualStyleBackColor = true;
            this.btnOpen.Click += new System.EventHandler(this.btnOpen_Click);
            // 
            // Scramble
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.BackColor = System.Drawing.SystemColors.ControlDark;
            this.ClientSize = new System.Drawing.Size(748, 481);
            this.Controls.Add(this.btnOpen);
            this.Controls.Add(this.progressBar);
            this.Controls.Add(this.panel);
            this.Name = "Scramble";
            this.Text = "Form1";
            this.panel.ResumeLayout(false);
            this.panel.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.pbInput)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.pbOutput)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }


        private System.Windows.Forms.FlowLayoutPanel panel;
        private System.Windows.Forms.PictureBox pbOutput;
        private System.Windows.Forms.ProgressBar progressBar;
        private System.Windows.Forms.PictureBox pbInput;
        private System.Windows.Forms.Button btnOpen;
    }
}

Chương trình.cs

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Palette
{
  static class Program
  {
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Scramble());
    }
  }
}

Kiểm tra 'Mã không an toàn' trong thuộc tính dự án để biên dịch.

Mô hình phức tạp

Tranh giành

Thay đổi phần đầu tiên của chức năng làm việc, tối đa thành Application.DoEvents:

        int w = srcb.Width, h = srcb.Height;
        string Msg = "Scramble";

        Graphics gr = Graphics.FromImage(outb);

        Font f = new Font("Arial", 100, FontStyle.Bold);
        var size = gr.MeasureString(Msg, f);
        f = new Font("Arial", w / size.Width * 110, FontStyle.Bold);
        size = gr.MeasureString(Msg, f);
        gr.DrawString(Msg, f, new SolidBrush(Color.White), (w - size.Width) / 2, (h - size.Height) / 2);

        gr.Dispose();

        Coord[] coord = new Coord[w * h];
        FastBitmap fsb = new FastBitmap(srcb);
        FastBitmap fob = new FastBitmap(outb);
        fsb.LockImage();
        fob.LockImage();
        ulong seed = 1;
        int numpix = h * w;
        int c1 = 0, c2 = numpix;
        int y2 = h / 2;

        int p2 = numpix/2;

        for (int p = 0; p < p2; p++)
        {
            for (int s = 1; s > -2; s -= 2)
            {
                int y = (p2+s*p) / w;
                int x = (p2+s*p) % w;

                uint d = fob.GetPixel(x, y);
                if (d != 0)
                {
                    c2--;
                    coord[c2].x = x;
                    coord[c2].y = y;
                }
                else
                {
                    coord[c1].x = x;
                    coord[c1].y = y;
                    c1++;
                }
                fob.SetPixel(x, y, fsb.GetPixel(x, y));
            }
        }
        fsb.UnlockImage();
        fob.UnlockImage();
        pbOutput.Refresh();
        Application.DoEvents();

1
Thú vị) Tôi tự hỏi liệu với cách tiếp cận tương tự có thể tạo ra các mẫu phức tạp hơn trong đầu ra không.
Somnium

1
Ý tưởng hay - điều gì xảy ra với đường giữa khi có một số dòng lẻ?
flawr

1
@flawr sự phân chia là trên mỗi pixel. Nếu có một số pixel lẻ, cái cuối cùng sẽ không bị ảnh hưởng. Nếu có một số hàng lẻ, nửa bên trái của hàng giữa là 'phía trên' và nửa bên phải là 'phía dưới'.
edc65

1
@ user2992539 Tôi nghĩ bạn có thể chia nhỏ hơn - ngay cả bàn cờ. Với nhiều phân khu hơn, hình ảnh dễ nhận biết hơn.
edc65

7
Giống như phiên bản "Scramble" của bạn!)
Somnium

43

C, làm mờ tùy ý, dễ dàng đảo ngược

Đi dự tiệc muộn. Đây là mục của tôi!

Phương pháp này làm mờ tranh giành. Tôi gọi nó là scramblur . Nó vô cùng đơn giản. Trong một vòng lặp, nó chọn một pixel ngẫu nhiên và sau đó hoán đổi nó với một pixel gần đó được chọn ngẫu nhiên trong một mô hình canvas hình xuyến. Bạn chỉ định khoảng cách tối đa xác định "pixel lân cận" nghĩa là gì (1 có nghĩa là luôn chọn một pixel liền kề), số lần lặp và tùy chọn một hạt giống số ngẫu nhiên. Khoảng cách tối đa càng lớn và số lần lặp càng lớn, kết quả càng mờ.

Nó có thể đảo ngược bằng cách chỉ định một số lần lặp âm (đây đơn giản là sự tiện lợi của giao diện dòng lệnh; thực sự không có thứ gọi là lặp lại âm). Trong nội bộ, nó sử dụng LCPRNG 64 bit tùy chỉnh (trình tạo số giả ngẫu nhiên tuyến tính) và tạo trước một khối các giá trị. Bảng cho phép lặp qua khối hoặc tiến hoặc lùi để xáo trộn hoặc xắp xếp lại, tương ứng.

Bản giới thiệu

Đối với hai hình ảnh đầu tiên, khi bạn cuộn xuống, mỗi hình ảnh được làm mờ bằng cách sử dụng độ lệch tối đa cao hơn: Trên cùng là hình ảnh gốc (ví dụ: độ lệch 0 pixel), tiếp theo là 1, 2, 4, 8, 16, 32, 64 , 128 và cuối cùng là 256. Số lần lặp là 10⁶ = 1.000.000 cho tất cả các hình ảnh bên dưới.

Đối với hai hình ảnh thứ hai, mỗi hình ảnh được làm mờ bằng cách sử dụng độ lệch thấp dần dần - ví dụ: mờ nhất đến mờ nhất - từ độ lệch tối đa 256 xuống còn 0. Thưởng thức!

Phong cảnh trừu tượng

Và đối với hai hình ảnh tiếp theo này, bạn có thể thấy các tiến trình kích thước đầy đủ ở đâyđây :

Xấu Simpsons

Tôi đã hack cái này cùng nhau trong khoảng một giờ trong khi thức dậy sáng nay và nó gần như không chứa tài liệu nào. Tôi có thể quay lại sau một vài ngày và thêm tài liệu sau nếu mọi người yêu cầu.

//=============================================================================
// SCRAMBLUR
//
// This program is a image-processing competition entry which scrambles or
// descrambles an image based on a pseudorandom process.  For more details,
// information, see:
//
//    http://codegolf.stackexchange.com/questions/35005
//
// It is assumed that you have the NETPBM package of image-processing tools
// installed on your system.  This can be obtained from:
//
//    http://netpbm.sourceforge.net/
//
// or by using your system's package manager, e.g., yum, apt-get, port, etc.
//
// Input to the program is a 24-bit PNM image (type "P6").  Output is same.
// Example command-line invocation:
//
// pngtopnm original.png  | scramblur 100  1000000 | pnmtopng >scrambled.png
// pngtopnm scrambled.png | scramblur 100 -1000000 | pnmtopng >recovered.png
//
//
// Todd S. Lehman, July 2014

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

typedef uint8_t uint8;
typedef uint64_t uint64;

//-----------------------------------------------------------------------------
// PIXEL STRUCTURE

#pragma pack(push, 1)
typedef struct
{
  uint8 r, g, b;     // Red, green, and blue color components
}
Pixel;
#pragma pack(pop)

//-----------------------------------------------------------------------------
// IMAGE STRUCTURE

typedef struct
{
  int width;          // Width of image in pixels
  int height;         // Height of image in pixels
  int pixel_count;    // Total number of pixels in image (e.g., width * height)
  int maxval;         // Maximum pixel component value (e.g., 255)
  Pixel *data;        // One-dimensional array of pixels
}
Image;

//-----------------------------------------------------------------------------
// 64-BIT LCG TABLE

static const long lcg64_table_length = 1000000;  // 10⁶ entries => 8 Megabytes

static uint64 lcg64_table[lcg64_table_length];

//-----------------------------------------------------------------------------
// GET 64-BIT LCG VALUE FROM TABLE

uint64 lcg64_get(long const iteration)
{
  return lcg64_table[iteration % lcg64_table_length];
}

//-----------------------------------------------------------------------------
// INITIALIZE 64-BIT LCG TABLE

void lcg64_init(uint64 const seed)
{
  uint64 x = seed;
  for (long iteration = 0; iteration < lcg64_table_length; iteration++)
  {
    uint64 const a = UINT64_C(6364136223846793005);
    uint64 const c = UINT64_C(1442695040888963407);
    x = (x * a) + c;
    lcg64_table[iteration] = x;
  }
}

//-----------------------------------------------------------------------------
// READ BINARY PNM IMAGE

Image image_read(FILE *const file)
{
  Image image = { .data = NULL };

  char *line = NULL;
  size_t linecap = 0;

  // Read image type.  (Currently only P6 is supported here.)
  if (getline(&line, &linecap, file) < 0) goto failure;
  if (strcmp(line, "P6\n") != 0) goto failure;

  // Read width and height of image in pixels.
  {
    if (getline(&line, &linecap, file) < 0) goto failure;
    char *pwidth = &line[0];
    char *pheight = strchr(line, ' ');
    if (pheight != NULL) pheight++; else goto failure;
    image.width = atoi(pwidth);
    image.height = atoi(pheight);
    image.pixel_count = image.width * image.height;
  }

  // Read maximum color value.  (Currently only 255 is supported here.)
  {
    if (getline(&line, &linecap, file) < 0) goto failure;
    image.maxval = atoi(line);
    if (image.maxval != 255)
      goto failure;
  }

  // Allocate image buffer and read image data.
  if (!(image.data = calloc(image.pixel_count, sizeof(Pixel))))
    goto failure;

  if (fread(image.data, sizeof(Pixel), image.pixel_count, file) !=
      image.pixel_count)
    goto failure;

success:
  free(line);
  return image;

failure:
  free(line);
  free(image.data); image.data = NULL;
  return image;
}

//-----------------------------------------------------------------------------
// WRITE BINARY PNM IMAGE

void image_write(const Image image, FILE *const file)
{
  printf("P6\n");
  printf("%d %d\n", image.width, image.height);
  printf("%d\n", image.maxval);
  (void)fwrite(image.data, sizeof(Pixel), image.pixel_count, file);
}

//-----------------------------------------------------------------------------
// DISCARD IMAGE

void image_discard(Image image)
{
  free(image.data);
}

//-----------------------------------------------------------------------------
// SCRAMBLE OR UNSCRAMBLE IMAGE

void image_scramble(Image image,
                    int const max_delta,
                    long const iterations,
                    uint64 const lcg64_seed)
{
  if (max_delta == 0) return;

  int neighborhood1 = (2 * max_delta) + 1;
  int neighborhood2 = neighborhood1 * neighborhood1;

  lcg64_init(lcg64_seed);

  long iteration_start = (iterations >= 0)? 0 : -iterations;
  long iteration_end   = (iterations >= 0)? iterations : 0;
  long iteration_inc   = (iterations >= 0)? 1 : -1;

  for (long iteration = iteration_start;
       iteration != iteration_end;
       iteration += iteration_inc)
  {
    uint64 lcg64 = lcg64_get(iteration);

    // Choose random pixel.
    int pixel_index = (int)((lcg64 >> 0) % image.pixel_count);

    // Choose random pixel in the neighborhood.
    int d2 = (int)((lcg64 >> 8) % neighborhood2);
    int dx = (d2 % neighborhood1) - (neighborhood1 / 2);
    int dy = (d2 / neighborhood1) - (neighborhood1 / 2);
    int other_pixel_index = pixel_index + dx + (dy * image.width);
    while (other_pixel_index < 0)
      other_pixel_index += image.pixel_count;
    other_pixel_index %= image.pixel_count;

    // Swap pixels.
    Pixel t = image.data[pixel_index];
    image.data[pixel_index] = image.data[other_pixel_index];
    image.data[other_pixel_index] = t;
  }
}

//-----------------------------------------------------------------------------
int main(const int argc, char const *const argv[])
{
  int max_delta     = (argc > 1)? atoi(argv[1]) : 1;
  long iterations   = (argc > 2)? atol(argv[2]) : 1000000;
  uint64 lcg64_seed = (argc > 3)? (uint64)strtoull(argv[3], NULL, 10) : 0;

  Image image = image_read(stdin);
  if (!image.data) { fprintf(stderr, "Invalid input\n"), exit(1); }

  image_scramble(image, max_delta, iterations, lcg64_seed);

  image_write(image, stdout);

  image_discard(image);

  return 0;
}

4
Chỉ cần cuộn qua câu trả lời này, trông thật tuyệt
Thomas

1
Câu trả lời này thực sự cao. Bạn có nghĩ rằng bạn có thể di chuyển các hình ảnh bổ sung (tức là mọi thứ trừ hai hình ảnh thử nghiệm, được làm mờ hoàn toàn) sang một bộ sưu tập ngoài trang web không?
Tim S.

@TimS. - làm xong! thu nhỏ chúng xuống hình thu nhỏ.
Todd Lehman

42

Con trăn 3,4

  • Phần thưởng 1: Tự nghịch đảo: lặp lại khôi phục ảnh gốc.
  • Hình ảnh khóa tùy chọn: hình ảnh gốc chỉ có thể được khôi phục bằng cách sử dụng lại cùng một hình ảnh chính.
  • Phần thưởng 2: Tạo mẫu ở đầu ra: hình ảnh chính được xấp xỉ bằng các pixel được xáo trộn.

Khi đạt được phần thưởng 2, bằng cách sử dụng một hình ảnh quan trọng bổ sung, phần thưởng 1 sẽ không bị mất. Chương trình vẫn tự đảo ngược, miễn là nó được chạy với cùng một hình ảnh chính.

Tiêu chuẩn sử dụng

Hình ảnh thử nghiệm 1:

Ảnh thử nghiệm xáo trộn 1

Hình ảnh thử nghiệm 2:

Ảnh thử nghiệm xáo trộn 2

Chạy chương trình với một tệp hình ảnh duy nhất vì đối số của nó lưu một tệp hình ảnh với các pixel được xáo trộn đều trên toàn bộ hình ảnh. Chạy lại nó với đầu ra được xáo trộn sẽ lưu một tệp hình ảnh với sự xáo trộn được áp dụng lại, nó khôi phục lại bản gốc do quá trình xáo trộn là nghịch đảo của chính nó.

Quá trình xáo trộn là tự đảo ngược vì danh sách tất cả các pixel được chia thành 2 chu kỳ, do đó mọi pixel được hoán đổi với một và chỉ một pixel khác. Chạy nó lần thứ hai hoán đổi mọi pixel với pixel mà nó được hoán đổi lần đầu tiên, đưa mọi thứ trở lại cách nó bắt đầu. Nếu có một số pixel lẻ, sẽ có một pixel không di chuyển.

Nhờ câu trả lời của mfvonh là người đầu tiên đề xuất 2 chu kỳ.

Sử dụng với một hình ảnh quan trọng

Xáo trộn hình ảnh thử nghiệm 1 với hình ảnh thử nghiệm 2 làm hình ảnh chính

Xáo trộn thử nghiệm 1 với thử nghiệm 2

Xáo trộn hình ảnh thử nghiệm 2 với hình ảnh thử nghiệm 1 làm hình ảnh chính

Scramble test 2 với test 1

Chạy chương trình với một đối số tệp hình ảnh thứ hai (hình ảnh chính) chia hình ảnh gốc thành các vùng dựa trên hình ảnh chính. Mỗi vùng trong số này được chia thành 2 chu kỳ riêng biệt, do đó tất cả các sự xáo trộn xảy ra trong các vùng và pixel không được di chuyển từ vùng này sang vùng khác. Điều này trải ra các pixel trên mỗi vùng và do đó các vùng trở thành một màu lốm đốm đồng nhất, nhưng với màu trung bình hơi khác nhau cho từng vùng. Điều này cung cấp một xấp xỉ rất thô của hình ảnh quan trọng, trong các màu sai.

Chạy lại hoán đổi các cặp pixel giống nhau ở mỗi vùng, do đó, mỗi vùng được khôi phục về trạng thái ban đầu và toàn bộ hình ảnh sẽ xuất hiện lại.

Nhờ câu trả lời của edc65 là người đầu tiên đề nghị chia hình ảnh thành các khu vực. Tôi muốn mở rộng về điều này để sử dụng các vùng tùy ý, nhưng cách tiếp cận hoán đổi mọi thứ trong khu vực 1 với mọi thứ trong khu vực 2 có nghĩa là các khu vực phải có kích thước giống hệt nhau. Giải pháp của tôi là giữ cho các vùng cách ly với nhau và chỉ cần xáo trộn từng vùng thành chính nó. Vì các vùng không còn cần phải có kích thước tương tự, nên việc áp dụng các vùng có hình dạng tùy ý trở nên đơn giản hơn.

import os.path
from PIL import Image   # Uses Pillow, a fork of PIL for Python 3
from random import randrange, seed


def scramble(input_image_filename, key_image_filename=None,
             number_of_regions=16777216):
    input_image_path = os.path.abspath(input_image_filename)
    input_image = Image.open(input_image_path)
    if input_image.size == (1, 1):
        raise ValueError("input image must contain more than 1 pixel")
    number_of_regions = min(int(number_of_regions),
                            number_of_colours(input_image))
    if key_image_filename:
        key_image_path = os.path.abspath(key_image_filename)
        key_image = Image.open(key_image_path)
    else:
        key_image = None
        number_of_regions = 1
    region_lists = create_region_lists(input_image, key_image,
                                       number_of_regions)
    seed(0)
    shuffle(region_lists)
    output_image = swap_pixels(input_image, region_lists)
    save_output_image(output_image, input_image_path)


def number_of_colours(image):
    return len(set(list(image.getdata())))


def create_region_lists(input_image, key_image, number_of_regions):
    template = create_template(input_image, key_image, number_of_regions)
    number_of_regions_created = len(set(template))
    region_lists = [[] for i in range(number_of_regions_created)]
    for i in range(len(template)):
        region = template[i]
        region_lists[region].append(i)
    odd_region_lists = [region_list for region_list in region_lists
                        if len(region_list) % 2]
    for i in range(len(odd_region_lists) - 1):
        odd_region_lists[i].append(odd_region_lists[i + 1].pop())
    return region_lists


def create_template(input_image, key_image, number_of_regions):
    if number_of_regions == 1:
        width, height = input_image.size
        return [0] * (width * height)
    else:
        resized_key_image = key_image.resize(input_image.size, Image.NEAREST)
        pixels = list(resized_key_image.getdata())
        pixel_measures = [measure(pixel) for pixel in pixels]
        distinct_values = list(set(pixel_measures))
        number_of_distinct_values = len(distinct_values)
        number_of_regions_created = min(number_of_regions,
                                        number_of_distinct_values)
        sorted_distinct_values = sorted(distinct_values)
        while True:
            values_per_region = (number_of_distinct_values /
                                 number_of_regions_created)
            value_to_region = {sorted_distinct_values[i]:
                               int(i // values_per_region)
                               for i in range(len(sorted_distinct_values))}
            pixel_regions = [value_to_region[pixel_measure]
                             for pixel_measure in pixel_measures]
            if no_small_pixel_regions(pixel_regions,
                                      number_of_regions_created):
                break
            else:
                number_of_regions_created //= 2
        return pixel_regions


def no_small_pixel_regions(pixel_regions, number_of_regions_created):
    counts = [0 for i in range(number_of_regions_created)]
    for value in pixel_regions:
        counts[value] += 1
    if all(counts[i] >= 256 for i in range(number_of_regions_created)):
        return True


def shuffle(region_lists):
    for region_list in region_lists:
        length = len(region_list)
        for i in range(length):
            j = randrange(length)
            region_list[i], region_list[j] = region_list[j], region_list[i]


def measure(pixel):
    '''Return a single value roughly measuring the brightness.

    Not intended as an accurate measure, simply uses primes to prevent two
    different colours from having the same measure, so that an image with
    different colours of similar brightness will still be divided into
    regions.
    '''
    if type(pixel) is int:
        return pixel
    else:
        r, g, b = pixel[:3]
        return r * 2999 + g * 5869 + b * 1151


def swap_pixels(input_image, region_lists):
    pixels = list(input_image.getdata())
    for region in region_lists:
        for i in range(0, len(region) - 1, 2):
            pixels[region[i]], pixels[region[i+1]] = (pixels[region[i+1]],
                                                      pixels[region[i]])
    scrambled_image = Image.new(input_image.mode, input_image.size)
    scrambled_image.putdata(pixels)
    return scrambled_image


def save_output_image(output_image, full_path):
    head, tail = os.path.split(full_path)
    if tail[:10] == 'scrambled_':
        augmented_tail = 'rescued_' + tail[10:]
    else:
        augmented_tail = 'scrambled_' + tail
    save_filename = os.path.join(head, augmented_tail)
    output_image.save(save_filename)


if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if arguments:
        scramble(*arguments[:3])
    else:
        print('\n'
              'Arguments:\n'
              '    input image          (required)\n'
              '    key image            (optional, default None)\n'
              '    number of regions    '
              '(optional maximum - will be as high as practical otherwise)\n')

Ghi hình ảnh JPEG

Các tập tin .jpg được xử lý rất nhanh, nhưng với chi phí chạy quá nóng. Điều này để lại một hình ảnh bị cháy sau khi bản gốc được khôi phục:

jpg ghi

Nhưng nghiêm túc, một định dạng bị mất sẽ dẫn đến một số màu pixel bị thay đổi một chút, chính điều đó làm cho đầu ra không hợp lệ. Khi một hình ảnh quan trọng được sử dụng và việc xáo trộn các pixel bị giới hạn ở các vùng, tất cả các biến dạng được giữ trong vùng mà nó xảy ra, và sau đó trải đều trên vùng đó khi hình ảnh được khôi phục. Sự khác biệt về độ méo trung bình giữa các vùng để lại sự khác biệt có thể nhìn thấy giữa chúng, vì vậy các vùng được sử dụng trong quá trình xáo trộn vẫn có thể nhìn thấy trong hình ảnh được khôi phục.

Chuyển đổi sang .png (hoặc bất kỳ định dạng không mất dữ liệu nào) trước khi xáo trộn đảm bảo rằng hình ảnh không bị xáo trộn giống hệt với bản gốc mà không bị cháy hoặc biến dạng:

png không có vết bỏng

Chi tiết nhỏ

  • Kích thước tối thiểu 256 pixel được áp đặt cho các vùng. Nếu hình ảnh được phép chia thành các vùng quá nhỏ, thì hình ảnh gốc vẫn có thể được nhìn thấy một phần sau khi xáo trộn.
  • Nếu có nhiều hơn một vùng có số pixel lẻ thì một pixel từ vùng thứ hai sẽ được gán lại cho vùng thứ nhất, v.v. Điều này có nghĩa là chỉ có thể có một vùng có số pixel lẻ và do đó, chỉ một pixel sẽ vẫn bị xáo trộn.
  • Có một đối số tùy chọn thứ ba giới hạn số lượng vùng. Đặt cài đặt này thành 2 chẳng hạn sẽ cho hai hình ảnh được xáo trộn. Điều này có thể trông tốt hơn hoặc xấu hơn tùy thuộc vào hình ảnh liên quan. Nếu một số được chỉ định ở đây, hình ảnh chỉ có thể được khôi phục bằng cách sử dụng lại cùng một số đó.
  • Số lượng màu sắc riêng biệt trong ảnh gốc cũng giới hạn số lượng vùng. Nếu hình ảnh gốc là hai tông màu thì bất kể hình ảnh chính hay đối số thứ ba, chỉ có thể có tối đa 2 vùng.

2
Vỗ tay +1! Tôi mơ hồ nghĩ về điều này, nhưng thấy nó quá khó để thực hiện.
edc65

1
Điều này thật tuyệt vời. Tôi đã có một mục được gửi, nhưng tôi thích mục của bạn hơn vì tính năng hình ảnh quan trọng.
Todd Lehman

Tôi tò mò không biết hai hình ảnh này trông như thế nào với nhau: lardlad.com/assets/wallapers/simpsons1920.jpgblog.nd.edu/oblation/files/2013/09/BreakingBad.jpg (giảm xuống còn 720x450 hoặc bất cứ điều gì có ý nghĩa và tất nhiên được chuyển đổi trước thành PNG để tránh bị cháy JPEG).
Todd Lehman

2
@ToddLehman Thuật toán của tôi bị giới hạn bởi sự cần thiết phải nghịch đảo của chính nó. Nếu bạn muốn xem một số cách tiếp cận thực sự thú vị để xáo trộn một hình ảnh để giống với hình ảnh khác, bạn nên nhìn vào American Gothic trong bảng màu của Mona Lisa . Một số chương trình sẽ làm những điều tuyệt vời với những hình ảnh bạn đề cập.
trichoplax

2
Các tính năng hình ảnh quan trọng đặt đầu và vai này trên phần còn lại.
Jack Aidley

33

Đây là một biến đổi không ngẫu nhiên cho một sự thay đổi

  1. Đặt tất cả các cột chẵn ở bên trái và tất cả các cột lẻ ở bên phải.
  2. lặp lại nxlần
  3. làm tương tự cho hàng nylần

Phép biến đổi gần như tự đảo ngược, lặp lại phép biến đổi tổng cộng số size_xlần (theo hướng x) trả về ảnh gốc. Tôi đã không tìm ra toán học chính xác, nhưng sử dụng bội số nguyên int(log_2(size_x))tạo ra sự xáo trộn tốt nhất với các hình ảnh ma nhỏ nhất

núi non xáo trộn nhập mô tả hình ảnh ở đây

from numpy import *
from pylab import imread, imsave

def imshuffle(im, nx=0, ny=0):
    for i in range(nx):
        im = concatenate((im[:,0::2], im[:,1::2]), axis=1)
    for i in range(ny):
        im = concatenate((im[0::2,:], im[1::2,:]), axis=0)
    return im

im1 = imread('circles.png')
im2 = imread('mountain.jpg')

imsave('s_circles.png', imshuffle(im1, 7,7))
imsave('s_mountain.jpg', imshuffle(im2, 8,9))

Đây là cách các bước đầu tiên 20 lần lặp lại trông như thế nào (nx = ny, lưu ý ảnh hưởng của các độ phân giải khác nhau) nhập mô tả hình ảnh ở đây


7
Đó là một thuật toán thực sự tuyệt vời. Và bạn hoàn toàn nên nhận được một phần thưởng cho việc sử dụng ảnh Lena Söderberg. :)
Todd Lehman

Luôn nâng cấp Lena

24

Toán học

Việc này thật thẳng thắn. Tôi chọn 5 * nPixelscác cặp tọa độ ngẫu nhiên và hoán đổi hai pixel đó (làm mờ hoàn toàn hình ảnh). Để xắp xếp lại, tôi làm tương tự ngược lại. Tất nhiên, tôi cần phải gieo hạt PRNG để có được các cặp tọa độ giống nhau trên cả hai bước.

scramble[image_] := Module[
   {data, h, w, temp},
   data = ImageData@image;
   {h, w} = Most@Dimensions@data;
   SeedRandom[42];
   (
      temp = data[[#[[1]], #[[2]]]];
      data[[#[[1]], #[[2]]]] = data[[#2[[1]], #2[[2]]]];
      data[[#2[[1]], #2[[2]]]] = temp;
      ) & @@@
    Partition[
     Transpose@{RandomInteger[h - 1, 10*h*w] + 1, 
       RandomInteger[w - 1, 10*h*w] + 1}, 2];
   Image@data
   ];
unscramble[image_] := Module[
   {data, h, w, temp},
   data = ImageData@image;
   {h, w} = Most@Dimensions@data;
   SeedRandom[42];
   (
      temp = data[[#[[1]], #[[2]]]];
      data[[#[[1]], #[[2]]]] = data[[#2[[1]], #2[[2]]]];
      data[[#2[[1]], #2[[2]]]] = temp;
      ) & @@@
    Reverse@
     Partition[
      Transpose@{RandomInteger[h - 1, 10*h*w] + 1, 
        RandomInteger[w - 1, 10*h*w] + 1}, 2];
   Image@data
   ];

Sự khác biệt duy nhất giữa hai chức năng là Reverse@trong unscramble. Cả hai chức năng đều có một đối tượng hình ảnh thực tế. Bạn có thể sử dụng chúng như sau:

in = Import["D:\\Development\\CodeGolf\\image-scrambler\\circles.png"]
scr = scramble[im]
out = unscramble[scr]

outingiống hệt nhau. Đây là những gì scrtrông giống như:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


4
Tuyệt quá! Vấn đề duy nhất là tự làm PRNG an toàn hơn, vì nếu sau một thời gian Mathicala nghĩ sẽ thay đổi thuật toán PRNG, điều này sẽ không giải mã được các hình ảnh được mã hóa cũ!
Somnium

1
Đẹp. Bạn sẽ có thể đạt được kết quả tương tự với Permute và FindPermuting.
DavidC

Tôi không chắc là tôi hiểu. Bạn có thể nhập hoán vị chính xác mà bạn muốn dưới dạng danh sách các chu kỳ.
DavidC

@DavidCarraher Hừm, thú vị. Tôi sẽ không phải nhớ hoán vị ban đầu để sử dụng FindPermutationchứ?
Martin Ender

Hoặc có thể một cái gì đó như {c, a, b}[[{2, 3, 1}]]có thể được sử dụng?
Somnium

22

C # (+ Tiền thưởng cho thuật toán đối xứng)

Điều này hoạt động bằng cách tìm một cái xnhư vậy x^2 == 1 mod (number of pixels in image), sau đó nhân chỉ số của từng pixel xđể tìm vị trí mới của nó. Điều này cho phép bạn sử dụng cùng một thuật toán để xáo trộn và xắp xếp lại một hình ảnh.

using System.Drawing;
using System.IO;
using System.Numerics;

namespace RearrangePixels
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (var arg in args)
                ScrambleUnscramble(arg);
        }

        static void ScrambleUnscramble(string fileName)
        {
            using (var origImage = new Bitmap(fileName))
            using (var newImage = new Bitmap(origImage))
            {
                BigInteger totalPixels = origImage.Width * origImage.Height;
                BigInteger modSquare = GetSquareRootOf1(totalPixels);
                for (var x = 0; x < origImage.Width; x++)
                {
                    for (var y = 0; y < origImage.Height; y++)
                    {
                        var newNum = modSquare * GetPixelNumber(new Point(x, y), origImage.Size) % totalPixels;
                        var newPoint = GetPoint(newNum, origImage.Size);
                        newImage.SetPixel(newPoint.X, newPoint.Y, origImage.GetPixel(x, y));
                    }
                }
                newImage.Save("scrambled-" + Path.GetFileName(fileName));
            }
        }

        static BigInteger GetPixelNumber(Point point, Size totalSize)
        {
            return totalSize.Width * point.Y + point.X;
        }

        static Point GetPoint(BigInteger pixelNumber, Size totalSize)
        {
            return new Point((int)(pixelNumber % totalSize.Width), (int)(pixelNumber / totalSize.Width));
        }

        static BigInteger GetSquareRootOf1(BigInteger modulo)
        {
            for (var i = (BigInteger)2; i < modulo - 1; i++)
            {
                if ((i * i) % modulo == 1)
                    return i;
            }
            return modulo - 1;
        }
    }
}

hình ảnh thử nghiệm đầu tiên, tranh giành

hình ảnh thử nghiệm thứ hai, xáo trộn


1
Thông minh một) Sẽ luôn có giải pháp cho phương trình đồng dư đó?
Somnium

1
@ user2992539 Sẽ luôn có các giải pháp tầm thường, 1(ảnh gốc) và modulo-1(ảnh đảo ngược / đảo ngược). Hầu hết các con số có giải pháp không tầm thường, nhưng có một số trường hợp ngoại lệ . (liên quan đến yếu tố chính của modulo)
Tim S.

Theo tôi hiểu các giải pháp tầm thường dẫn đến hình ảnh tương tự như đầu vào.
Somnium

Chính xác: 1xuất hình ảnh gốc và -1đầu ra, ví dụ imgur.com/EiE6VW2
Tim S.

19

C #, tự đảo ngược, không ngẫu nhiên

Nếu hình ảnh gốc có kích thước là lũy thừa của hai, thì mỗi hàng và cột được trao đổi với hàng và cột có mẫu bit đảo ngược, ví dụ: đối với hình ảnh có chiều rộng 256 thì hàng 0xB4 được trao đổi với hàng 0x2D. Hình ảnh có kích thước khác được chia thành các hình chữ nhật với các cạnh có sức mạnh bằng 2.

namespace CodeGolf
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (var arg in args)
                Scramble(arg);
        }

        static void Scramble(string fileName)
        {
            using (var origImage = new System.Drawing.Bitmap(fileName))
            using (var tmpImage = new System.Drawing.Bitmap(origImage))
            {
                {
                    int x = origImage.Width;
                    while (x > 0) {
                       int xbit = x & -x;
                        do {
                            x--;
                            var xalt = BitReverse(x, xbit);
                            for (int y = 0; y < origImage.Height; y++)
                                tmpImage.SetPixel(xalt, y, origImage.GetPixel(x, y));
                        } while ((x & (xbit - 1)) != 0);
                    }
                }
                {
                    int y = origImage.Height;
                    while (y > 0) {
                        int ybit = y & -y;
                        do {
                            y--;
                            var yalt = BitReverse(y, ybit);
                            for (int x = 0; x < origImage.Width; x++)
                                origImage.SetPixel(x, yalt, tmpImage.GetPixel(x, y));
                        } while ((y & (ybit - 1)) != 0);
                    } 
                }
                origImage.Save(System.IO.Path.GetFileNameWithoutExtension(fileName) + "-scrambled.png");
            }
        }

        static int BitReverse(int n, int bit)
        {
            if (bit < 4)
                return n;
            int r = n & ~(bit - 1);
            int tmp = 1;
            while (bit > 1) {
                bit >>= 1;
                if ((n & bit) != 0)
                    r |= tmp;
                tmp <<= 1;
            }
            return r;
        }
    }
}

Hình ảnh đầu tiên:

Tranh giành hình ảnh đầu tiên

Hình ảnh thứ hai:

Ảnh thứ hai bị xáo trộn


2
Tôi thích đầu ra "kẻ sọc" trên cái này.
Brian Rogers

14

C #

Phương pháp tương tự để xáo trộn và xắp xếp lại. Tôi sẽ đánh giá cao đề xuất cải thiện điều này.

using System;
using System.Drawing;
using System.Linq;

public class Program
{
    public static Bitmap Scramble(Bitmap bmp)
    {
        var res = new Bitmap(bmp);
        var r = new Random(1);

        // Making lists of even and odd numbers and shuffling them
        // They contain numbers between 0 and picture.Width (or picture.Height)
        var rX = Enumerable.Range(0, bmp.Width / 2).Select(x => x * 2).OrderBy(x => r.Next()).ToList();
        var rrX = rX.Select(x => x + 1).OrderBy(x => r.Next()).ToList();
        var rY = Enumerable.Range(0, bmp.Height / 2).Select(x => x * 2).OrderBy(x => r.Next()).ToList();
        var rrY = rY.Select(x => x + 1).OrderBy(x => r.Next()).ToList();

        for (int y = 0; y < bmp.Height; y++)
        {
            for (int x = 0; x < rX.Count; x++)
            {
                // Swapping pixels in a row using lists rX and rrX
                res.SetPixel(rrX[x], y, bmp.GetPixel(rX[x], y));
                res.SetPixel(rX[x], y, bmp.GetPixel(rrX[x], y));
            }
        }
        for (int x = 0; x < bmp.Width; x++)
        {
            for (int y = 0; y < rY.Count; y++)
            {
                // Swapping pixels in a column using sets rY and rrY
                var px = res.GetPixel(x, rrY[y]);
                res.SetPixel(x, rrY[y], res.GetPixel(x, rY[y]));
                res.SetPixel(x, rY[y], px);
            }
        }

        return res;
    }
}

Kết quả đầu ra trong kẻ sọc psychedelic Đầu tiên Cái thứ hai


Rất vui vì điều này có một số mẫu sọc)
Somnium

1
Bạn có thể vui lòng trao đổi 2 hình ảnh? Trong câu hỏi hình ảnh núi là đầu tiên.
AL

1
Bạn có thể bao gồm một lời giải thích ngắn gọn về thuật toán?
trichoplax

14

Python 2 (tự đảo ngược, không ngẫu nhiên, nhạy cảm theo ngữ cảnh)

Điều này sẽ không giành được bất kỳ giải thưởng nào cho "ít nhận ra nhất", nhưng có lẽ nó có thể ghi điểm là "thú vị". :-)

Tôi muốn làm cho một cái gì đó nhạy cảm theo ngữ cảnh, trong đó sự xáo trộn của các pixel thực sự phụ thuộc vào chính hình ảnh.

Ý tưởng khá đơn giản: Sắp xếp tất cả các pixel theo một số giá trị tùy ý xuất phát từ màu của pixel và sau đó hoán đổi vị trí của pixel đầu tiên trong danh sách đó với cuối cùng, thứ hai với thứ hai để cuối cùng, v.v.

Thật không may trong cách tiếp cận đơn giản này có một vấn đề với các pixel cùng màu, vì vậy để làm cho nó tự đảo ngược, chương trình của tôi trở nên phức tạp hơn một chút ...

from PIL import Image

img = Image.open('1.png', 'r')
pixels = img.load()
size_x, size_y = img.size

def f(colour):
    r,g,b = colour[:3]
    return (abs(r-128)+abs(g-128)+abs(b-128))//128

pixel_list = [(x,y,f(pixels[x,y])) for x in xrange(size_x) for y in xrange(size_y)]
pixel_list.sort(key=lambda x: x[2])
print "sorted"

colours = {}
for p in pixel_list:
    if p[2] in colours:
        colours[p[2]] += 1
    else:
        colours[p[2]] = 1
print "counted"

for n in set(colours.itervalues()):
    pixel_group = [p for p in pixel_list if colours[p[2]]==n]
    N = len(temp_list)
    for p1, p2 in zip(pixel_group[:N//2], pixel_group[-1:-N//2:-1]):
        pixels[p1[0],p1[1]], pixels[p2[0],p2[1]] = pixels[p2[0],p2[1]], pixels[p1[0],p1[1]]
print "swapped"

img.save('1scrambled.png')
print "saved"

Đây là kết quả: (abs (r-128) + abs (g-128) + abs (b-128)) // 128 (abs (r-128) + abs (g-128) + abs (b-128)) // 128

Bạn có thể đạt được kết quả khá khác nhau bằng cách thay đổi hàm băm f:

  • r-g-b:

    rgb

  • r+g/2.**8+b/2.**16:

    r + g / 2. ** 8 + b / 2. ** 16

  • math.sin(r+g*2**8+b*2**16):

    math.sin (r + g * 2 ** 8 + b * 2 ** 16)

  • (r+g+b)//600:

    (r + g + b) // 600

  • 0:

    0


3
Ôi! Cái này thật tuyệt !!! Công việc tốt đẹp!
Todd Lehman

1
Đó là điều thú vị nhất cho đến nay. Làm tốt lắm!
bebe

12

Toán học (+ tiền thưởng)

Điều này thu gọn các kênh màu và xáo trộn hình ảnh thành một danh sách dài dữ liệu. Kết quả là một phiên bản được xáo trộn thậm chí ít nhận ra hơn vì nó không có phân phối màu giống như bản gốc (vì dữ liệu đó cũng bị xáo trộn). Điều này là rõ ràng nhất trong hình ảnh tranh giành thứ hai, nhưng nếu bạn nhìn kỹ, bạn sẽ thấy hiệu ứng tương tự trong lần đầu tiên. Các chức năng là nghịch đảo của chính nó.

Có một nhận xét rằng điều này có thể không hợp lệ vì nó tranh giành trên mỗi kênh. Tôi nghĩ rằng nó nên, nhưng nó không phải là một vấn đề lớn. Thay đổi duy nhất cần thiết để xáo trộn toàn bộ pixel (thay vì trên mỗi kênh) sẽ là thay đổi Flatten @ xthành Flatten[x, 1]:)

ClearAll @ f;

f @ x_ := 
  With[
    {r = SeedRandom[Times @@ Dimensions @ x], f = Flatten @ x},
    ArrayReshape[
      Permute[f, Cycles @ Partition[RandomSample @ Range @ Length @ f, 2]],
      Dimensions @ x]]

Giải trình

Xác định hàm flấy mảng 2 chiều x. Hàm sử dụng sản phẩm có kích thước của hình ảnh như một hạt giống ngẫu nhiên, sau đó làm phẳng mảng thành danh sách 1 chiều f(bị bóng cục bộ). Sau đó, nó tạo ra một danh sách biểu mẫu {1, 2, ... n}nđộ dài f, ngẫu nhiên hoán chuyển danh sách đó, phân vùng nó thành các phân đoạn 2 (vì vậy, ví dụ: {{1, 2}, {3, 4}, ...}(giảm số cuối cùng nếu cả hai chiều đều lẻ) và sau đó fhoán đổi bằng cách hoán đổi các giá trị tại các vị trí được chỉ định trong mỗi danh sách con vừa tạo và cuối cùng, nó sẽ định hình lại danh sách được cho phép trở lại kích thước ban đầu x. Nó xáo trộn trên mỗi kênh vì ngoài việc thu gọn kích thước hình ảnhFlattenlệnh cũng thu gọn dữ liệu kênh trong mỗi pixel. Hàm này là nghịch đảo của chính nó vì các chu kỳ chỉ bao gồm hai pixel.

Sử dụng

img1=Import@"http://i.stack.imgur.com/2C2TY.jpg"//ImageData;
img2=Import@"http://i.stack.imgur.com/B5TbK.png"//ImageData;

f @ img1 // Image

nhập mô tả hình ảnh ở đây

f @ f @ img1 // Image

nhập mô tả hình ảnh ở đây

f @ img2 // Image

nhập mô tả hình ảnh ở đây

f @ f @ img2 // Image

nhập mô tả hình ảnh ở đây

Đây là sử dụng Flatten[x, 1].

g@x_ := With[{r = SeedRandom[Times @@ Dimensions @ x], f = Flatten[x, 1]}, 
  ArrayReshape[
   Permute[f, Cycles@Partition[RandomSample@Range@Length@f, 2]], 
   Dimensions@x]]

g@img2 // Image

nhập mô tả hình ảnh ở đây


1
Tôi đoán là điều này không đáp ứng các tiêu chí, vì nó hoán đổi ở quy mô nhỏ hơn so với pixel.
trichoplax

1
Tôi không nghĩ đó là một câu trả lời hợp lệ, nhưng tôi cũng thực sự thích nó. Đó là một bước ngoặt hấp dẫn, vì vậy +1 dù sao ...
trichoplax

1
@githubphagocyte Xem cập nhật :)
mfvonh

Tuyệt vời - Tôi đã đạt được +1 lần nữa nhưng tất nhiên tôi không thể làm điều đó hai lần ...
trichoplax

1
@githubphagocyte Đúng rồi, tôi quên cú pháp ngắn có thể kỳ quái. Đúng. f @ f @ img1 // Imagelà (theo cú pháp đầy đủ)Image[f[f[img1]]]
mfvonh

10

Matlab (+ tiền thưởng)

Về cơ bản, tôi chuyển đổi vị trí của hai pixel một cách ngẫu nhiên và gắn thẻ cho từng pixel đã được chuyển đổi để nó sẽ không bị chuyển đổi nữa. Tập lệnh tương tự có thể được sử dụng lại cho 'giải mã' vì tôi đặt lại trình tạo số ngẫu nhiên mỗi lần. Điều này được thực hiện cho đến khi gần như tất cả các pixel được chuyển đổi (đó là lý do tại sao stepize lớn hơn 2)

EDIT: Chỉ thấy rằng Martin Büttner đã sử dụng một cách tiếp cận tương tự - Tôi không có ý định sao chép ý tưởng - Tôi bắt đầu viết mã của mình khi không có câu trả lời, rất xin lỗi vì điều đó. Tôi vẫn nghĩ rằng phiên bản của tôi sử dụng một số ý tưởng khác nhau =) (Và thuật toán của tôi kém hiệu quả hơn nhiều nếu bạn nhìn vào bit nơi hai tọa độ ngẫu nhiên được chọn ^^)

Hình ảnh

1 2

img = imread('shuffle_image2.bmp');
s = size(img)
rand('seed',0)
map = zeros(s(1),s(2));
for i = 1:2.1:s(1)*s(2) %can use much time if stepsize is 2 since then every pixel has to be exchanged
    while true %find two unswitched pixels
        a = floor(rand(1,2) .* [s(1),s(2)] + [1,1]);
        b = floor(rand(1,2) .* [s(1),s(2)] + [1,1]);
        if map(a(1),a(2)) == 0 && map(b(1),b(2)) == 0
            break
        end
    end
    %switch
    map(a(1),a(2)) = 1;
    map(b(1),b(2)) = 1;
    t = img(a(1),a(2),:);
    img(a(1),a(2),:) = img(b(1),b(2),:);
    img(b(1),b(2),:) = t;
end
image(img)
imwrite(img,'output2.png')

Tôi không hiểu đầy đủ, mã của bạn được áp dụng lần thứ hai trên hình ảnh được mã hóa sẽ giải mã nó?
Somnium

2
Chính xác: Mỗi lần chính xác hai pixel bị hoán đổi và sẽ không bị hoán đổi lần nữa trong toàn bộ quá trình. Vì các số 'ngẫu nhiên' đều giống hệt nhau (do đặt lại bộ tạo số ngẫu nhiên), các cặp pixel sẽ bị tráo đổi. (RNG luôn dựa vào số được tạo trước đó để tạo số tiếp theo, tôi hy vọng điều này rõ ràng.)
flawr

1
Hà, mà thực sự ý tưởng ban đầu của tôi, nhưng sau đó tôi không thể bị làm phiền để đảm bảo mỗi điểm ảnh được hoán đổi đúng một lần, bởi vì tôi đã phải bắt đầu làm việc. : D +1!
Martin Ender

3
@ user2992539 Hãy xem Octave , một công cụ thay thế mã nguồn mở tốt cho MATLAB và bạn có thể chạy 99% mã MATLAB trực tiếp trong quãng tám.
flawr

2
Tôi nghĩ rằng nếu bạn nheo mắt thực sự khó khăn với hình ảnh của mình, bạn vẫn có thể thấy một số cấu trúc từ đầu vào (đó là do không di chuyển tất cả các pixel). Tôi đoán nếu bạn thay đổi thuật toán lựa chọn của mình để chạy trong O (1) thay vì O (), bạn có thể sửa nó. ;)
Martin Ender

10

Mathicala - Sử dụng một hoán vị để xáo trộn và nghịch đảo của nó để xắp xếp lại.

Một hình ảnh jpg là một mảng ba chiều của {r,g,b}màu pixel. (Cấu trúc 3 chiều cấu trúc tập hợp pixel theo hàng, cột và màu). Nó có thể được làm phẳng thành một danh sách các {r,g,b}bộ ba, sau đó được thẩm thấu theo danh sách chu kỳ "đã biết" và cuối cùng được tập hợp lại thành một mảng các kích thước ban đầu. Kết quả là một hình ảnh tranh giành.

Xắp xếp lại lấy hình ảnh được xáo trộn và xử lý nó với mặt trái của danh sách chu kỳ. Nó xuất ra, vâng, hình ảnh gốc.

Vì vậy, một hàm duy nhất (trong trường hợp hiện tại scramble) phục vụ cho việc xáo trộn cũng như các pixel xắp xếp lại trong một hình ảnh.

Một hình ảnh được nhập vào cùng với số hạt giống (để đảm bảo rằng trình tạo số Ngẫu nhiên sẽ ở cùng trạng thái để xáo trộn và xắp xếp lại). Khi tham số, đảo ngược, là Sai, hàm sẽ tranh giành. Khi nó là True, hàm sẽ xắp xếp lại.


tranh giành

Các pixel được làm phẳng và một danh sách các chu kỳ ngẫu nhiên được tạo ra. Permute sử dụng chu kỳ để chuyển đổi vị trí của pixel trong danh sách dẹt.

xắp xếp lại

Các chức năng tương tự, scrambleđược sử dụng để xắp xếp lại. Tuy nhiên, thứ tự của danh sách chu kỳ bị đảo ngược.

scramble[img_,s_,reverse_:False,imgSize_:300]:=
  Module[{i=ImageData[img],input,r},input=Flatten[i,1];SeedRandom[s];
  r=RandomSample@Range[Length[input]];Image[ArrayReshape[Permute[input,
  Cycles[{Evaluate@If[reverse,Reverse@r,r]}]],Dimensions[i]],ImageSize->imgSize]]

Ví dụ

Hạt giống tương tự (37) được sử dụng để xáo trộn và xắp xếp lại.

Điều này tạo ra hình ảnh tranh giành của ngọn núi. Hình dưới đây cho thấy biến scrambledMount có thể được thay thế bằng hình ảnh thực tế của cảnh núi non.

scrambledMount=scramble[mountain, 37, True]

gắn kết1


Bây giờ chúng tôi chạy ngược lại; scrambledMount được nhập và ảnh gốc được phục hồi.

 scramble[scrambledMount, 37, True]

gắn kết2


Điều tương tự cho các vòng tròn:

vòng tròn1


 scramble[scrambledCircles, 37, True]

vòng tròn2


Tôi không thể thấy làm thế nào một hình ảnh có thể là một mảng 3 chiều.
edc65

1
@ edc65, Hàng x Cột Cột x Màu sắc. Hình ảnh núi là 422 hàng bằng 800 cột bằng 3 màu. Nếu mảng được làm phẳng, nó mang lại 1012800 mẩu dữ liệu dưới dạng mảng một chiều, tức là dưới dạng danh sách.
DavidC

@ edc65 Tôi nên thêm rằng Permute đã được sử dụng để sắp xếp lại các màu dưới dạng bộ ba rgb. Tôi đã không làm phẳng điều đó nữa bởi vì tôi không quan tâm đến việc thực hiện bất kỳ thay đổi nào trong danh sách màu của bất kỳ pixel nào. Nếu bạn coi thông tin rgb, {r, g, b} là một phần tử, thì chúng ta đang nói về một mảng 2D. Nhìn theo cách này, nó hoàn toàn có ý nghĩa để đưa ra câu hỏi (Làm thế nào một hình ảnh có thể là một mảng 3 chiều?) Mà bạn nêu ra. Trong thực tế, có thể bình thường hơn khi coi một hình ảnh là một mảng 2D, không quan tâm đến thực tế là các yếu tố rgb thêm một chiều khác.
DavidC

10

Con trăn

Tôi thích câu đố này, anh ta có vẻ thú vị và tôi đã đi kèm với chức năng bao bọc và Chuyển động để áp dụng trên hình ảnh.

Gói

Tôi đọc bức tranh dưới dạng văn bản (từ trái sang phải, lên và xuống) và viết nó dưới dạng vỏ ốc.

Hàm này có chu kỳ: có một N, f ^ (n) (x) = x, ví dụ, đối với ảnh 4 * 2, f (f (f (x))) = x

Phong trào

Tôi lấy một số ngẫu nhiên và di chuyển từng cột và ligne từ nó

# Opening and creating pictures
img = Image.open("/home/faquarl/Bureau/unnamed.png")
PM1 = img.load()
(w,h) = img.size
img2 = Image.new( 'RGBA', (w,h), "black") 
PM2 = img2.load()
img3 = Image.new( 'RGBA', (w,h), "black") 
PM3 = img3.load()

# Rotation
k = 0
_i=w-1
_j=h-1
_currentColMin = 0
_currentColMax = w-1
_currentLigMin = 0
_currentLigMax = h-1
_etat = 0
for i in range(w):
    for j in range(h):
        PM2[_i,_j]=PM1[i,j]
        if _etat==0:
            if _currentColMax == _currentColMin:
                _j -= 1
                _etat = 2
            else:
                _etat = 1
                _i -= 1
        elif _etat==1:
            _i -= 1
            if _j == _currentLigMax and _i == _currentColMin:
                _etat = 2
        elif _etat==2:
            _j -= 1
            _currentLigMax -= 1
            if _j == _currentLigMin and _i == _currentColMin:
                _etat = 5
            else:
                _etat = 3
        elif _etat==3:
            _j -= 1
            if _j == _currentLigMin and _i == _currentColMin:
                _etat = 4
        elif _etat==4:
            _i += 1
            _currentColMin += 1
            if _j == _currentLigMin and _i == _currentColMax:
                _etat = 7
            else:
                _etat = 5
        elif _etat==5:
            _i += 1
            if _j == _currentLigMin and _i == _currentColMax:
                _etat = 6
        elif _etat==6:
            _j += 1
            _currentLigMin += 1
            if _j == _currentLigMax and _i == _currentColMax:
                _etat = 1
            else:
                _etat = 7
        elif _etat==7:
            _j += 1
            if _j == _currentLigMax and _i == _currentColMax:
                _etat = 8
        elif _etat==8:
            _i -= 1
            _currentColMax -= 1
            if _j == _currentLigMax and _i == _currentColMin:
                _etat = 3
            else:
                _etat = 1
        k += 1
        if k == w * h:
            i = w
            j = h
# Movement
if w>h:z=w
else:z=h
rand.seed(z)
a=rand.randint(0,h)
for i in range(w):
  for j in range(h):
  if i%2==0:
    PM3[(i+a)%w,(j+a)%h]=PM2[i,j]
  else:
    PM3[(i-a)%w,(j-a)%h]=PM2[i,j]
# Rotate Again

Những bức ảnh

Vòng quay đầu tiên: nhập mô tả hình ảnh ở đây

sau đó hoán vị: nhập mô tả hình ảnh ở đây

Và với giới hạn cuối cùng: nhập mô tả hình ảnh ở đây

Đối với ví dụ khác: nhập mô tả hình ảnh ở đây


2
Làm thế nào để bạn khôi phục lại hình ảnh gốc?
trichoplax

Nếu chỉ là xoay vòng, tôi có thể thực hiện nó trong một khoảng thời gian nhất định (tùy thuộc vào kích thước). Tuy nhiên, nếu tôi có hoán vị thì tôi không chắc là nó có chu kỳ hay không nên tôi chỉ có chức năng thứ hai mà chỉ thay đổi là PM2 [_i, _j] = PM1 [i, j] đã trở thành PM2 [i, j] = PM1 [ _i, _j] và PM3 [(i + a)% w, (j + a)% h] = PM2 [i, j] đã trở thành PM3 [(ia)% w, (ja)% h] = PM2 [i, j]. Tôi đang tìm cách để làm điều đó mà không thay đổi hai dòng này
Faquarl

8

VB.NET (+ tiền thưởng)

Điều này sử dụng ý tưởng của flawr, nhờ anh ta, tuy nhiên điều này sử dụng thuật toán trao đổi và kiểm tra khác nhau. Chương trình mã hóa và giải mã theo cùng một cách.

Imports System

Module Module1

    Sub swap(ByVal b As Drawing.Bitmap, ByVal i As Integer, ByVal j As Integer)
        Dim c1 As Drawing.Color = b.GetPixel(i Mod b.Width, i \ b.Width)
        Dim c2 As Drawing.Color = b.GetPixel(j Mod b.Width, j \ b.Width)
        b.SetPixel(i Mod b.Width, i \ b.Width, c2)
        b.SetPixel(j Mod b.Width, j \ b.Width, c1)
    End Sub

    Sub Main(ByVal args() As String)
        For Each a In args
            Dim f As New IO.FileStream(a, IO.FileMode.Open)
            Dim b As New Drawing.Bitmap(f)
            f.Close()
            Dim sz As Integer = b.Width * b.Height - 1
            Dim w(sz) As Boolean
            Dim r As New Random(666)
            Dim u As Integer, j As Integer = 0
            Do While j < sz
                Do
                    u = r.Next(0, sz)
                Loop While w(u)
                ' swap
                swap(b, j, u)
                w(j) = True
                w(u) = True
                Do
                    j += 1
                Loop While j < sz AndAlso w(j)
            Loop
            b.Save(IO.Path.ChangeExtension(a, "png"), Drawing.Imaging.ImageFormat.Png)
            Console.WriteLine("Done!")
        Next
    End Sub

End Module

Hình ảnh đầu ra:


8

Sau khi được nhắc nhở rằng điều này sắp hoán đổi pixel và không thay đổi chúng, đây là giải pháp của tôi cho việc này:

Tranh giành: nhập mô tả hình ảnh ở đây

Đã khôi phục: nhập mô tả hình ảnh ở đây

Điều này được thực hiện bằng cách ngẫu nhiên hóa thứ tự pixel, nhưng để có thể khôi phục nó, sự ngẫu nhiên đã được sửa. Điều này được thực hiện bằng cách sử dụng giả ngẫu nhiên với một hạt giống cố định và tạo một danh sách các chỉ mục mô tả các pixel sẽ hoán đổi. Vì hoán đổi sẽ giống nhau, cùng một danh sách sẽ khôi phục lại hình ảnh gốc.

public class ImageScramble {

  public static void main(String[] args) throws IOException {
    if (args.length < 2) {
      System.err.println("Usage: ImageScramble <fileInput> <fileOutput>");
    } else {
      // load image
      final String extension = args[0].substring(args[0].lastIndexOf('.') + 1);
      final BufferedImage image = ImageIO.read(new File(args[0]));
      final int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());

      // create randomized swap list
      final ArrayList<Integer> indexes = IntStream.iterate(0, i -> i + 1).limit(pixels.length).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
      Collections.shuffle(indexes, new Random(1337));

      // swap all pixels at index n with pixel at index n+1
      int tmp;
      for (int i = 0; i < indexes.size(); i += 2) {
        tmp = pixels[indexes.get(i)];
        pixels[indexes.get(i)] = pixels[indexes.get(i + 1)];
        pixels[indexes.get(i + 1)] = tmp;
      }

      // write image to disk
      final BufferedImage imageScrambled = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
      imageScrambled.setRGB(0, 0, imageScrambled.getWidth(), imageScrambled.getHeight(), pixels, 0, imageScrambled.getWidth());
      ImageIO.write(imageScrambled, extension, new File(args[1]));
    }
  }
}

Lưu ý rằng sử dụng thuật toán này trên định dạng nén mất dữ liệu sẽ không tạo ra kết quả tương tự, vì định dạng hình ảnh sẽ thay đổi dữ liệu. Điều này sẽ hoạt động tốt với bất kỳ codec không mất dữ liệu như PNG.


8

Toán học

Chúng tôi định nghĩa một hàm trợ giúp hvà hàm xáo trộn scramblelà:

h[l_List, n_Integer, k_Integer: 1] := 
  With[{ m = Partition[l, n, n, 1, 0] }, 
    Flatten[
      Riffle[
        RotateLeft[ m[[ ;; , {1} ]] , k ],
        m[[ ;; , 2;; ]]
      ], 1
    ] [[ ;; Length[l] ]]
  ];

scramble[img_Image, k_Integer] :=
  Module[{ list , cNum = 5 },
    Which[
      k > 0,    list = Prime@Range[cNum],
      k < 0,    list = Reverse@Prime@Range[cNum],
      True,     list = {}
    ];
    Image[
      Transpose[
        Fold[ h[ #1, #2, k ] &, #, list ] & /@
        Transpose[
          Fold[ h[#1, #2, k] &, #, list ] & /@ ImageData[img]
        ]
      ]
    ]
  ];

Sau khi tải một hình ảnh, bạn có thể gọi scramble[img, k]nơi klà bất kỳ số nguyên, để tranh giành ảnh. Gọi lại với -ksẽ giải mã. (Nếu k0, thì không có thay đổi nào được thực hiện.) Thông thường knên được chọn là một cái gì đó giống như 100, nó mang lại một hình ảnh khá lộn xộn:

Ví dụ đầu ra 1

Ví dụ đầu ra 2


7

Matlab: Tranh giành hàng và cột dựa trên tính bất biến tổng của hàng / cột

Đây dường như là một câu đố thú vị, vì vậy tôi đã suy nghĩ về nó và đưa ra chức năng sau đây. Nó dựa trên sự bất biến của các tổng giá trị pixel của hàng và cột trong quá trình dịch chuyển vòng tròn: nó dịch chuyển từng hàng, sau đó mỗi cột, bằng tổng tổng các giá trị pixel của hàng / cột (giả sử uint8 cho toàn bộ số trong biến ca ). Điều này sau đó có thể được đảo ngược bằng cách dịch chuyển từng cột sau đó hàng theo giá trị tổng của chúng theo hướng ngược lại.

Nó không đẹp như những cái khác, nhưng tôi thích rằng nó không ngẫu nhiên và được chỉ định đầy đủ bởi hình ảnh - không chọn tham số.

Ban đầu tôi đã thiết kế nó để dịch chuyển từng kênh màu riêng biệt, nhưng sau đó tôi nhận thấy thông số kỹ thuật chỉ di chuyển các pixel đầy đủ.

function pic_scramble(input_filename)
i1=imread(input_filename);
figure;
subplot(1,3,1);imagesc(i1);title('Original','fontsize',20);

i2=i1;
for v=1:size(i1,1)
    i2(v,:,:)=circshift(i2(v,:,:),sum(sum(i2(v,:,:))),2);
end
for w=1:size(i2,2)
    i2(:,w,:)=circshift(i2(:,w,:),sum(sum(i2(:,w,:))),1);
end
subplot(1,3,2);imagesc(i2);title('Scrambled','fontsize',20);

i3=i2;
for w=1:size(i3,2)
    i3(:,w,:)=circshift(i3(:,w,:),-1*sum(sum(i3(:,w,:))),1);
end
for v=1:size(i3,1)
    i3(v,:,:)=circshift(i3(v,:,:),-1*sum(sum(i3(v,:,:))),2);
end
subplot(1,3,3);imagesc(i3);title('Recovered','fontsize',20);

Hình ảnh thử nghiệm đầu tiên Hình ảnh thử nghiệm của Secont


6

Java

Chương trình này hoán đổi ngẫu nhiên các pixel (tạo ánh xạ pixel sang pixel), nhưng thay vì hàm ngẫu nhiên, nó sử dụng Math.sin () (số nguyên x). Nó hoàn toàn có thể đảo ngược. Với hình ảnh thử nghiệm nó tạo ra một số mẫu.

Các tham số: số nguyên (số lần truyền, số âm để đảo ngược, 0 không làm gì), pháp sư đầu vào và hình ảnh đầu ra (có thể giống nhau). Tập tin đầu ra phải ở định dạng sử dụng nén không mất dữ liệu.

1 lượt: nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

100 đường chuyền (phải mất vài phút để làm điều đó): nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Mã số:

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class Test{

public static void main(String... args) {
    String in = "image.png";
    String out = in;
    int passes = 0;
    if (args.length < 1) {
        System.out.println("no paramem encryptimg, 1 pass, reading and saving image.png");
        System.out.println("Usage: pass a number. Negative - n passes of decryption, positive - n passes of encryption, 0 - do nothing");
    } else {
        passes = Integer.parseInt(args[0]);
        if (args.length > 1) {
            in = args[1];
        }
        if(args.length > 2){
            out = args[2];
        }
    }
    boolean encrypt = passes > 0;
    passes = Math.abs(passes);
    for (int a = 0; a < passes; a++) {
        BufferedImage img = null;
        try {
            img = ImageIO.read(new File(a == 0 ? in : out));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        int pixels[][] = new int[img.getWidth()][img.getHeight()];
        int[][] newPixels = new int[img.getWidth()][img.getHeight()];
        for (int x = 0; x < pixels.length; x++) {
            for (int y = 0; y < pixels[x].length; y++) {
                pixels[x][y] = img.getRGB(x, y);
            }
        }
        int amount = img.getWidth() * img.getHeight();
        int[] list = new int[amount];
        for (int i = 0; i < amount; i++) {
            list[i] = i;
        }
        int[] mapping = new int[amount];
        for (int i = amount - 1; i >= 0; i--) {
            int num = (Math.abs((int) (Math.sin(i) * amount))) % (i + 1);
            mapping[i] = list[num];
            list[num] = list[i];
        }
        for (int xz = 0; xz < amount; xz++) {
            int x = xz % img.getWidth();
            int z = xz / img.getWidth();
            int xzMap = mapping[xz];
            int newX = xzMap % img.getWidth();
            int newZ = xzMap / img.getWidth();
            if (encrypt) {
                newPixels[x][z] = pixels[newX][newZ];
            } else {
                newPixels[newX][newZ] = pixels[x][z];
            }
        }
        BufferedImage newImg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < pixels.length; x++) {
            for (int y = 0; y < pixels[x].length; y++) {
                newImg.setRGB(x, y, newPixels[x][y]);
            }
        }

        try {
            String[] s = out.split("\\.");
            ImageIO.write(newImg, s[s.length - 1],
                    new File(out));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
    }
}
}

6

Python 2.7 với PIL

Đến bữa tiệc muộn một chút, nhưng tôi nghĩ sẽ rất vui khi chuyển đổi hình ảnh thành kẻ sọc (và dĩ nhiên là quay lại). Đầu tiên chúng ta dịch chuyển cột lên hoặc xuống gấp 4 lần số cột (chẵn cột xuống, cột lẻ lên). Sau đó, chúng tôi dịch chuyển các hàng sang trái hoặc phải bằng 4 lần số hàng (các cột chẵn bên trái, các cột lẻ phải).

Kết quả là khá biến mất.

Để đảo ngược, chúng ta chỉ cần làm những việc này theo thứ tự ngược lại và thay đổi theo số tiền ngược lại.

from PIL import Image

def slideColumn (pix, tpix, x, offset, height):
  for y in range(height):
    tpix[x,(offset+y)%height] = pix[x,y]

def slideRow (pix, tpix, y, offset, width):
  for x in range(width):
    tpix[(offset+x)%width,y] = pix[x,y]

def copyPixels (source, destination, width, height):
  for x in range(width):
    for y in range(height):
      destination[x,y]=source[x,y]

def shuffleHorizontal (img, tmpimg, factor, encoding):
  xsize,ysize = img.size
  pix = img.load()
  tpix = tmpimg.load()
  for y in range(ysize):
    offset = y*factor
    if y%2==0:
      offset = xsize-offset
    offset = (xsize + offset) % xsize
    if encoding:
      slideRow(pix,tpix,y,offset,xsize)
    else:
      slideRow(pix,tpix,y,-offset,xsize)
  copyPixels(tpix,pix,xsize,ysize)

def shuffleVertical (img, tmpimg, factor, encoding):
  xsize,ysize = img.size
  pix = img.load()
  tpix = tmpimg.load()
  for x in range(xsize):
    offset = x*factor
    if x%2==0:
      offset = ysize-offset
    offset = (ysize + offset) % ysize
    if encoding:
      slideColumn(pix,tpix,x,offset,ysize)
    else:
      slideColumn(pix,tpix,x,-offset,ysize)
  copyPixels(tpix,pix,xsize,ysize)


def plaidify (img):
  tmpimg = Image.new("RGB",img.size)
  shuffleVertical(img,tmpimg,4,True)
  shuffleHorizontal(img,tmpimg,4,True)

def deplaidify (img):
  tmpimg = Image.new("RGB",img.size)
  shuffleHorizontal(img,tmpimg,4,False)
  shuffleVertical(img,tmpimg,4,False)

Các kết quả

Kẻ sọc từ hình ảnh 1:

1.jpg plaidized

Hình thức kẻ sọc 2:

2.png hóa


2
Rất đẹp! Có thể có được các đường chéo dọc theo một góc 45 °?
Todd Lehman

2
Có thể bằng cách thay đổi các dòng bù thành: offset = x*xsize/ysizeoffset = y*ysize/xsize thật không may, nó cũng không che giấu hình ảnh.
jrrl

5

Python (+ phần thưởng) - hoán vị của các pixel

Trong phương pháp này, mọi pixel sẽ được đặt ở vị trí khác, với ràng buộc là pixel kia sẽ được đặt ở vị trí đầu tiên. Về mặt toán học, nó là một hoán vị với độ dài chu kỳ 2. Như vậy, phương thức này là nghịch đảo của chính nó.

Nhìn lại, nó rất giống với mfvonh, nhưng bài nộp này là bằng Python và tôi đã phải tự xây dựng hoán vị đó.

def scramble(I):
    result = np.zeros_like(I)
    size = I.shape[0:2]
    nb_pixels = size[0]*size[1]
    #Build permutation
    np.random.seed(0)
    random_indices = np.random.permutation( range(nb_pixels) )
    random_indices1 = random_indices[0:int(nb_pixels/2)]
    random_indices2 = random_indices[-1:-1-int(nb_pixels/2):-1]
    for c in range(3):
        Ic = I[:,:,c].flatten()
        Ic[ random_indices2 ] = Ic[random_indices1]
        Ic[ random_indices1 ] = I[:,:,c].flatten()[random_indices2]
        result[:,:,c] = Ic.reshape(size)
    return result

Hình ảnh thử nghiệm đầu tiên: Hình ảnh thử nghiệm đầu tiên Hình ảnh thử nghiệm thứ hai: Hình ảnh thử nghiệm thứ hai


5

Python 2.7 + PIL, Cảm hứng từ các câu đố trượt

Chỉ cần có một ý tưởng khác. Về cơ bản, phương pháp này chia một hình ảnh thành các khối có kích thước bằng nhau và sau đó xáo trộn thứ tự của chúng. Vì đơn hàng mới dựa trên một hạt giống cố định, có thể hoàn toàn hoàn nguyên quy trình bằng cách sử dụng cùng một hạt giống. Ngoài ra, với tham số bổ sung được gọi là độ chi tiết, có thể đạt được các kết quả khác nhau và không thể nhận ra.

Các kết quả:

Nguyên

nguyên

Độ chi tiết 16

16

Độ chi tiết 13

13

Độ chi tiết 10

10

Độ chi tiết 3

3

Độ chi tiết 2

2

Độ chi tiết 1

nhập mô tả hình ảnh ở đây

Nguyên

nguyên

Độ chi tiết 16

16

Độ chi tiết 13

13

Độ chi tiết 10

10

Độ chi tiết 3

3

Độ chi tiết 2

2

Độ chi tiết 1

1

Mã số:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PIL import Image
import random

def scramble_blocks(im,granularity,password,nshuffle):
    set_seed(password)
    width=im.size[0]
    height=im.size[1]

    block_width=find_block_dim(granularity,width)       #find the possible block dimensions
    block_height=find_block_dim(granularity,height)

    grid_width_dim=width/block_width                #dimension of the grid
    grid_height_dim=height/block_height

    nblocks=grid_width_dim*grid_height_dim          #number of blocks

    print "nblocks: ",nblocks," block width: ",block_width," block height: ",block_height
    print "image width: ",width," image height: ",height
    print "getting all the blocks ..."
    blocks=[]
    for n in xrange(nblocks): #get all the image blocks
        blocks+=[get_block(im,n,block_width,block_height)]

    print "shuffling ..."
    #shuffle the order of the blocks
    new_order=range(nblocks)
    for n in xrange(nshuffle):
        random.shuffle(new_order)

    print "building final image ..."
    new_image=im.copy()
    for n in xrange(nblocks):
        #define the target box where to paste the new block
        i=(n%grid_width_dim)*block_width                #i,j -> upper left point of the target image
        j=(n/grid_width_dim)*block_height
        box = (i,j,i+block_width,j+block_height)    

        #paste it   
        new_image.paste(blocks[new_order[n]],box)

    return new_image



#find the dimension(height or width) according to the desired granularity (a lower granularity small blocks)
def find_block_dim(granularity,dim):
    assert(granularity>0)
    candidate=0
    block_dim=1
    counter=0
    while counter!=granularity:         #while we dont achive the desired granularity
        candidate+=1
        while((dim%candidate)!=0):      
            candidate+=1
            if candidate>dim:
                counter=granularity-1
                break

        if candidate<=dim:
            block_dim=candidate         #save the current feasible lenght

        counter+=1

    assert(dim%block_dim==0 and block_dim<=dim)
    return block_dim

def unscramble_blocks(im,granularity,password,nshuffle):
    set_seed(password)
    width=im.size[0]
    height=im.size[1]

    block_width=find_block_dim(granularity,width)       #find the possible block dimensions
    block_height=find_block_dim(granularity,height)

    grid_width_dim=width/block_width                #dimension of the grid
    grid_height_dim=height/block_height

    nblocks=grid_width_dim*grid_height_dim          #number of blocks

    print "nblocks: ",nblocks," block width: ",block_width," block height: ",block_height
    print "getting all the blocks ..."
    blocks=[]
    for n in xrange(nblocks): #get all the image blocks
        blocks+=[get_block(im,n,block_width,block_height)]

    print "shuffling ..."
    #shuffle the order of the blocks
    new_order=range(nblocks)
    for n in xrange(nshuffle):
        random.shuffle(new_order)

    print "building final image ..."
    new_image=im.copy()
    for n in xrange(nblocks):
        #define the target box where to paste the new block
        i=(new_order[n]%grid_width_dim)*block_width             #i,j -> upper left point of the target image
        j=(new_order[n]/grid_width_dim)*block_height
        box = (i,j,i+block_width,j+block_height)    

        #paste it   
        new_image.paste(blocks[n],box)

    return new_image

#get a block of the image
def get_block(im,n,block_width,block_height):

    width=im.size[0]

    grid_width_dim=width/block_width                        #dimension of the grid

    i=(n%grid_width_dim)*block_width                        #i,j -> upper left point of the target block
    j=(n/grid_width_dim)*block_height

    box = (i,j,i+block_width,j+block_height)
    block_im = im.crop(box)
    return block_im

#set random seed based on the given password
def set_seed(password):
    passValue=0
    for ch in password:                 
        passValue=passValue+ord(ch)
    random.seed(passValue)


if __name__ == '__main__':

    filename="0RT8s.jpg"
    # filename="B5TbK.png"
    password="yOs0ZaKpiS"
    nshuffle=1
    granularity=1

    im=Image.open(filename)

    new_image=scramble_blocks(im,granularity,password,nshuffle)
    new_image.show()
    new_image.save(filename.split(".")[0]+"_puzzled.png")

    new_image=unscramble_blocks(new_image,granularity,password,nshuffle)
    new_image.save(filename.split(".")[0]+"_unpuzzled.png")
    new_image.show()

5

47

94 dòng. 47 để mã hóa, 47 để giải mã.

require 'chunky_png'
require_relative 'codegolf-35005_ref.rb'


REF = {:png => ref, :w => 1280, :h => 720}
REF[:pix] = REF[:png].to_rgb_stream.unpack('C*').each_slice(3).to_a
SEVENTH_PRIME = 4*7 - 4-7 - (4&7)
FORTY_SEVEN   = 4*7 + 4+7 + (4&7) + (4^7) + 7/4
THRESHOLD     = FORTY_SEVEN * SEVENTH_PRIME


class RNG
    @@m = 2**32
    @@r = 0.5*(Math.sqrt(5.0) - 1.0)
    def initialize(n=0)
        @cur = FORTY_SEVEN + n
    end
    def hash(seed)
        (@@m*((seed*@@r)%1)).floor
    end
    def _next(max)
        hash(@cur+=1) % max
    end
    def _prev(max)
        hash(@cur-=1) % max
    end        
    def advance(n)
        @cur += n
    end
    def state
        @cur
    end
    alias_method :rand, :_next
end


def load_png(file, resample_w = nil, resample_h = nil)
    png  = ChunkyPNG::Image.from_file(file)
    w    = resample_w || png.width
    h    = resample_h || png.height
    png.resample_nearest_neighbor!(w,h) if resample_w || resample_h
    pix  = png.to_rgb_stream.unpack('C*').each_slice(3).to_a
    return {:png => png, :w => w, :h => h, :pix => pix}
end


def make_png(img)
    rgb_stream = img[:pix].flatten.pack('C*')
    img[:png] = ChunkyPNG::Canvas.from_rgb_stream(img[:w],img[:h],rgb_stream)
    return img
end


def difference(pix_a,pix_b)
    (pix_a[0]+pix_a[1]+pix_a[2]-pix_b[0]-pix_b[1]-pix_b[2]).abs
end


def code(img, img_ref, mode)
    img_in  = load_png(img)
    pix_in  = img_in[:pix]
    pix_ref = img_ref[:pix]
    s = img_in[:w] * img_in[:h] 
    rng = RNG.new(mode==:enc ? 0 : FORTY_SEVEN*s+1)
    rand = mode == :enc ? rng.method(:_next) : rng.method(:_prev)
    s.times do
        FORTY_SEVEN.times do
            j = rand.call(s)
            i = rng.state % s
            diff_val = difference(pix_ref[i],pix_ref[j])
            if diff_val > THRESHOLD
               pix_in[i], pix_in[j] = pix_in[j], pix_in[i]
            end
        end
    end
    make_png(img_in)
end


case ARGV.shift
when 'enc'
    org, cod = ARGV
    encoded_image = code(org,REF,:enc)
    encoded_image[:png].save(cod)
when 'dec'
    org, cod = ARGV
    decoded_image = code(cod,REF,:dec)
    decoded_image[:png].save(org)
else
    puts '<original> <coded>'
    puts 'specify either <enc> or <dec>'
    puts "ruby #{$0} enc codegolf-35005_inp.png codegolf-35005_enc.png"
end

codegolf-35005_Vf.rb

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

(chuyển đổi sang jpg)

nhập mô tả hình ảnh ở đây

(thu nhỏ ban đầu)

nhập mô tả hình ảnh ở đây


3
Một số mô hình ban đầu được nhìn thấy thông qua các dòng đó. Tuy nhiên, nó giống như khi bạn vẽ bằng ngón tay trên cửa sổ mờ).
Somnium

2
... + 184426 byte cho codegolf-35005_Vf.rb?
edc65

5

Matlab với một chút lý thuyết nhóm (+ tiền thưởng)

Theo cách tiếp cận này, chúng tôi giả định rằng chúng tôi có số lượng pixel chẵn. (Nếu không, chúng ta chỉ bỏ qua một pixel) Vì vậy, chúng ta cần chọn một nửa số pixel để trao đổi với nửa còn lại. Đối với điều này, chúng tôi lập chỉ mục tất cả các pixel từ 0tối đa 2N-1và coi các chỉ số này là một nhóm tuần hoàn.

Trong số các số nguyên tố chúng tôi tìm kiếm một số pkhông quá nhỏ và không quá lớn và đó là số nguyên tố 2Ntheo thứ tự của nhóm chúng tôi. Điều này có nghĩa là g tạo nhóm của chúng tôi hoặc {k*g mod 2N | k=0,1,...,2N-1} = {0,1,...,2N-1}.

Vì vậy, chúng tôi chọn Nbội số đầu tiên của gmột bộ và tất cả các phân còn lại là bộ khác và chỉ trao đổi bộ pixel tương ứng.

Nếu pđược chọn đúng cách, bộ đầu tiên được phân bổ đều trên toàn bộ hình ảnh.

Hai trường hợp thử nghiệm:

Hơi lạc đề nhưng thú vị:

Trong quá trình thử nghiệm tôi nhận thấy rằng nếu bạn lưu nó vào jpg (nén bị mất) (thay vì png được nén không mất dữ liệu) và áp dụng chuyển đổi qua lại, bạn sẽ thấy rất nhanh các kết quả của quá trình nén, điều này cho thấy kết quả của hai lần sắp xếp lại liên tiếp :

Như bạn có thể thấy, nén jpg làm cho kết quả trông gần như đen và trắng!

clc;clear;
inputname = 'codegolf_rearrange_pixels2.png';
inputname = 'codegolf_rearrange_pixels2_swapped.png';
outputname = 'codegolf_rearrange_pixels2_swapped.png';

%read image
src = imread(inputname);

%separate into channels
red = src(:,:,1);
green = src(:,:,2);
blue = src(:,:,3);

Ntotal = numel(red(:));  %number of pixels
Nswap = floor(Ntotal/2); %how many pairs we can swap

%find big enough generator
factors = unique(factor(Ntotal));
possible_gen = primes(max(size(red)));
eliminated = setdiff(possible_gen,factors);
if mod(numel(eliminated),2)==0 %make length odd for median
    eliminated = [1,eliminated];
end
generator = median(eliminated);

%set up the swapping vectors
swapindices1 = 1+mod((1:Nswap)*generator, Ntotal);
swapindices2 = setdiff(1:Ntotal,swapindices1);
swapindices2 = swapindices2(1:numel(swapindices1)); %make sure both have the same length

%swap the pixels
red([swapindices1,swapindices2]) = red([swapindices2,swapindices1]);
green([swapindices1,swapindices2]) = green([swapindices2,swapindices1]);
blue([swapindices1,swapindices2]) = blue([swapindices2,swapindices1]);

%write and display
output = cat(3,red,green,blue);
imwrite(output,outputname);
subplot(2,1,1);
imshow(src)
subplot(2,1,2);
imshow(output);

4

JavaScript (+ tiền thưởng) - bộ lặp hoán đổi chia pixel

Hàm lấy một phần tử hình ảnh và

  1. Chia các pixel cho 8.
  2. Liệu một hoán đổi đảo ngược của các nhóm pixel.
  3. Đệ quy hoán đổi nếu nhóm pixel> = 8.
function E(el){
    var V=document.createElement('canvas')
    var W=V.width=el.width,H=V.height=el.height,C=V.getContext('2d')
    C.drawImage(el,0,0)
    var id=C.getImageData(0,0,W,H),D=id.data,L=D.length,i=L/4,A=[]
    for(;--i;)A[i]=i
    function S(A){
        var L=A.length,x=L>>3,y,t,i=0,s=[]
        if(L<8)return A
        for(;i<L;i+=x)s[i/x]=S(A.slice(i,i+x))
        for(i=4;--i;)y=[6,4,7,5,1,3,0,2][i],t=s[i],s[i]=s[y],s[y]=t
        s=[].concat.apply([],s)
        return s
    }
    var N=C.createImageData(W,H),d=N.data,A=S(A)
    for(var i=0;i<L;i++)d[i]=D[(A[i>>2]*4)+(i%4)]
    C.putImageData(N,0,0)
    el.src=C.canvas.toDataURL()
}

Núi Vòng kết nối


4

Python 2.7 + PIL, Cột / Hàng Scrambler

Phương pháp này chỉ đơn giản là xáo trộn các hàng và cột của hình ảnh. Chỉ có thể tranh giành một trong hai chiều hoặc cả hai. Ngoài ra, thứ tự của hàng / cột được xáo trộn mới dựa trên mật khẩu. Ngoài ra, một khả năng khác là xáo trộn toàn bộ mảng hình ảnh mà không xem xét kích thước.

Các kết quả:

Xáo trộn toàn bộ hình ảnh:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Xáo trộn các cột:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Xáo trộn các hàng:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Xáo trộn cả cột và hàng:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Tôi cũng đã thử áp dụng một số lần chạy cho hình ảnh, nhưng kết quả cuối cùng không khác nhau nhiều, chỉ là khó khăn để giải mã nó.

Mã số:

from PIL import Image
import random,copy

def scramble(im,columns,rows):
    pixels =list(im.getdata())

    newOrder=range(columns*rows)        
    random.shuffle(newOrder)            #shuffle

    newpixels=copy.deepcopy(pixels)
    for i in xrange(len(pixels)):
        newpixels[i]=pixels[newOrder[i]]

    im.putdata(newpixels)

def unscramble(im,columns,rows):
    pixels =list(im.getdata())

    newOrder=range(columns*rows)        
    random.shuffle(newOrder)            #unshuffle

    newpixels=copy.deepcopy(pixels)
    for i in xrange(len(pixels)):
        newpixels[newOrder[i]]=pixels[i]

    im.putdata(newpixels)

def scramble_columns(im,columns,rows):
    pixels =list(im.getdata())

    newOrder=range(columns)     
    random.shuffle(newOrder)            #shuffle

    newpixels=[]
    for i in xrange(rows):
        for j in xrange(columns):
            newpixels+=[pixels[i*columns+newOrder[j]]]

    im.putdata(newpixels)

def unscramble_columns(im,columns,rows):
    pixels =list(im.getdata())

    newOrder=range(columns)     
    random.shuffle(newOrder)            #shuffle

    newpixels=copy.deepcopy(pixels)
    for i in xrange(rows):
        for j in xrange(columns):
            newpixels[i*columns+newOrder[j]]=pixels[i*columns+j]

    im.putdata(newpixels)

def scramble_rows(im,columns,rows):
    pixels =list(im.getdata())

    newOrder=range(rows)        
    random.shuffle(newOrder)            #shuffle the order of pixels

    newpixels=copy.deepcopy(pixels)
    for j in xrange(columns):
        for i in xrange(rows):
            newpixels[i*columns+j]=pixels[columns*newOrder[i]+j]

    im.putdata(newpixels)

def unscramble_rows(im,columns,rows):
    pixels =list(im.getdata())

    newOrder=range(rows)        
    random.shuffle(newOrder)            #shuffle the order of pixels

    newpixels=copy.deepcopy(pixels)
    for j in xrange(columns):
        for i in xrange(rows):
            newpixels[columns*newOrder[i]+j]=pixels[i*columns+j]

    im.putdata(newpixels)


#set random seed based on the given password
def set_seed(password):
    passValue=0
    for ch in password:                 
        passValue=passValue+ord(ch)
    random.seed(passValue)

def encrypt(im,columns,rows,password):
    set_seed(password)
    # scramble(im,columns,rows)
    scramble_columns(im,columns,rows)
    scramble_rows(im,columns,rows)

def decrypt(im,columns,rows,password):
    set_seed(password)
    # unscramble(im,columns,rows)
    unscramble_columns(im,columns,rows)
    unscramble_rows(im,columns,rows)

if __name__ == '__main__':
    passwords=["yOs0ZaKpiS","NA7N3v57og","Nwu2T802mZ","6B2ec75nwu","FP78XHYGmn"]
    iterations=1
    filename="0RT8s.jpg"
    im=Image.open(filename)
    size=im.size
    columns=size[0]
    rows=size[1]

    for i in range(iterations):
        encrypt(im,columns,rows,passwords[i])
    im.save(filename.split(".")[0]+"_encrypted.jpg")

    for i in range(iterations):
        decrypt(im,columns,rows,passwords[iterations-i-1])
    im.save(filename.split(".")[0]+"_decrypted.jpg")

3

Winforms C #

Hình ảnh 1: nhập mô tả hình ảnh ở đây

Hình 2: nhập mô tả hình ảnh ở đây

Mã nguồn:

class Program
{
    public static void codec(String src, String trg, bool enc)
    {
        Bitmap bmp = new Bitmap(src);
        Bitmap dst = new Bitmap(bmp.Width, bmp.Height);

        List<Point> points = new List<Point>();
        for (int y = 0; y < bmp.Height; y++)
            for (int x = 0; x < bmp.Width; x++)
                points.Add(new Point(x, y));

        for (int y = 0; y < bmp.Height; y++)
        {
            for (int x = 0; x < bmp.Width; x++)
            {
                int py = Convert.ToInt32(y + 45 * Math.Sin(2.0 * Math.PI * x / 128.0));
                int px = Convert.ToInt32(x + 45 * Math.Sin(2.0 * Math.PI * y / 128.0));

                px = px < 0 ? 0 : px;
                py = py < 0 ? 0 : py;
                px = px >= bmp.Width ? bmp.Width - 1 : px;
                py = py >= bmp.Height ? bmp.Height - 1 : py;

                int srcIndex = x + y * bmp.Width;
                int dstIndex = px + py * bmp.Width;

                Point temp = points[srcIndex];
                points[srcIndex] = points[dstIndex];
                points[dstIndex] = temp;
            }
        }

        for (int y = 0; y < bmp.Height; y++)
        {
            for (int x = 0; x < bmp.Width; x++)
            {
                Point p = points[x + y * bmp.Width];
                if (enc)
                    dst.SetPixel(x, y, bmp.GetPixel(p.X, p.Y));
                else
                    dst.SetPixel(p.X, p.Y, bmp.GetPixel(x, y));
            }
        }

        dst.Save(trg);
    }


    static void Main(string[] args)
    {
        // encode
        codec(@"c:\shared\test.png", @"c:\shared\test_enc.png", true);

        // decode
        codec(@"c:\shared\test_enc.png", @"c:\shared\test_dec.png", false);
    }
}

1

Python 3.6 + pypng

Riffle / Master Shuffle

#!/usr/bin/env python3.6

import argparse
import itertools

import png

def read_image(filename):
    img = png.Reader(filename)
    w, h, data, meta = img.asRGB8()
    return w, h, list(itertools.chain.from_iterable(
        [
            (row[i], row[i+1], row[i+2])
            for i in range(0, len(row), 3)
        ]
        for row in data
    ))

def riffle(img, n=2):
    l = len(img)
    base_size = l // n
    big_groups = l % n
    base_indices = [0]
    for i in range(1, n):
        base_indices.append(base_indices[-1] + base_size + int(i <= big_groups))
    result = []
    for i in range(0, base_size):
        for b in base_indices:
            result.append(img[b + i])
    for i in range(big_groups):
        result.append(img[base_indices[i] + base_size])
    return result

def master(img, n=2):
    parts = [[] for _ in range(n)]
    for i, pixel in enumerate(img):
        parts[i % n].append(pixel)
    return list(itertools.chain.from_iterable(parts))

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('infile')
    parser.add_argument('outfile')
    parser.add_argument('-r', '--reverse', action='store_true')
    parser.add_argument('-i', '--iterations', type=int, default=1)
    parser.add_argument('-n', '--groupsize', type=int, default=2)
    parser.add_argument('-c', '--complex', nargs='+', type=int)

    args = parser.parse_args()

    w, h, img = read_image(args.infile)

    if args.complex:
        if any(-1 <= n <= 1 for n in args.complex):
            parser.error("Complex keys must use group sizes of at least 2")
        if args.reverse:
            args.complex = [
                -n for n in reversed(args.complex)
            ]
        for n in args.complex:
            if n > 1:
                img = riffle(img, n)
            elif n < -1:
                img = master(img, -n)
    elif args.reverse:
        for _ in range(args.iterations):
            img = master(img, args.groupsize)
    else:
        for _ in range(args.iterations):
            img = riffle(img, args.groupsize)

    writer = png.Writer(w, h)
    with open(args.outfile, 'wb') as f:
        writer.write_array(f, list(itertools.chain.from_iterable(img)))


if __name__ == '__main__':
    main()

Thuật toán của tôi áp dụng xáo trộn riffle theo một hướng và xáo trộn chính theo hướng khác (vì hai lần này là nghịch đảo của nhau), mỗi lần lặp lại, nhưng mỗi lần lặp lại được chia thành bất kỳ số nhóm con nào thay vì chỉ hai. Hiệu quả là bạn có thể tạo một khóa hoán vị đa vòng lặp vì hình ảnh sẽ không được khôi phục mà không biết chính xác trình tự xáo trộn và xáo trộn chính. Một chuỗi có thể được chỉ định với một loạt các số nguyên, với các số dương đại diện cho các riff và số âm đại diện cho các bậc thầy.

Tôi xáo trộn phong cảnh bằng phím [3, -5, 2, 13, -7]:

Cảnh 3 -5 2 13 -7

Thật thú vị, một số điều thú vị xảy ra từ [3, -5], trong đó một số tạo tác từ hình ảnh gốc còn sót lại:

Cảnh 3 -5

Đây là mẫu trừu tượng được xáo trộn bằng phím [2, 3, 5, 7, -11, 13, -17]:

Vòng 2 3 5 7 -11 13 -17

Nếu chỉ có một tham số sai trong khóa, thì việc xáo trộn sẽ không khôi phục lại hình ảnh:

Xáo trộn xấu

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.