利用随机种子可逆地打乱图片

思路来自随机数库可以通过设定种子复现结果,因此随机种子可以简单地作为某个加密算法的密码。程序如下,但是程序目前仅支持 PNG,三通道图片上出现的问题可能是由读取与写入的 RGB 顺序导致的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import hashlib
import pathlib as p
import typing as t

import cv2
import numpy as np


Path = t.Union[str, p.Path]
Seed = t.Union[str, int]


class Image:
    def __init__(self, data: np.ndarray) -> None:
        self._data = data

    @classmethod
    def from_file(cls, path: Path) -> 'Image':
        if p.Path(path).suffix != '.png':
            raise NotImplementedError('The bug with non-png images is not yet fixed')
        return cls(cv2.imread(str(path)))

    @property
    def data(self) -> np.ndarray:
        return self._data

    def encryption(self, seed: Seed) -> 'Image':
        rng = self._rng(seed)
        height, width, _ = self._data.shape
        x = rng.permutation(height)
        y = rng.permutation(width)
        return self.__class__(self._data[x, :, :][:, y, :])

    def decryption(self, seed: Seed) -> 'Image':
        rng = self._rng(seed)
        height, width, _ = self._data.shape
        x = self._inverse_permutation(rng.permutation(height))
        y = self._inverse_permutation(rng.permutation(width))
        return self.__class__(self._data[x, :, :][:, y, :])

    def write(self, path: Path) -> 'Image':
        cv2.imwrite(path, self._data)
        return self

    def _rng(self, seed: Seed) -> np.random.RandomState:
        if isinstance(seed, str):
            md5 = hashlib.md5(seed.encode('utf-8')).hexdigest()
            seed = int(md5[:8], 16)
        return np.random.RandomState(seed)

    def _inverse_permutation(self, array: np.ndarray) -> np.ndarray:
        ans = np.zeros_like(array)
        for ith, element in enumerate(array):
            ans[element] = ith
        return ans


if __name__ == '__main__':
    Image \
        .from_file('target.png') \
        .encryption('Just Monika.') \
        .write('output.png')

    # Image \
    #     .from_file('output.png') \
    #     .decryption('Just Monika.') \
    #     .write('reverse.png')

Dummy image

打乱顺序的图片:output.png