จัดเรียงพิกเซลภาพใหม่ดังนั้นจึงไม่สามารถจดจำได้และนำกลับมาใช้ใหม่


86

สร้างโปรแกรมที่สามารถจัดเรียงพิกเซลใหม่ในภาพเพื่อให้ไม่สามารถจดจำได้ อย่างไรก็ตามโปรแกรมของคุณจะสามารถแปลงกลับเป็นรูปภาพดั้งเดิมได้

คุณสามารถเขียนสองฟังก์ชั่น - สำหรับการเข้ารหัสและถอดรหัสอย่างไรก็ตามหนึ่งฟังก์ชั่นที่ใช้ซ้ำ ๆ ให้ภาพต้นฉบับ (ตัวอย่างในคณิตศาสตร์ - f(x) = 1 - x) เป็นโบนัส

นอกจากนี้การสร้างรูปแบบบางอย่างในเอาต์พุตก็ให้โบนัสเช่นกัน

รูปภาพอาจถูกแทนด้วยอาร์เรย์ 1D / 2D หรือวัตถุรูปภาพหากภาษาของคุณรองรับ โปรดทราบว่าคุณสามารถเปลี่ยนลำดับพิกเซลได้เท่านั้น!

จะมีเหตุผลที่จะเลือกเป็นรหัสผู้ชนะซึ่งให้ภาพที่เป็นที่รู้จักน้อยกว่า แต่ฉันไม่ทราบวิธีการวัดอย่างแม่นยำทุกวิธีที่ฉันสามารถจินตนาการสามารถโกงได้ ดังนั้นฉันเลือกคำถามนี้ว่าเป็นการประกวดความนิยม - ให้ผู้ใช้เลือกคำตอบที่ดีที่สุด!

ภาพทดสอบ 1 (800 x 422 px): ภาพทดสอบ 2 (800 x 480 px): โปรดระบุด้วยภาพออกรหัส


คำถามนี้เป็นวิธีที่ใช้เวลานานมากในการพูดว่า "เขียนอัลกอริธึมการเข้ารหัสสำหรับรูปภาพที่มีเอาต์พุตเป็นรูปภาพ"
David Richerby

3
@DavidRicherby ... ที่ใช้พิกเซล / สีเดียวกัน ห้าพิกเซลสีดำใน "ภาพธรรมดา" -> ห้าพิกเซลสีดำใน "รูปภาพตัวเลข"
Daniel Beck

2
@ user2992539 เอาล่ะในกรณีนี้คุณอาจต้องการระบุอย่างชัดเจนว่าสิ่งนี้ถูกใช้เป็น tie-breaker มิฉะนั้นเพียงกล่าวว่าเป็นโบนัสที่ไม่มีความหมายมาก
Martin Ender

3
คำถามนี้ทำให้ผมคิดว่าแผนที่แมวของ Arnold ฉันไม่คิดว่ามันค่อนข้างจะเหมาะสมสำหรับจุดประสงค์นี้ แต่มันน่าสนใจในแบบเดียวกัน - การทำแผนที่ซ้ำหลายครั้งพอที่จะพาคุณกลับไปที่ภาพดั้งเดิม
trichoplax

4
ตอนนี้ที่อื่นในเครือข่าย Stack Exchange: Security.SEของทุกสถานที่
Doorknob

คำตอบ:


58

Python 2.7 (with PIL) - ไม่มี Pseudorandomness

ฉันแบ่งภาพเป็น 2 โดย 2 บล็อก (ไม่สนใจส่วนที่เหลือ) และหมุนแต่ละบล็อกโดย 180 องศาจากนั้นฉันก็ทำแบบเดียวกันกับบล็อก 3 โดย 3 แล้ว 4 และอื่น ๆ ถึงพารามิเตอร์ BLKSZ บางส่วน จากนั้นฉันก็ทำแบบเดียวกันกับ BLKSZ-1 แล้วก็ BLKSZ-2 ไปจนถึง 3 แล้วก็ 2 วิธีนี้จะกลับตัวเองอย่างแน่นอน ฟังก์ชัน unscramble คือฟังก์ชัน scramble

รหัส :

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!")

คุณสามารถทำการคำนวณเพื่อกำจัดความคล้ายคลึงทั้งหมดให้กับภาพต้นฉบับ: (BLKSZ = 50) ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

หรือทำให้การคำนวณมีประสิทธิภาพ: (BLKSZ = 10) ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่


6
เสียงเหมือนผลลัพธ์ที่ดีที่สุดคือถ้า BLKSZ จะมีขนาดประมาณครึ่งหนึ่งของภาพ อย่างไรก็ตามฉันชอบอัลกอริทึมและสำหรับ BLKSZ ขนาดเล็กมันดูเหมือนศิลปะสมัยใหม่! เย็น!
Somnium

11
ฉันลงคะแนนหลามเสมอ
qwr

แทนที่จะแย่งชิงค่าทั้งหมดตั้งแต่ 2 ถึง 50 บางทีคุณควรใช้เฉพาะจำนวนเฉพาะ?
Neil

@ Neil อาจเป็นไปได้ว่ามันจะสุ่มมากขึ้นและศิลปะน้อยลง
Somnium

BLKSZ = 10ภูมิทัศน์เจ๋งจริงๆ!
wchargin

52

C #, Winform

แก้ไขการเปลี่ยนวิธีที่คุณเติมอาร์เรย์พิกัดที่คุณสามารถมีรูปแบบที่แตกต่างกัน - ดูด้านล่าง

คุณชอบรูปแบบนี้ไหม?

แนวนอน

บทคัดย่อ

โบนัส:

กรี๊ด Scream สัญญาณรบกวน

การสลับแบบสุ่มหนึ่งครั้งทุกพิกเซลในครึ่งบนกับพิกเซลทั้งหมดในครึ่งล่าง ทำซ้ำขั้นตอนเดียวกันสำหรับการยกเลิกการพนัน (โบนัส)

รหัส

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;
    }
}

Program.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());
    }
  }
}

ทำเครื่องหมาย 'รหัสที่ไม่ปลอดภัย' ในคุณสมบัติโครงการเพื่อคอมไพล์

รูปแบบที่ซับซ้อน

การแย่งชิง

เปลี่ยนส่วนแรกของฟังก์ชั่นการทำงานได้สูงสุดถึง 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
ที่น่าสนใจ) ฉันสงสัยว่าด้วยวิธีการที่คล้ายกันเป็นไปได้ที่จะสร้างรูปแบบที่ซับซ้อนมากขึ้นในการส่งออก
Somnium

1
แนวคิดที่ดี - เกิดอะไรขึ้นกับเส้นตรงกลางเมื่อมีจำนวนบรรทัดผิดปกติ?
ข้อบกพร่อง

1
@ flawr แยกเป็นต่อพิกเซล หากมีจำนวนพิกเซลผิดปกติพิกเซลสุดท้ายจะไม่มีการเปลี่ยนแปลง หากมีจำนวนแถวคี่ครึ่งซ้ายของแถวกลางคือ 'ด้านบน' และครึ่งทางขวาคือ 'ด้านล่าง'
edc65

1
@ user2992539 ฉันคิดว่าคุณสามารถแบ่งย่อยได้มากขึ้น - แม้กระทั่งกระดานหมากรุก ด้วยการแบ่งย่อยมากขึ้นภาพจะเป็นที่รู้จักมากขึ้น
edc65

7
เช่นเดียวกับรุ่น "Scramble" ของคุณ!)
Somnium

43

C เบลอโดยพลการย้อนกลับได้ง่าย

ไปงานเลี้ยงสาย นี่คือรายการของฉัน!

วิธีนี้ทำให้เกิดภาพเบลอ ฉันเรียกมันว่าscramblur scramblurมันง่ายมาก ในการวนซ้ำมันเลือกพิกเซลสุ่มแล้วสลับกับพิกเซลใกล้เคียงที่เลือกแบบสุ่มในโมเดลผ้าใบแบบวงแหวน คุณระบุระยะทางสูงสุดที่กำหนดว่า "พิกเซลที่อยู่ใกล้เคียง" หมายถึง (1 หมายถึงเลือกพิกเซลที่อยู่ติดกันเสมอ) จำนวนการวนซ้ำและการเลือกตัวเลขสุ่มแบบสุ่ม ยิ่งระยะทางสูงสุดและจำนวนการวนซ้ำมากขึ้นเท่าไรผลลัพธ์ก็จะพร่ามัว

มันสามารถย้อนกลับได้โดยการระบุจำนวนลบของการทำซ้ำ (นี่เป็นเพียงความสะดวกในอินเตอร์เฟสบรรทัดคำสั่ง; จริงๆแล้วมันไม่มีสิ่งที่เรียกว่าการทำซ้ำเชิงลบ) ภายในจะใช้ LCPRNG 64 บิตแบบกำหนดเอง (ตัวสร้างตัวเลขหลอกเชิงเส้นเชิงเส้นเชิง Congruential) และสร้างบล็อกของค่าล่วงหน้า ตารางนี้อนุญาตให้วนลูปผ่านบล็อกทั้งไปข้างหน้าหรือย้อนกลับสำหรับการเล่น scrambling หรือ unscrambling ตามลำดับ

การสาธิต

สำหรับสองภาพแรกเมื่อคุณเลื่อนลงภาพแต่ละภาพจะเบลอโดยใช้การชดเชยสูงสุดที่สูงกว่า: สูงสุดคือภาพต้นฉบับ (เช่นการชดเชย 0 พิกเซล) ตามด้วย 1, 2, 4, 8, 16, 32, 64 , 128 และสุดท้ายคือ 256 การนับซ้ำคือ10⁶ = 1,000,000 สำหรับภาพทั้งหมดด้านล่าง

สำหรับภาพที่สองสองภาพแต่ละภาพเบลอโดยใช้การชดเชยที่ต่ำกว่าอย่างต่อเนื่อง- เช่นภาพเบลอส่วนใหญ่ถึงเบลอน้อยที่สุด - จากการชดเชยสูงสุด 256 ลงเหลือ 0 สนุก!

ภูมิประเทศ บทคัดย่อ

และสำหรับสองภาพถัดไปคุณสามารถเห็นความก้าวหน้าเต็มขนาดได้ที่นี่และที่นี่ :

จบไม่สวย ซิมป์สัน

รหัส

ฉันแฮ็คข้อมูลนี้ด้วยกันประมาณหนึ่งชั่วโมงในขณะที่ตื่นขึ้นมาในเช้าวันนี้และมันไม่มีเอกสารเลย ฉันอาจจะกลับมาในอีกสองสามวันและเพิ่มเอกสารเพิ่มเติมในภายหลังหากมีคนร้องขอ

//=============================================================================
// 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
เพิ่งเลื่อนผ่านคำตอบนี้ดูดีมาก
Thomas

1
คำตอบนี้สูงจริงๆ คุณคิดว่าคุณสามารถย้ายภาพพิเศษ (เช่นทุกอย่างยกเว้นภาพทดสอบสองภาพเบลอทั้งหมด) ไปที่แกลเลอรีนอกไซต์หรือไม่
Tim S.

@TimS - ทำแล้ว! ย่อส่วนลงเป็นภาพขนาดเล็ก
ทอดด์เลห์แมน

42

Python 3.4

  • โบนัส 1:การย้อนกลับด้วยตนเอง: การเรียกคืนภาพต้นฉบับซ้ำ
  • รูปภาพคีย์เสริม: รูปภาพดั้งเดิมสามารถกู้คืนได้โดยใช้รูปภาพคีย์เดียวกันอีกครั้ง
  • โบนัส 2:รูปแบบการผลิตในผลลัพธ์: รูปกุญแจถูกประมาณในพิกเซลที่ถูกแปลง

เมื่อได้รับโบนัส 2 โดยใช้รูปกุญแจเพิ่มเติมโบนัส 1 จะไม่สูญหาย โปรแกรมยังคงเป็นแบบผกผันของตัวเองหากมันทำงานด้วยอิมเมจคีย์เดิมอีกครั้ง

การใช้งานมาตรฐาน

ทดสอบภาพ 1:

ภาพทดสอบสัญญาณรบกวน 1

ภาพทดสอบ 2:

ภาพทดสอบสัญญาณรบกวน 2

การรันโปรแกรมด้วยไฟล์ภาพเดียวเป็นอาร์กิวเมนต์มันจะบันทึกไฟล์ภาพด้วยพิกเซลที่มีสัญญาณรบกวนตลอดทั้งภาพ เรียกใช้อีกครั้งด้วยสัญญาณรบกวนที่บันทึกไว้ไฟล์ภาพที่มีสัญญาณรบกวนนำมาใช้อีกครั้งซึ่งจะเรียกคืนต้นฉบับเนื่องจากกระบวนการ scrambling เป็นสิ่งที่ตรงกันข้าม

กระบวนการ scrambling เป็นการย้อนกลับด้วยตนเองเนื่องจากรายการของพิกเซลทั้งหมดแบ่งออกเป็น 2 รอบดังนั้นทุกพิกเซลจะถูกสลับกับพิกเซลอื่น ๆ หนึ่งพิกเซลเท่านั้น การรันครั้งที่สองจะสลับทุกพิกเซลด้วยพิกเซลที่สลับกันครั้งแรกโดยนำทุกอย่างกลับไปสู่การเริ่มต้น หากมีจำนวนพิกเซลคี่จะมีหนึ่งที่ไม่ย้าย

ขอบคุณคำตอบของ mfvonhเป็นคนแรกที่แนะนำ 2 รอบ

การใช้งานด้วยรูปกุญแจ

Scrambling Test image 1 พร้อมรูปภาพ Test 2 เป็นรูปกุญแจ

การทดสอบการแย่งชิง 1 กับการทดสอบ 2

Scrambling Test image 2 พร้อมรูป Test 1 เป็นรูปกุญแจ

การทดสอบการแย่งชิง 2 กับการทดสอบ 1

การรันโปรแกรมด้วยอาร์กิวเมนต์ไฟล์ภาพที่สอง (รูปภาพหลัก) แบ่งภาพต้นฉบับออกเป็นภูมิภาคตามภาพหลัก แต่ละภูมิภาคเหล่านี้แบ่งออกเป็น 2 รอบแยกต่างหากเพื่อให้เกิดการแย่งชิงกันภายในภูมิภาคและพิกเซลจะไม่ถูกย้ายจากภูมิภาคหนึ่งไปยังอีกภูมิภาคหนึ่ง สิ่งนี้จะกระจายพิกเซลไปในแต่ละภูมิภาคดังนั้นภูมิภาคจึงกลายเป็นสีจุดด่างดำที่สม่ำเสมอ แต่มีสีเฉลี่ยแตกต่างกันเล็กน้อยสำหรับแต่ละภูมิภาค สิ่งนี้ทำให้การประมาณคร่าวๆของภาพหลักในสีผิด

การสลับพิกเซลคู่เดียวกันอีกครั้งในแต่ละภูมิภาคดังนั้นแต่ละภูมิภาคจะกลับคืนสู่สถานะดั้งเดิมและภาพโดยรวมจะปรากฏขึ้นอีกครั้ง

ขอบคุณคำตอบของ edc65เป็นคนแรกที่แนะนำให้แบ่งภาพออกเป็นภูมิภาคฉันต้องการขยายการใช้ขอบเขตโดยพลการ แต่วิธีการแลกเปลี่ยนทุกอย่างในพื้นที่ 1 กับทุกสิ่งในพื้นที่ 2 หมายความว่าภูมิภาคต้องมีขนาดเท่ากัน ทางออกของฉันคือการทำให้ภูมิภาคเป็นฉนวนจากกันและกันและเพียงแค่สลับแต่ละภูมิภาคเข้าด้วยกัน เนื่องจากภูมิภาคไม่จำเป็นต้องมีขนาดใกล้เคียงกันจึงเป็นเรื่องง่ายที่จะใช้ขอบเขตที่มีรูปร่างตามอำเภอใจ

รหัส

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')

ภาพเขียน JPEG

ไฟล์. jpg นั้นได้รับการประมวลผลอย่างรวดเร็วมาก การทำเช่นนี้จะทำให้เกิดการไหม้หลังจากภาพเมื่อต้นฉบับถูกกู้คืน:

jpg เบิร์น

แต่จริงจังรูปแบบการสูญเสียจะส่งผลให้บางส่วนของพิกเซลสีมีการเปลี่ยนแปลงเล็กน้อยซึ่งในตัวเองทำให้การส่งออกไม่ถูกต้อง เมื่อมีการใช้รูปภาพคีย์และการสลับพิกเซลจะ จำกัด เฉพาะภูมิภาคความผิดเพี้ยนทั้งหมดจะถูกเก็บไว้ในพื้นที่ที่มันเกิดขึ้นจากนั้นกระจายให้ทั่วบริเวณนั้นเมื่อทำการกู้คืนรูปภาพ ความแตกต่างของความผิดเพี้ยนโดยเฉลี่ยระหว่างภูมิภาคทำให้เกิดความแตกต่างที่เห็นได้ชัดเจนดังนั้นพื้นที่ที่ใช้ในกระบวนการการแยกจะยังคงปรากฏให้เห็นในภาพที่ถูกเรียกคืน

การแปลงเป็น. png (หรือรูปแบบที่ไม่มีการสูญเสียใด ๆ ) ก่อนที่จะทำการตรวจสอบเพื่อให้แน่ใจว่าภาพที่ไม่มีรอยหยักนั้นเหมือนกับต้นฉบับโดยไม่มีการเบิร์นหรือการบิดเบี้ยว:

png โดยไม่ต้องเผา

รายละเอียดเล็กน้อย

  • กำหนดขนาดต่ำสุด 256 พิกเซลในพื้นที่ หากภาพได้รับอนุญาตให้แยกออกเป็นภูมิภาคที่เล็กเกินไปภาพต้นฉบับจะยังคงมองเห็นได้บางส่วนหลังจากการตรวจสอบ
  • หากมีมากกว่าหนึ่งภูมิภาคที่มีจำนวนพิกเซลคี่แล้วหนึ่งพิกเซลจากพื้นที่ที่สองจะถูกกำหนดใหม่เป็นครั้งแรกและต่อไป ซึ่งหมายความว่าจะมีเพียงหนึ่งภูมิภาคเท่านั้นที่มีจำนวนพิกเซลคี่และดังนั้นจึงมีเพียงหนึ่งพิกเซลเท่านั้นที่จะไม่มีการแกะสลัก
  • มีอาร์กิวเมนต์ตัวเลือกที่สามซึ่ง จำกัด จำนวนภูมิภาค ตัวอย่างเช่นการตั้งค่านี้เป็น 2 จะให้ภาพที่มีสัญญาณรบกวนสองโทน สิ่งนี้อาจดูดีขึ้นหรือแย่ลงขึ้นอยู่กับภาพที่เกี่ยวข้อง หากมีการระบุหมายเลขไว้ที่นี่ภาพจะสามารถเรียกคืนได้โดยใช้หมายเลขเดิมอีกครั้ง
  • จำนวนสีที่แตกต่างในภาพต้นฉบับยัง จำกัด จำนวนภูมิภาคด้วย หากภาพต้นฉบับเป็นแบบทูโทนโดยไม่คำนึงถึงคีย์รูปภาพหรืออาร์กิวเมนต์ที่สามอาจมีได้สูงสุด 2 ภูมิภาคเท่านั้น

2
+1 เสียงปรบมือ! ฉันคิดเกี่ยวกับเรื่องนี้อย่างคลุมเครือ แต่พบว่ามันยากเกินไปที่จะนำไปใช้
edc65

1
อันนี้ยอดเยี่ยม ฉันได้ส่งรายการแล้ว แต่ฉันชอบคุณดีกว่าเนื่องจากคุณสมบัติของภาพหลัก
ทอดด์เลห์แมน

ฉันอยากรู้ว่าภาพทั้งสองนี้เป็นอย่างไรต่อกัน: lardlad.com/assets/wallpaper/simpsons1920.jpgและblogs.nd.edu/oblation/files/2013/09/BreakingBad.jpg (ลดขนาดเป็น 720x450 หรือ อะไรก็ตามที่เหมาะสมและแน่นอนถูกแปลงเป็น PNG ล่วงหน้าเพื่อหลีกเลี่ยงการเบิร์นไฟล์ JPEG)
ทอดด์เลห์แมน

2
@ToddLehman อัลกอริทึมของฉันถูก จำกัด โดยต้องเป็นสิ่งที่ตรงกันข้าม หากคุณต้องการที่จะเห็นวิธีการที่น่าสนใจจริงๆบางอย่างที่จะสับหนึ่งภาพมีลักษณะคล้ายกับคนอื่นคุณควรมีลักษณะที่อเมริกันกอธิคในจานสีของโมนาลิซ่า บางส่วนของโปรแกรมเหล่านี้จะทำสิ่งที่น่าอัศจรรย์กับภาพที่คุณพูดถึง
trichoplax

2
คุณลักษณะภาพหลักทำให้ส่วนหัวและไหล่อยู่เหนือส่วนที่เหลือ
Jack Aidley

33

นี่คือการแปลงแบบไม่สุ่มสำหรับการเปลี่ยนแปลง

  1. วางคอลัมน์คู่ทั้งหมดทางซ้ายและคอลัมน์คี่ทั้งหมดทางด้านขวา
  2. ทำซ้ำnxครั้ง
  3. ทำเช่นเดียวกันสำหรับแถวnyครั้ง

การเปลี่ยนแปลงเกือบจะเป็นแบบผกผันตัวเองการทำซ้ำการแปลงทั้งหมดsize_xครั้ง (ในทิศทาง x) จะคืนค่าภาพต้นฉบับ ฉันไม่ได้คำนวณคณิตศาสตร์ที่แน่นอน แต่การใช้จำนวนเต็มจำนวนเต็มในการint(log_2(size_x))ผลิตการสับที่ดีที่สุดกับภาพผีที่เล็กที่สุด

ภูเขาสับ ป้อนคำอธิบายรูปภาพที่นี่

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))

นี่คือลักษณะการวนซ้ำขั้นตอนแรก 20 ลักษณะ (nx = ny ให้สังเกตผลของความละเอียดที่ต่างกัน) ป้อนคำอธิบายรูปภาพที่นี่


7
นั่นเป็นอัลกอริธึมที่ยอดเยี่ยมจริงๆ และคุณควรได้รับโบนัสทั้งหมดสำหรับการใช้รูป Lena Söderberg :)
ทอดด์เลห์แมน


24

มาติกา

ตรงนี้ค่อนข้างตรงไปตรงมา ฉันเลือก5 * nPixelsคู่พิกัดแบบสุ่มและสลับพิกเซลทั้งสองนั้น (ซึ่งปิดบังภาพทั้งหมด) ในการถอดรหัสมันฉันทำแบบเดียวกันในทางกลับกัน แน่นอนฉันต้องเริ่มต้น PRNG เพื่อให้ได้คู่พิกัดเดียวกันในทั้งสองขั้นตอน

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
   ];

ข้อแตกต่างระหว่างทั้งสองฟังก์ชั่นคือในReverse@ unscrambleทั้งสองฟังก์ชั่นถ่ายภาพวัตถุจริง คุณสามารถใช้พวกเขาดังต่อไปนี้:

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

outและinเหมือนกัน นี่คือสิ่งที่scrดูเหมือนว่า:

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่


4
ที่ดี! ปัญหาเดียวคือมันปลอดภัยกว่าที่จะทำให้ PRNG เป็นตัวของตัวเองเพราะถ้าหลังจากเวลาผ่านไป Mathematica คิดว่าจะเปลี่ยนอัลกอริทึม PRNG สิ่งนี้จะไม่ถอดรหัสรูปภาพที่เข้ารหัสเก่า!
Somnium

1
ดี คุณควรจะได้ผลลัพธ์เดียวกันกับ Permute และ FindPermutation
DavidC

ฉันไม่แน่ใจว่าฉันเข้าใจ คุณสามารถป้อนการเปลี่ยนแปลงที่แม่นยำที่คุณต้องการเป็นรายการของรอบ
DavidC

@DavidCarraher อืมน่าสนใจ ฉันจะต้องจำการเปลี่ยนรูปดั้งเดิมFindPermutationไม่ได้หรือไม่?
Martin Ender

หรืออาจจะเป็นสิ่งที่{c, a, b}[[{2, 3, 1}]]สามารถนำมาใช้?
Somnium

22

C # (+ โบนัสสำหรับอัลกอริทึมแบบสมมาตร)

มันทำงานได้โดยการค้นหาสิ่งxนั้นx^2 == 1 mod (number of pixels in image)และคูณดัชนีของแต่ละพิกเซลด้วยxเพื่อหาตำแหน่งใหม่ สิ่งนี้จะช่วยให้คุณใช้อัลกอริธึมที่แน่นอนในการเบียดเสียดและถอดรหัสภาพ

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;
        }
    }
}

ภาพการทดสอบครั้งแรกสัญญาณรบกวน

ภาพทดสอบที่สองมีสัญญาณรบกวน


1
เคลฟเวอร์หนึ่ง) จะมีวิธีแก้สมการสมการที่สอดคล้องกันหรือไม่?
Somnium

1
@ user2992539 จะมีวิธีแก้ปัญหาเล็กน้อย1(ภาพดั้งเดิม) และmodulo-1(ภาพกลับ / กลับด้าน) ตัวเลขส่วนใหญ่จะมีการแก้ปัญหาที่ไม่น่ารำคาญ แต่มีข้อยกเว้นบางอย่างก็ดูเหมือนว่า (เกี่ยวข้องกับการแยกตัวประกอบเฉพาะของmodulo)
ทิม S.

ในขณะที่ฉันเข้าใจวิธีแก้ปัญหาเล็กน้อยนำไปสู่ภาพคล้ายกับการป้อนข้อมูลหนึ่ง
Somnium

ถูกต้อง: 1ส่งภาพต้นฉบับและ-1เอาท์พุทเช่นimgur.com/EiE6VW2
Tim S.

19

C # ตรงกันข้ามตนเองไม่มีการสุ่ม

หากภาพต้นฉบับมีขนาดที่มีกำลังสองแล้วแต่ละแถวและคอลัมน์จะถูกแลกเปลี่ยนกับแถวและคอลัมน์ที่มีรูปแบบบิตที่ตรงกันข้ามเช่นภาพกว้าง 256 จากนั้น 0xB4 แถวจะแลกเปลี่ยนกับแถว 0x2D ภาพขนาดอื่น ๆ จะแบ่งออกเป็นสี่เหลี่ยมที่มีด้านข้างของกำลัง 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;
        }
    }
}

ภาพแรก:

ภาพแรกมีสัญญาณรบกวน

ภาพที่สอง:

ภาพที่สองมีสัญญาณรบกวน


2
ฉันชอบเอาต์พุต "plaid" ของอันนี้
Brian Rogers

14

C #

วิธีการเดียวกันสำหรับการต่อสู้และการถอนเงิน ฉันขอขอบคุณข้อเสนอแนะในการปรับปรุงนี้

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;
    }
}

ผลลัพธ์ส่งผลในลายสก๊อตประสาทหลอน คนแรก อันที่สอง


ดีมากที่นี่มีรูปแบบที่เป็นแถบ)
Somnium

1
คุณกรุณาสลับสองภาพได้ไหม? ในคำถามภาพภูเขาเป็นครั้งแรก
อัล

1
คุณสามารถรวมคำอธิบายสั้น ๆ เกี่ยวกับอัลกอริทึมได้หรือไม่?
trichoplax

14

Python 2 (การย้อนกลับของตัวเอง, ไม่มีการสุ่ม, คำนึงถึงบริบท)

สิ่งนี้จะไม่ชนะรางวัลใด ๆ สำหรับ "ที่เป็นที่รู้จักน้อยที่สุด" แต่อาจทำให้ได้คะแนนเป็น "น่าสนใจ" :-)

ฉันต้องการสร้างบางสิ่งบางอย่างที่ไวต่อบริบทโดยที่การแย่งของพิกเซลขึ้นกับภาพนั้น

แนวคิดนี้ค่อนข้างง่าย: จัดเรียงพิกเซลทั้งหมดตามค่านิยมบางอย่างที่ได้มาจากสีของพิกเซลแล้วสลับตำแหน่งของพิกเซลแรกในรายการนั้นด้วยค่าสุดท้ายค่าที่สองที่มีที่สองเป็นที่สุดท้ายและต่อไปเรื่อย ๆ

น่าเสียดายที่วิธีการง่าย ๆ นี้มีปัญหากับพิกเซลที่มีสีเดียวกันดังนั้นเพื่อให้โปรแกรมของฉันกลับมามีความซับซ้อนมากขึ้น ...

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"

นี่คือผลลัพธ์ที่ได้: (เอบีเอส (R-128) + เอบีเอส (G-128) + เอบีเอส (B-128)) // 128 (เอบีเอส (R-128) + เอบีเอส (G-128) + เอบีเอส (B-128)) // 128

คุณสามารถบรรลุผลลัพธ์ที่แตกต่างกันมากโดยการเปลี่ยนฟังก์ชั่นแฮช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 + ข) // 600

  • 0:

    0


3
ว้าว! อันนี้ยอดเยี่ยม !!! เยี่ยมมาก!
ทอดด์เลห์แมน

1
นั่นเป็นสิ่งที่น่าสนใจที่สุด การทำงานที่ดี!
bebe

12

Mathematica (+ โบนัส)

การทำเช่นนี้จะยุบช่องสีและทำให้ภาพเป็นข้อมูลที่มีความยาวหนึ่งรายการ ผลลัพธ์เป็นรุ่นที่มีสัญญาณรบกวนต่ำกว่าที่เป็นที่รู้จักเนื่องจากไม่มีการกระจายสีเหมือนกับต้นฉบับ (เนื่องจากข้อมูลนั้นมีสัญญาณรบกวน) นี่เป็นสิ่งที่ชัดเจนที่สุดในภาพที่มีสัญญาณรบกวนที่สอง แต่ถ้าคุณมองอย่างใกล้ชิดคุณจะเห็นเอฟเฟกต์แบบเดียวกันในภาพแรก ฟังก์ชั่นเป็นสิ่งที่ตรงกันข้าม

มีความคิดเห็นว่าสิ่งนี้อาจไม่ถูกต้องเพราะจะแก้ไขปัญหาต่อหนึ่งช่อง ฉันคิดว่ามันควรจะเป็น แต่มันไม่ใช่เรื่องใหญ่ การเปลี่ยนแปลงเพียงอย่างเดียวที่จำเป็นในการช่วงชิงพิกเซลทั้งหมด (แทนที่จะเป็นต่อแชแนล) คือการเปลี่ยนFlatten @ xเป็น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]]

คำอธิบาย

กำหนดฟังก์ชั่นที่ใช้อาร์เรย์f 2 มิติ xฟังก์ชั่นใช้ผลิตภัณฑ์ของขนาดของภาพเป็นเมล็ดสุ่มแล้วแบนอาร์เรย์ลงในรายการ 1 มิติf(เงาในเครื่อง) จากนั้นมันจะสร้างรายการของแบบฟอร์ม{1, 2, ... n}ที่nมีความยาวของfแบบสุ่มอนุญาตให้ลิสต์นั้นแบ่งพาร์ติชันออกเป็นส่วน ๆ ของ 2 (เช่นเช่น{{1, 2}, {3, 4}, ...}(วางตัวเลขสุดท้ายหากขนาดเป็นคี่ทั้งคู่) จากนั้นทำการfสลับค่าที่ ตำแหน่งที่ระบุในแต่ละรายการย่อยที่เพิ่งสร้างขึ้นและในที่สุดก็เปลี่ยนรูปร่างรายการที่อนุญาตกลับไปเป็นมิติเดิมของxมัน scrambles ต่อช่องเพราะนอกเหนือจากการยุบขนาดภาพFlattenคำสั่งยังยุบข้อมูลช่องในแต่ละพิกเซล ฟังก์ชันนี้เป็นค่าผกผันของมันเองเนื่องจากวงรอบนั้นมีเพียงสองพิกเซลต่อพิกเซล

การใช้

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

f @ img1 // Image

ป้อนคำอธิบายรูปภาพที่นี่

f @ f @ img1 // Image

ป้อนคำอธิบายรูปภาพที่นี่

f @ img2 // Image

ป้อนคำอธิบายรูปภาพที่นี่

f @ f @ img2 // Image

ป้อนคำอธิบายรูปภาพที่นี่

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

ป้อนคำอธิบายรูปภาพที่นี่


1
ฉันเดาว่านี่จะไม่เป็นไปตามเกณฑ์เนื่องจากมันสลับกับขนาดที่เล็กกว่าพิกเซล
trichoplax

1
ฉันไม่คิดว่ามันเป็นคำตอบที่ถูกต้อง แต่ฉันก็ชอบเช่นกัน มันบิดที่น่าสนใจเพื่อให้ +1 แล้ว ...
Trichoplax

1
@githubphagocyte ดูอัปเดต :)
mfvonh

ยอดเยี่ยม - ฉันไปถึง +1 อีกครั้ง แต่แน่นอนว่าฉันไม่สามารถทำได้สองครั้ง ...
trichoplax

1
@ githubphagocyte โอ้ใช่ฉันลืมไวยากรณ์สั้น ๆ ที่แปลกประหลาด ใช่. f @ f @ img1 // Imageคือ (ในรูปแบบเต็ม)Image[f[f[img1]]]
mfvonh

10

Matlab (+ โบนัส)

โดยทั่วไปฉันจะสลับตำแหน่งของสองพิกเซลโดยการสุ่มและติดแท็กแต่ละพิกเซลที่ถูกสลับดังนั้นมันจะไม่ถูกสลับอีก สคริปต์เดียวกันสามารถใช้อีกครั้งสำหรับ 'ถอดรหัส' เพราะฉันรีเซ็ตตัวสร้างตัวเลขสุ่มในแต่ละครั้ง สิ่งนี้ทำจนเกือบทุกพิกเซลเปลี่ยน (นั่นคือสาเหตุที่ stepize มากกว่า 2)

แก้ไข: เพิ่งเห็นว่ามาร์ตินBüttnerใช้วิธีการที่คล้ายกัน - ฉันไม่ได้ตั้งใจที่จะคัดลอกความคิด - ฉันเริ่มเขียนรหัสของฉันเมื่อไม่มีคำตอบขอโทษด้วย ฉันยังคิดว่าเวอร์ชั่นของฉันใช้ความคิดที่แตกต่างกัน =) (และอัลกอริทึมของฉันไม่มีประสิทธิภาพมากขึ้นถ้าคุณดูที่บิตที่สุ่มเลือกพิกัดสองค่า ^^)

ภาพ

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')

ฉันไม่เข้าใจรหัสของคุณถูกนำไปใช้เป็นครั้งที่สองในรูปที่เข้ารหัสจะถอดรหัสหรือไม่
Somnium

2
แน่นอน: แต่ละครั้งที่มีการสลับสองพิกเซลอย่างแน่นอนและจะไม่ถูกสลับอีกครั้งในระหว่างกระบวนการทั้งหมด เนื่องจากตัวเลข 'สุ่ม' ทั้งสองเท่ากันทุกประการ (เนื่องจากการรีเซ็ตตัวสร้างตัวเลขสุ่ม) คู่พิกเซลจะได้รับการสลับกลับ (RNG อาศัยหมายเลขที่สร้างไว้ก่อนหน้านี้เสมอสำหรับการสร้างหมายเลขถัดไปฉันหวังว่าสิ่งนี้จะชัดเจน)
ข้อผิดพลาด

1
ฮ่านั่นคือความคิดเริ่มต้นของฉันจริง ๆ แต่จากนั้นฉันก็ไม่สามารถใส่ใจได้เพื่อให้แน่ใจว่าแต่ละพิกเซลจะถูกสลับสับเปลี่ยนกันเพียงครั้งเดียวเพราะฉันต้องทำงาน : D +1!
Martin Ender

3
@ user2992539 ลองดูOctaveซึ่งเป็นทางเลือก opensource ที่ดีสำหรับ matlab และคุณสามารถเรียกใช้รหัส matlab ได้ 99% โดยตรงในระดับแปดเสียง
ข้อบกพร่อง

2
ฉันคิดว่าถ้าคุณเหลื่อมกับรูปภาพของคุณอย่างหนักคุณยังสามารถเห็นโครงสร้างบางส่วนจากอินพุต (ซึ่งเกิดจากการไม่ย้ายพิกเซลทั้งหมด) ฉันเดาว่าถ้าคุณเปลี่ยนอัลกอริทึมการเลือกของคุณให้ทำงานใน O (1) แทน O (∞) คุณสามารถแก้ไขได้ ;)
Martin Ender

10

Mathematica- ใช้การเปลี่ยนแปลงเพื่อแย่งกันและผกผันกับการถอดรหัส

รูปภาพ jpg เป็น{r,g,b}สีพิกเซลแบบสามมิติ (โครงสร้างสามมิติคือชุดพิกเซลตามแถวคอลัมน์และสี) มันสามารถถูกทำให้แบนเป็นรายการของ{r,g,b}อเนกประสงค์ได้จากนั้นทำการเรียงลำดับตามรายการวงรอบ "ที่รู้จัก" และในที่สุดก็รวมเข้ากับอาร์เรย์ของมิติเดิมอีกครั้ง ผลที่ได้คือภาพที่มีสัญญาณรบกวน

Unscrambling ใช้ภาพที่มีสัญญาณรบกวนและประมวลผลด้วยการย้อนกลับของรายการวงจร มันออกมาใช่ภาพต้นฉบับ

ดังนั้นฟังก์ชั่นเดียว (ในกรณีปัจจุบันscramble) ทำหน้าที่กลั่นกรองและกำจัดสัญญาณภาพในภาพ

ภาพถูกป้อนพร้อมกับหมายเลขเมล็ด (เพื่อให้แน่ใจว่าตัวสร้างหมายเลขสุ่มจะอยู่ในสถานะเดียวกันสำหรับการแย่งชิงและยกเลิกการสุ่มเสี่ยง) เมื่อพารามิเตอร์ย้อนกลับเป็นเท็จฟังก์ชันจะช่วงชิง เมื่อเป็น True ฟังก์ชันจะถอดรหัสสัญญาณ


การแย่งชิง

พิกเซลแบนและรายการแบบสุ่มของรอบจะถูกสร้างขึ้น Permute ใช้วงรอบเพื่อสลับตำแหน่งของพิกเซลในรายการที่แบน

ถอดรหัส

ฟังก์ชั่นเดียวกันscrambleนี้ใช้สำหรับยกเลิกการเสี่ยงโชค อย่างไรก็ตามลำดับของรายการวงจรจะกลับรายการ

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]]

ตัวอย่าง

เมล็ดเดียวกัน (37) ใช้สำหรับการแย่งชิงและการไม่เอาชีวิตรอด

สิ่งนี้ก่อให้เกิดภาพกวนของภูเขา ภาพด้านล่างแสดงให้เห็นว่าตัวแปร scrambledMount สามารถใช้แทนภาพจริงของฉากภูเขา

scrambledMount=scramble[mountain, 37, True]

mount1


ตอนนี้เราวิ่งกลับกัน scrambledMount ถูกป้อนและภาพต้นฉบับจะพักฟื้น

 scramble[scrambledMount, 37, True]

mount2


สิ่งเดียวกันสำหรับแวดวง:

circles1


 scramble[scrambledCircles, 37, True]

circles2


ฉันไม่เห็นว่าภาพจะเป็นแบบสามมิติได้อย่างไร
edc65

1
@ edc65, แถว x คอลัมน์ x สี ภาพภูเขาคือ 422 แถวคูณ 800 คอลัมน์ 3 สี ถ้าอาเรย์นั้นแบนมันจะให้ข้อมูล 1,012800 ชิ้นเป็นอาเรย์หนึ่งมิตินั่นคือเป็นรายการ
DavidC

@ edc65 ฉันควรเพิ่ม Permute ที่ใช้ในการจัดเรียงสีเป็น rgb อเนกประสงค์ ฉันไม่ได้ทำให้แบนอย่างนั้นอีกเพราะฉันไม่สนใจที่จะทำการเปลี่ยนแปลงใด ๆ ภายในรายการสีของพิกเซลใด ๆ หากคุณพิจารณาข้อมูล rgb {r, g, b} เป็นองค์ประกอบเราจะพูดถึงอาร์เรย์ 2 มิติ เมื่อดูด้วยวิธีนี้คุณจะต้องตั้งคำถามอย่างถี่ถ้วน (ภาพจะเป็นแบบสามมิติได้อย่างไร) ที่คุณยกขึ้น ในความเป็นจริงมันอาจเป็นเรื่องปกติมากขึ้นที่จะถือว่าภาพเป็นอาเรย์ 2 มิติโดยไม่คำนึงถึงข้อเท็จจริงที่ว่าองค์ประกอบ rgb เพิ่มอีกมิติหนึ่ง
DavidC

10

หลาม

ฉันชอบจิ๊กซอว์นี้เขาดูน่าสนใจและฉันก็มาพร้อมกับฟังก์ชั่น wraped และ Movement เพื่อใช้กับภาพ

Wraped

ฉันอ่านรูปภาพเป็นข้อความ (จากซ้ายไปขวาขึ้นและลง) และเขียนเป็นหอยทาก

ฟังก์ชั่นนี้เป็นวงจร: มี in N, f ^ (n) (x) = x ตัวอย่างเช่นสำหรับรูปภาพ 4 * 2, f (f (f (x))) x

การเคลื่อนไหว

ฉันใช้จำนวนสุ่มและย้ายแต่ละคอลัมน์และ ligne จากมัน

รหัส

# 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

รูปภาพ

การหมุนครั้งแรก: ป้อนคำอธิบายรูปภาพที่นี่

เปลี่ยนแปลงแล้ว: ป้อนคำอธิบายรูปภาพที่นี่

และด้วย rotaion ล่าสุด: ป้อนคำอธิบายรูปภาพที่นี่

สำหรับตัวอย่างอื่น ๆ : ป้อนคำอธิบายรูปภาพที่นี่


2
คุณคืนค่ารูปภาพดั้งเดิมอย่างไร
trichoplax

ถ้ามันเป็นแค่การหมุนฉันสามารถทำได้ในระยะเวลาหนึ่ง (ขึ้นอยู่กับขนาด) อย่างไรก็ตามถ้าฉันมีการเรียงสับเปลี่ยนฉันไม่แน่ใจว่ามันเป็นวงจรดังนั้นฉันจึงมีฟังก์ชั่นที่สองซึ่งเปลี่ยนเฉพาะสิ่งที่ PM2 [_i, _j] = PM1 [i, j] กลายเป็น PM2 [i, j] = PM1 [ _i, _j] และ PM3 [(i + a)% w, (j + a)% h] = PM2 [i, j] กลายเป็น PM3 [(ia)% w, (ja)% h] = PM2 [i, เจ] ฉันกำลังมองหาวิธีที่จะทำได้โดยไม่ต้องเปลี่ยนสองบรรทัดนี้
Faquarl

8

VB.NET (+ โบนัส)

สิ่งนี้ใช้ความคิดของข้อบกพร่องขอบคุณเขา แต่สิ่งนี้ใช้การสลับและการตรวจสอบอัลกอริทึมที่แตกต่างกัน โปรแกรมเข้ารหัสและถอดรหัสด้วยวิธีเดียวกัน

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

ภาพที่ส่งออก:


8

หลังจากได้รับการเตือนว่านี่เป็นเรื่องเกี่ยวกับการสลับพิกเซลและไม่เปลี่ยนแปลงนี่คือวิธีแก้ปัญหาของฉันสำหรับสิ่งนี้:

scrambled: ป้อนคำอธิบายรูปภาพที่นี่

เรียกคืน: ป้อนคำอธิบายรูปภาพที่นี่

สิ่งนี้ทำได้โดยการสุ่มลำดับพิกเซล แต่เพื่อให้สามารถคืนค่ามันการสุ่มจะได้รับการแก้ไข สิ่งนี้ทำได้โดยใช้การสุ่มหลอกด้วยเมล็ดพืชคงที่และสร้างรายการดัชนีที่อธิบายว่าพิกเซลใดที่จะสลับ เนื่องจากการสลับจะเหมือนกันรายการเดียวกันจะคืนค่ารูปภาพดั้งเดิม

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]));
    }
  }
}

โปรดทราบว่าการใช้อัลกอริทึมนี้ในรูปแบบการบีบอัดแบบสูญหายจะไม่ให้ผลลัพธ์เดียวกันเนื่องจากรูปแบบรูปภาพจะเปลี่ยนข้อมูล สิ่งนี้จะทำงานได้ดีกับตัวแปลงสัญญาณที่ไม่มีการสูญเสียเช่น PNG


8

มาติกา

เรากำหนดฟังก์ชั่นผู้ช่วยhและฟังก์ชั่น scrambling scrambleเป็น:

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]
        ]
      ]
    ]
  ];

หลังจากโหลดภาพคุณสามารถเรียกได้scramble[img, k]ว่าkเป็นจำนวนเต็มใดเพื่อแย่งภาพ การโทรอีกครั้งพร้อม-kจะตกหลุมรัก (ถ้าkเป็น0เช่นนั้นจะไม่มีการเปลี่ยนแปลง) โดยทั่วไปแล้วkควรเลือกให้เป็นแบบ100ที่ให้ภาพที่มีสัญญาณรบกวน:

ตัวอย่างผลลัพธ์ 1

ตัวอย่างผลลัพธ์ 2


7

Matlab: การลบแถวและคอลัมน์ตามการแปรปรวนรวมแถว / คอลัมน์

ดูเหมือนว่าจะเป็นปริศนาที่สนุกฉันจึงคิดเกี่ยวกับมันและสร้างฟังก์ชั่นต่อไปนี้ขึ้นมา มันขึ้นอยู่กับความแปรปรวนของผลรวมของพิกเซลและค่าพิกเซลของคอลัมน์ในระหว่างการเลื่อนแบบวงกลม: มันเลื่อนแต่ละแถวจากนั้นแต่ละคอลัมน์โดยรวมผลรวมของค่าพิกเซลของแถว / คอลัมน์ (สมมติว่า uint8 สำหรับทั้งจำนวนในตัวแปรการเปลี่ยนแปลง ) สิ่งนี้สามารถย้อนกลับได้โดยการเลื่อนแต่ละคอลัมน์จากนั้นเรียงแถวด้วยผลรวมของพวกเขาในทิศทางตรงกันข้าม

มันไม่ได้สวยเหมือนคนอื่น ๆ แต่ฉันชอบที่มันเป็นแบบไม่สุ่มและระบุอย่างครบถ้วนโดยภาพ - ไม่มีการเลือกพารามิเตอร์

ตอนแรกฉันออกแบบมันเพื่อเลื่อนแต่ละช่องสีแยกกัน แต่จากนั้นฉันสังเกตเห็นสเปคเพื่อย้ายพิกเซลแบบเต็มเท่านั้น

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);

ภาพทดสอบครั้งแรก ภาพทดสอบ Secont


6

ชวา

โปรแกรมนี้สุ่มสลับพิกเซล (สร้างพิกเซลเป็นพิกเซลแมป) แต่แทนที่จะใช้ฟังก์ชั่นแบบสุ่มก็ใช้ Math.sin () (จำนวนเต็ม x) มันย้อนกลับได้อย่างเต็มที่ ด้วยภาพทดสอบมันสร้างรูปแบบบางอย่าง

พารามิเตอร์: หมายเลขจำนวนเต็ม (จำนวนการผ่านจำนวนลบเพื่อย้อนกลับ 0 ไม่ทำอะไรเลย), ผู้วิเศษอินพุตและอิมเมจเอาท์พุท (อาจเหมือนกัน) ไฟล์เอาต์พุตควรอยู่ในรูปแบบที่ใช้การบีบอัดแบบไม่สูญเสียข้อมูล

1 ผ่าน: ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

100 รอบ (ใช้เวลาไม่กี่นาทีในการทำ): ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

รหัส:

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 พร้อม PIL

สายไปงานเลี้ยงเล็ก ๆ น้อย ๆ แต่ฉันคิดว่ามันคงจะสนุกที่จะแปลงภาพให้กลายเป็นลายสก๊อต เริ่มแรกเราเลื่อนคอลัมน์ขึ้นหรือลง 4 เท่าของจำนวนคอลัมน์ (แม้แต่คอลัมน์ลง, คอลัมน์คี่ขึ้น) จากนั้นเราเลื่อนแถวไปทางซ้ายหรือขวา 4 เท่าของจำนวนแถว (แม้แต่คอลัมน์ทางซ้ายคอลัมน์ขวาคี่)

ผลที่ได้คือค่อนข้าง Tartanish

เพื่อย้อนกลับเราแค่ทำตามลำดับตรงกันข้ามแล้วเลื่อนตามจำนวนที่ตรงกันข้าม

รหัส

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)

ผล

ลายสก๊อตจากภาพ 1:

1.jpg ลายสก๊อต

รูปแบบลายสก๊อต 2:

2.png ลายสก๊อต


2
ดีมาก! เป็นไปได้ไหมที่จะได้เส้นทแยงมุมไปตามมุม 45 °?
ทอดด์เลห์แมน

2
เป็นไปได้ด้วยการเปลี่ยนเส้นออฟเซ็ตเป็น: offset = x*xsize/ysize และ offset = y*ysize/xsize มันไม่ได้ซ่อนรูปภาพด้วยโชคไม่ดี
jrrl

5

Python (+ โบนัส) - การเรียงสับเปลี่ยนพิกเซล

ในวิธีนี้ทุกพิกเซลจะถูกวางในตำแหน่งอื่นโดยมีข้อ จำกัด ที่พิกเซลอื่นจะถูกวางในตำแหน่งแรก ในทางคณิตศาสตร์มันคือการเรียงสับเปลี่ยนที่มีความยาววงรอบ 2 ดังนั้นวิธีนี้จึงเป็นวิธีที่ตรงกันข้าม

ในการหวนกลับมันคล้ายกับ mfvonh แต่การส่งนี้เป็น Python และฉันต้องสร้างการเรียงสับเปลี่ยนที่ตัวเอง

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

ภาพทดสอบแรก: ภาพทดสอบครั้งแรก ภาพทดสอบครั้งที่สอง: ภาพทดสอบที่สอง


5

Python 2.7 + PIL แรงบันดาลใจจากเกมไขปริศนา

เพิ่งมีความคิดอื่น โดยทั่วไปวิธีการนี้จะแบ่งภาพเป็นบล็อกขนาดเท่ากันแล้วสลับลำดับของพวกเขา เนื่องจากคำสั่งซื้อใหม่นั้นยึดตามเมล็ดที่ตายตัวจึงเป็นไปได้ที่จะคืนค่ากระบวนการโดยใช้เมล็ดเดียวกัน นอกจากนี้ด้วยพารามิเตอร์เพิ่มเติมที่เรียกว่า granularity เป็นไปได้ที่จะได้ผลลัพธ์ที่แตกต่างและไม่สามารถจดจำได้

ผล:

เป็นต้นฉบับ

เป็นต้นฉบับ

ความละเอียด 16

16

มีความละเอียด 13

13

ความละเอียดเป็นอันดับ 10

10

มีความละเอียด 3

3

ความละเอียดเป็นเม็ด 2

2

ความละเอียด 1

ป้อนคำอธิบายรูปภาพที่นี่

เป็นต้นฉบับ

เป็นต้นฉบับ

ความละเอียด 16

16

มีความละเอียด 13

13

ความละเอียดเป็นอันดับ 10

10

มีความละเอียด 3

3

ความละเอียดเป็นเม็ด 2

2

ความละเอียด 1

1

รหัส:

#!/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 สาย 47 สำหรับการเข้ารหัส 47 สำหรับการถอดรหัส

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_ref.rb

ป้อนคำอธิบายรูปภาพที่นี่ ป้อนคำอธิบายรูปภาพที่นี่

(แปลงเป็น jpg)

ป้อนคำอธิบายรูปภาพที่นี่

(ลดระดับดั้งเดิม)

ป้อนคำอธิบายรูปภาพที่นี่


3
รูปแบบดั้งเดิมบางส่วนสามารถมองเห็นได้ผ่านบรรทัดนั้น อย่างไรก็ตามมันคล้ายกับเมื่อคุณวาดด้วยนิ้วบนหน้าต่างหมอก)
Somnium

2
... 184426 ไบต์สำหรับ codegolf-35005_ref.rb
edc65

5

Matlab ด้วยการหยิกของทฤษฎีกลุ่ม (+ โบนัส)

ในวิธีการนี้เราคิดว่าเรามีจำนวนพิกเซลทั้งหมด (หากไม่ใช่เราแค่ละเว้นหนึ่งพิกเซล) ดังนั้นเราต้องเลือกครึ่งหนึ่งของพิกเซลเพื่อสลับกับอีกครึ่งหนึ่ง สำหรับสิ่งนี้เราจัดทำดัชนีพิกเซลทั้งหมดจาก0ขึ้นไป2N-1และพิจารณาดัชนีเหล่านี้เป็นกลุ่มแบบวงกลม

ในบรรดาจำนวนเฉพาะเราค้นหาหมายเลขpที่ไม่เล็กเกินไปและไม่ใหญ่เกินไปและนั่นคือ2Nคำสั่งของกลุ่มของเรา วิธีการนี้g จะสร้าง{k*g mod 2N | k=0,1,...,2N-1} = {0,1,...,2N-1}กลุ่มของเราหรือ

ดังนั้นเราเลือกNทวีคูณแรกของgเป็นชุดเดียวและส่วนที่เหลือทั้งหมดเป็นเซ็ตอื่นและเพียงสลับชุดพิกเซลที่สอดคล้องกัน

หากpเลือกวิธีที่เหมาะสมชุดแรกจะกระจายอย่างสม่ำเสมอทั่วทั้งภาพ

กรณีทดสอบสองกรณี:

ปิดหัวข้อเล็กน้อย แต่น่าสนใจ:

ในระหว่างการทดสอบฉันสังเกตเห็นว่าถ้าคุณบันทึกลงใน jpg (lossy บีบอัด) jpg (แทนที่จะบีบอัด png losslessly) และใช้การแปลงไปมาคุณจะเห็นสิ่งประดิษฐ์ของการบีบอัดค่อนข้างเร็วนี่แสดงผลลัพธ์ของการจัดเรียงสองครั้งติดต่อกัน :

อย่างที่คุณเห็นการบีบอัด jpg ทำให้ผลลัพธ์ดูเกือบขาวดำ!

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 (+ โบนัส) - ตัวกระจายการสลับพิกเซลแบบแบ่งส่วน

ฟังก์ชั่นใช้องค์ประกอบภาพและ

  1. หารพิกเซลด้วย 8
  2. ทำการสลับสับเปลี่ยนของกลุ่มพิกเซลได้หรือไม่
  3. การสลับซ้ำอีกครั้งหากกลุ่มพิกเซล> = 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()
}

ภูเขา แวดวง


4

Python 2.7 + PIL, Scrambler คอลัมน์ / แถว

วิธีนี้จะไขปัญหาแถวและคอลัมน์ของภาพ เป็นไปได้ที่จะช่วงชิงเพียงมิติเดียวหรือทั้งสองอย่าง นอกจากนี้คำสั่งของแถว / คอลัมน์สัญญาณรบกวนใหม่จะขึ้นอยู่กับรหัสผ่าน นอกจากนี้ยังมีความเป็นไปได้ที่จะตรวจสอบอาเรย์ภาพทั้งหมดอีกครั้งโดยไม่พิจารณาขนาด

ผล:

Scrambling ภาพทั้งหมด:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

Scrambling คอลัมน์:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

Scrambling แถว:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

Scrambling ทั้งคอลัมน์และแถว:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

ฉันพยายามใช้หลาย ๆ ภาพ แต่ผลลัพธ์ไม่ได้แตกต่างกันมากแค่ถอดรหัสยาก

รหัส:

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

C # Winforms

ภาพที่ 1: ป้อนคำอธิบายรูปภาพที่นี่

ภาพที่ 2: ป้อนคำอธิบายรูปภาพที่นี่

รหัสแหล่งที่มา:

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()

อัลกอริธึมของฉันใช้การสลับแบบ riffle ในทิศทางเดียวและสับเปลี่ยนแบบมาสเตอร์ในอีกทิศทางหนึ่ง (เนื่องจากทั้งสองเป็นค่าผกผันกัน) มีการวนซ้ำหลายครั้งในแต่ละทิศทาง เอฟเฟกต์คือคุณสามารถสร้างคีย์การเปลี่ยนรูปแบบการวนซ้ำได้เนื่องจากรูปภาพจะไม่ถูกกู้คืนโดยไม่ทราบลำดับที่แน่นอนของ ruffle และมาสเตอร์ shuffles สามารถระบุลำดับได้ด้วยชุดของจำนวนเต็มโดยมีจำนวนบวกแทน riffles และจำนวนลบที่แทนปริญญาโท

ฉันสลับภูมิทัศน์ด้วยปุ่ม [3, -5, 2, 13, -7]:

ภูมิทัศน์ 3 -5 2 13 -7

น่าสนใจพอสิ่งที่น่าสนใจบางอย่างเกิดขึ้นจาก [3, -5] ซึ่งมีสิ่งประดิษฐ์บางชิ้นจากภาพต้นฉบับเหลืออยู่:

แนวนอน 3 -5

นี่คือรูปแบบนามธรรมที่สับด้วยปุ่ม [2, 3, 5, 7, -11, 13, -17]:

แวดวง 2 3 5 7 -11 13 -17

หากมีเพียงพารามิเตอร์ตัวเดียวในคีย์การยกเลิกการสลับจะไม่กู้คืนรูปภาพ:

ไม่ดีสลับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.