├── LICENSE ├── README.md ├── gray_encrypt ├── .gitignore ├── README.md ├── analysis │ ├── __init__.py │ ├── bifurcation.py │ ├── correlation.py │ ├── differencial.py │ ├── entropy.py │ ├── histogram.py │ └── sensitivity.py ├── decrypt.py ├── docs │ └── img │ │ ├── correlation.png │ │ ├── decrypt.png │ │ ├── decrypt_sensitivity.png │ │ ├── encrypt.png │ │ ├── encrypt_sensitivity.png │ │ ├── histogram.png │ │ └── other_analysis_data.png ├── encrypt.py ├── images │ ├── lena.bmp │ ├── lena.png │ └── rabbit.jpg ├── main.py ├── requirements.txt └── utils.py └── improvement ├── .gitignore ├── README.md ├── analysis ├── __init__.py ├── bifurcation.py ├── correlation.py ├── differencial.py ├── entropy.py ├── histogram.py └── sensitivity.py ├── decrypt.py ├── docs └── img │ ├── 分岔图.png │ ├── 加密图像.png │ ├── 加密图像直方图.png │ ├── 加密图像相关性分析.png │ ├── 加密过程的密钥敏感性分析.png │ ├── 原始图像直方图.png │ ├── 原始图像相关性分析.png │ ├── 实验结果.png │ ├── 解密图像.png │ └── 解密过程的密钥敏感性分析.png ├── encrypt.py ├── images ├── astesia.jpg ├── lena.png ├── pvz.jpg └── rabbit.jpg ├── main.py ├── requirements.txt ├── result.txt └── utils.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 亚甲基蓝 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 数字内容安全课程作业 2 | 3 | - 本项目为基于论文 [A novel bit-level image encryption algorithm based on chaotic maps](https://doi.org/10.1016/j.optlaseng.2015.09.007) 中提出的图像加密算法与改进算法的 python 实现 4 | 5 | - [gray_encrypt/](gray_encrypt/) 目录下的文件为原论文算法实现代码 6 | 7 | - [improvement/](improvement/) 目录下的文件为改进算法的实现代码 -------------------------------------------------------------------------------- /gray_encrypt/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | images/ 131 | params/ -------------------------------------------------------------------------------- /gray_encrypt/README.md: -------------------------------------------------------------------------------- 1 | # 一种新的基于混沌映射的比特级图像加密算法 2 | 3 | > 原论文题目:A novel bit-level image encryption algorithm based on chaotic maps 4 | > 链接:https://doi.org/10.1016/j.optlaseng.2015.09.007 5 | 6 | 数字内容安全大作业1 7 | 8 | ## 介绍 9 | 10 | - 本项目为论文 [A novel bit-level image encryption algorithm based on chaotic maps](https://doi.org/10.1016/j.optlaseng.2015.09.007) 中提出的图像加密算法的 python 实现,复现了加密算法、解密算法以及性能分析 11 | - 原文提出的算法并不复杂,然而对 python 的矩阵运算方法掌握不熟练导致很久才成功复现(~~家人们,谁懂啊,被 numpy 的 `reshape()` 的下头参数顺序气晕~~) 12 | 13 | ## 目录结构 14 | 15 | - `.git` 16 | - `gray_encrypt` 17 | - `analysis` 18 | - `__init__.py` 19 | - `correlation.py`: 相邻像素相关性分析 20 | - `differencial.py`: 差分攻击分析 21 | - `entropy.py`: 信息熵分析 22 | - `histogram.py`: 直方图分析 23 | - `sensitivity.py`: 密钥敏感测试 24 | - `images`: 实验图片存放路径 25 | - `lena.bmp` 26 | - `lena.png` 27 | - `rabbit.jpg` 28 | - `params`: 密钥存放路径 29 | - `decrypt.py` 30 | - `encrypt.py` 31 | - `main.py`: 主函数,加解密 + 性能分析 32 | - `utils.py`: 图像的位平面分解 + 生成混沌映射序列 33 | - `img` 34 | - `.gitnore` 35 | - `LICENSE` 36 | - `README.md` 37 | 38 | ## 使用方法 39 | 40 | - 新建 python 虚拟环境 41 | - 激活虚拟环境,安装依赖:`pip install -r requirements.txt` 42 | - 运行代码 43 | 1. 加解密 + 性能分析:将要处理的图像放到 `images` 目录下,修改 `main.py` 第 4 行的图像路径,运行 `python main.py` 44 | 2. 如果要单独执行/不执行某一个方法,请自行在 `main.py` 中添加/注释对应的函数(注意传参) 45 | 46 | ## 实验结果 47 | 48 | 以 lena 图为输入,执行的结果如下 49 | 50 | - 加密图像 51 | ![加密图像](docs/img/encrypt.png) 52 | 53 | - 解密图像 54 | ![解密图像](docs/img/decrypt.png) 55 | 56 | - 直方图分析 57 | ![直方图分析](docs/img/histogram.png) 58 | 59 | - 相关性分析 60 | ![相关性分析](docs/img/correlation.png) 61 | 62 | - 加密密钥敏感性分析 63 | ![加密密钥敏感性分析](docs/img/encrypt_sensitivity.png) 64 | 65 | - 解密密钥敏感性分析 66 | ![解密密钥敏感性分析](docs/img/decrypt_sensitivity.png) 67 | 68 | - 其他分析数据 69 | 70 | ![其他分析数据](docs/img/other_analysis_data.png) 71 | 72 | ## TODO 73 | 74 | - [x] 调整密钥所包含的项目(原算法中除混沌映射初始值外还必须保存每轮扩散后的序列的第一项) 75 | - [x] 基于此算法实现彩色图像的加密 -------------------------------------------------------------------------------- /gray_encrypt/analysis/__init__.py: -------------------------------------------------------------------------------- 1 | from .correlation import correlation 2 | from .differencial import differencial 3 | from .entropy import entropy 4 | from .histogram import histogram 5 | from .sensitivity import decrypt_sensitivity, encrypt_sensitivity 6 | from .bifurcation import bifurcation_diagram 7 | -------------------------------------------------------------------------------- /gray_encrypt/analysis/bifurcation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from utils import PWLCM 3 | from matplotlib import pyplot as plt 4 | 5 | 6 | def bifurcation_diagram(seed, n_skip, n_iter, step=1e-4, u_min=1e-16): 7 | ''' 8 | 绘制分岔图 9 | ''' 10 | print("Starting with x0 seed {0}, skip plotting first {1} iterations, then plot next {2} iterations.".format( 11 | seed, n_skip, n_iter)) 12 | # μ 列表, 分岔图的 x 轴 13 | U = [] 14 | # x 列表, 分岔图的 y 轴 15 | X = [] 16 | 17 | # Create the r values to loop. For each r value we will plot n_iter points 18 | u_range = np.linspace(u_min, 0.5-(1e-16), int(1/step)) 19 | for u in u_range: 20 | U.extend([u]*(n_iter+1)) 21 | X.extend(PWLCM(seed, u, n_iter+n_skip+1)[n_skip:]) 22 | 23 | # Plot the data 24 | plt.plot(U, X, ls='', marker=',') 25 | plt.ylim(0, 1) 26 | plt.xlim(u_min, 0.5) 27 | plt.xlabel('μ') 28 | plt.ylabel('X') 29 | plt.show() 30 | 31 | 32 | if __name__ == "__main__": 33 | bifurcation_diagram(0.2, 100, 10) 34 | -------------------------------------------------------------------------------- /gray_encrypt/analysis/correlation.py: -------------------------------------------------------------------------------- 1 | # 原代码地址:https://blog.csdn.net/qq_41137110/article/details/115675014 2 | 3 | import cv2 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | 7 | 8 | ''' 9 | 分别计算图像通道相邻像素的水平、垂直和对角线的相关系数并返回 10 | ''' 11 | 12 | 13 | def _correlation(img, N): 14 | # 计算img通道 15 | h, w = img.shape 16 | # 随机产生pixels个[0,w-1)范围内的整数序列 17 | row = np.random.randint(0, h-1, N) 18 | col = np.random.randint(0, w-1, N) 19 | # 绘制相邻像素相关性图,统计x,y坐标 20 | x = [] 21 | h_y = [] 22 | v_y = [] 23 | d_y = [] 24 | for i in range(N): 25 | # 选择当前一个像素 26 | x.append(img[row[i]][col[i]]) 27 | # 水平相邻像素是它的右侧也就是同行下一列的像素 28 | h_y.append(img[row[i]][col[i]+1]) 29 | # 垂直相邻像素是它的下方也就是同列下一行的像素 30 | v_y.append(img[row[i]+1][col[i]]) 31 | # 对角线相邻像素是它的右下即下一行下一列的那个像素 32 | d_y.append(img[row[i]+1][col[i]+1]) 33 | # 三个方向的合到一起 34 | x = x*3 35 | y = h_y+v_y+d_y 36 | 37 | # 计算E(x),计算三个方向相关性时,x没有重新选择也可以更改 38 | ex = 0 39 | for i in range(N): 40 | ex += img[row[i]][col[i]] 41 | ex = ex/N 42 | # 计算D(x) 43 | dx = 0 44 | for i in range(N): 45 | dx += (img[row[i]][col[i]]-ex)**2 46 | dx /= N 47 | 48 | # 水平相邻像素h_y 49 | # 计算E(y) 50 | h_ey = 0 51 | for i in range(N): 52 | h_ey += img[row[i]][col[i]+1] 53 | h_ey /= N 54 | # 计算D(y) 55 | h_dy = 0 56 | for i in range(N): 57 | h_dy += (img[row[i]][col[i]+1]-h_ey)**2 58 | h_dy /= N 59 | # 计算协方差 60 | h_cov = 0 61 | for i in range(N): 62 | h_cov += (img[row[i]][col[i]]-ex)*(img[row[i]][col[i]+1]-h_ey) 63 | h_cov /= N 64 | h_Rxy = h_cov/(np.sqrt(dx)*np.sqrt(h_dy)) 65 | 66 | # 垂直相邻像素v_y 67 | # 计算E(y) 68 | v_ey = 0 69 | for i in range(N): 70 | v_ey += img[row[i]+1][col[i]] 71 | v_ey /= N 72 | # 计算D(y) 73 | v_dy = 0 74 | for i in range(N): 75 | v_dy += (img[row[i]+1][col[i]]-v_ey)**2 76 | v_dy /= N 77 | # 计算协方差 78 | v_cov = 0 79 | for i in range(N): 80 | v_cov += (img[row[i]][col[i]]-ex)*(img[row[i]+1][col[i]]-v_ey) 81 | v_cov /= N 82 | v_Rxy = v_cov/(np.sqrt(dx)*np.sqrt(v_dy)) 83 | 84 | # 对角线相邻像素d_y 85 | # 计算E(y) 86 | d_ey = 0 87 | for i in range(N): 88 | d_ey += img[row[i]+1][col[i]+1] 89 | d_ey /= N 90 | # 计算D(y) 91 | d_dy = 0 92 | for i in range(N): 93 | d_dy += (img[row[i]+1][col[i]+1]-d_ey)**2 94 | d_dy /= N 95 | # 计算协方差 96 | d_cov = 0 97 | for i in range(N): 98 | d_cov += (img[row[i]][col[i]]-ex) * \ 99 | (img[row[i]+1][col[i]+1]-d_ey) 100 | d_cov /= N 101 | d_Rxy = d_cov/(np.sqrt(dx)*np.sqrt(d_dy)) 102 | 103 | return h_Rxy, v_Rxy, d_Rxy, x, y 104 | 105 | 106 | ''' 107 | 分别计算图像img的各通道相邻像素的相关系数,默认随机选取2000对相邻像素 108 | ''' 109 | 110 | 111 | def show_correlation(raw_img, encrypt_img, N=2000): 112 | r_img = cv2.imread(raw_img, cv2.IMREAD_GRAYSCALE) 113 | e_img = cv2.imread(encrypt_img, cv2.IMREAD_GRAYSCALE) 114 | r_Rxy = _correlation(r_img, N) 115 | e_Rxy = _correlation(e_img, N) 116 | 117 | # 结果展示 118 | # 原图像 119 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 120 | plt.subplot(221) 121 | plt.imshow(r_img, cmap='gray') 122 | plt.title('原图像') 123 | # 原图像相邻像素分布 124 | plt.subplot(222) 125 | plt.scatter(r_Rxy[3], r_Rxy[4], s=1) 126 | plt.title('原图像像素分布') 127 | # 加密图像 128 | plt.subplot(223) 129 | plt.imshow(e_img, cmap='gray') 130 | plt.title('加密图像') 131 | # 加密图像相邻像素分布 132 | plt.subplot(224) 133 | plt.scatter(e_Rxy[3], e_Rxy[4], s=1) 134 | plt.title('加密图像像素分布') 135 | plt.show() 136 | 137 | return r_Rxy[0:3], e_Rxy[0:3] 138 | 139 | 140 | def correlation(img, encrypt_img): 141 | r_Rxy, e_Rxy = show_correlation(img, encrypt_img) 142 | # 输出结果保留四位有效数字 143 | print("========原始图像的各方向的相关系数========") 144 | print('Horizontal\tVertical\tDiagonal') 145 | print('{:.4f}\t\t{:.4f}\t\t{:.4f}'.format( 146 | r_Rxy[0], r_Rxy[1], r_Rxy[2])) 147 | print("========加密图像的各方向的相关系数========") 148 | print('Horizontal\tVertical\tDiagonal') 149 | print('{:.4f}\t\t{:.4f}\t\t{:.4f}'.format( 150 | e_Rxy[0], e_Rxy[1], e_Rxy[2])) 151 | 152 | 153 | if __name__ == '__main__': 154 | img = '../images/lena.png' 155 | encrypt_img = '../images/lena_encrypt.png' 156 | correlation(img, encrypt_img) 157 | -------------------------------------------------------------------------------- /gray_encrypt/analysis/differencial.py: -------------------------------------------------------------------------------- 1 | # 原代码地址:https://blog.csdn.net/qq_41137110/article/details/115675014 2 | 3 | import cv2 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | from encrypt import encrypt 7 | from os import remove 8 | 9 | ''' 10 | 计算像素数变化率 11 | ''' 12 | 13 | 14 | def NPCR(img1, img2): 15 | w, h, = img1.shape 16 | 17 | # 图像通道拆分 18 | # 返回数组的排序后的唯一元素和每个元素重复的次数 19 | ar, num = np.unique((img1 != img2), return_counts=True) 20 | npcr = (num[0] if ar[0] == True else num[1])/(w*h) 21 | 22 | return npcr 23 | 24 | 25 | ''' 26 | 两张图像之间的平均变化强度 27 | ''' 28 | 29 | 30 | def UACI(img1, img2): 31 | h, w = img1.shape 32 | # 元素为uint8类型取值范围:0到255 33 | # 强制转换元素类型,为了运算 34 | img1 = img1.astype(np.int16) 35 | img2 = img2.astype(np.int16) 36 | 37 | sum = np.sum(abs(img1-img2)) 38 | uaci = sum/255/(w*h) 39 | 40 | return uaci 41 | 42 | 43 | def differencial(img_path): 44 | img_path_2 = img_path.rsplit('.', 1)[0] + '_differencial.png' 45 | img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) 46 | img[0][0] = img[0][0] ^ 2**4 # 修改第一个像素值的第5位 47 | cv2.imwrite(img_path_2, img) 48 | _, img1 = encrypt(img_path) 49 | _, img2 = encrypt(img_path_2) 50 | npcr = NPCR(img1, img2) 51 | print('=================差分攻击=================') 52 | # 百分数表示,保留小数点后4位 53 | print('PSNR:\t{:.4%}'.format(npcr)) 54 | 55 | uaci = UACI(img1, img2) 56 | # 百分数表示,保留小数点后4位 57 | print('UACI:\t{:.4%}'.format(uaci)) 58 | remove(img_path_2) 59 | remove(img_path_2.rsplit('.', 1)[0] + '_encrypt.png') 60 | 61 | 62 | if __name__ == '__main__': 63 | img_path = '../images/lena.png' 64 | differencial(img_path) 65 | -------------------------------------------------------------------------------- /gray_encrypt/analysis/entropy.py: -------------------------------------------------------------------------------- 1 | # 原代码地址:https://blog.csdn.net/qq_41137110/article/details/115675014 2 | 3 | import cv2 4 | import math 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | 9 | ''' 10 | 计算图像的信息熵 11 | ''' 12 | 13 | 14 | def _entropy(img): 15 | img = cv2.imread(img, cv2.IMREAD_GRAYSCALE) 16 | h, w = img.shape 17 | gray, num = np.unique(img, return_counts=True) 18 | entropy = 0 19 | 20 | for i in range(len(gray)): 21 | p = num[i]/(w*h) 22 | entropy -= p*(math.log(p, 2)) 23 | return entropy 24 | 25 | 26 | def entropy(raw_img, encrypt_img): 27 | # 图像lena的熵 28 | raw_entropy = _entropy(raw_img) 29 | encrypt_entropy = _entropy(encrypt_img) 30 | print('==================信息熵==================') 31 | print('原图像: \t{:.5}'.format(raw_entropy)) 32 | print('加密图像: \t{:.5}'.format(encrypt_entropy)) 33 | 34 | 35 | if __name__ == '__main__': 36 | img = '../images/lena.png' 37 | encrypt_img = '../images/lena_encrypt.png' 38 | entropy(img, encrypt_img) 39 | -------------------------------------------------------------------------------- /gray_encrypt/analysis/histogram.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from matplotlib import pyplot as plt 3 | 4 | # 生成直方图 5 | 6 | 7 | def histogram(img_path): 8 | src = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) 9 | plt.hist(src.ravel(), 256) 10 | plt.title("直方图分析") 11 | plt.show() 12 | 13 | 14 | if __name__ == "__main__": 15 | img_path = "../images/lena_encrypt.png" 16 | histogram(img_path) 17 | -------------------------------------------------------------------------------- /gray_encrypt/analysis/sensitivity.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from matplotlib import pyplot as plt 3 | from encrypt import encrypt 4 | from decrypt import decrypt 5 | import numpy as np 6 | from copy import deepcopy 7 | 8 | 9 | def encrypt_sensitivity(img_path, key=None, modified_key=None): 10 | key = [0.01234567890123, 0.12345678912345, 11 | 0.01234567891234, 0.21234567891234] if not key else key 12 | modified_key = [0.01234567890124, 0.12345678912345, 13 | 0.01234567891234, 0.21234567891234] if not modified_key else modified_key 14 | 15 | # 结果展示 16 | # 原图像 17 | r_img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) 18 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 19 | plt.subplot(221) 20 | plt.imshow(r_img, cmap='gray') 21 | plt.title('原图像') 22 | 23 | # key加密的图像 24 | _, key_img = encrypt(img_path, *key) 25 | plt.subplot(222) 26 | plt.imshow(key_img, cmap='gray') 27 | plt.title('key加密的图像') 28 | 29 | # 修改过的key加密的图像 30 | _, modified_key_img = encrypt(img_path, *modified_key) 31 | plt.subplot(223) 32 | plt.imshow(modified_key_img, cmap='gray') 33 | plt.title('修改过的key加密的图像') 34 | 35 | # 两者差值 36 | plt.subplot(224) 37 | plt.imshow(np.abs(modified_key_img - key_img), cmap='gray') 38 | plt.title('两者差值') 39 | plt.show() 40 | 41 | 42 | def decrypt_sensitivity(img_path, encrypt_img_path, key=None, incorrect_key=None): 43 | key = [0.01234567890123, 0.12345678912345, 44 | 0.01234567891234, 0.21234567891234] if not key else key 45 | if not incorrect_key: 46 | incorrect_key = deepcopy(key) 47 | incorrect_key[0] += 0.00000000000001 48 | 49 | # 结果展示 50 | # 原图像 51 | r_img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) 52 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 53 | plt.subplot(221) 54 | plt.imshow(r_img, cmap='gray') 55 | plt.title('原图像') 56 | 57 | # 原始key加密的图像 58 | _, key_img = encrypt(img_path, *key) 59 | plt.subplot(222) 60 | plt.imshow(key_img, cmap='gray') 61 | plt.title('原始key加密的图像') 62 | 63 | # 修改过的key解密的图像 64 | # 读取参数 65 | raw_params = np.load('./params/params.npz') 66 | np.savez('./params/incorrect_params.npz', 67 | x0=incorrect_key[0], u1=incorrect_key[1], 68 | y0=incorrect_key[2], u2=incorrect_key[3], 69 | A11_0=raw_params['A11_0'], A22_0=raw_params['A22_0'], 70 | n_round=raw_params['n_round']) 71 | incorrect_decrypt_img = decrypt( 72 | encrypt_img_path, params_path='incorrect_params.npz') 73 | plt.subplot(223) 74 | plt.imshow(incorrect_decrypt_img, cmap='gray') 75 | plt.title('修改过的key解密的图像') 76 | 77 | # 原始key解密的图像 78 | decrypt_img = decrypt(encrypt_img_path, params_path='params.npz') 79 | plt.subplot(224) 80 | plt.imshow(decrypt_img, cmap='gray') 81 | plt.title('原始key解密的图像') 82 | plt.show() 83 | 84 | 85 | if __name__ == "__main__": 86 | img_path = "../images/lena.png" 87 | encrypt_img_path = "../images/lena_encrypt.png" 88 | encrypt_sensitivity(img_path) 89 | decrypt_sensitivity(img_path, encrypt_img_path, None, None) 90 | -------------------------------------------------------------------------------- /gray_encrypt/decrypt.py: -------------------------------------------------------------------------------- 1 | from math import floor 2 | import cv2 3 | import numpy as np 4 | from copy import deepcopy 5 | from matplotlib import pyplot as plt 6 | from utils import PWLCM, img_bit_decomposition 7 | 8 | 9 | def decrypt(encrypt_img_path, raw_img_path=None, params_path='params.npz', show=False): 10 | ''' 11 | 解密图像 12 | ''' 13 | npz_file = np.load(f"./params/{params_path}") # 加载参数 14 | x0, u1, y0, u2, A11_0, A22_0, n_round = \ 15 | npz_file['x0'], \ 16 | npz_file['u1'], \ 17 | npz_file['y0'], \ 18 | npz_file['u2'], \ 19 | npz_file['A11_0'], \ 20 | npz_file['A22_0'], \ 21 | npz_file['n_round'] 22 | A11_0 = [int(i) for i in list(bin(A11_0)[2:])[1:]] 23 | A22_0 = [int(i) for i in list(bin(A22_0)[2:])[1:]] 24 | # print( 25 | # f"参数:\nx0: {x0}, u1: {u1},\ny0: {y0}, u2: {u2},\nA11_0: {A11_0}, A22_0: {A22_0},\nn_round: {n_round}" 26 | # ) 27 | filename, ext = encrypt_img_path.rsplit('.', 1) 28 | decrypt_img_path = f"{filename}_decrypt.{ext}" 29 | 30 | img = cv2.imread(encrypt_img_path, cv2.IMREAD_GRAYSCALE) # 读取图像 31 | 32 | M, N = img.shape # M: height, N: width 33 | if M != M or N != N: 34 | raise ValueError("The shape of image is not correct!") 35 | 36 | if show: 37 | print(f"图像分辨率为: {N} x {M}") 38 | 39 | # Piecewise Logistic Chaotic Map 40 | N0 = 1000 # 舍弃前N0个数 41 | PWLCM_MAP_X = PWLCM(x0, u1, N0 + M*N)[N0:] 42 | X1 = [floor(i * 1e14) % 256 for i in PWLCM_MAP_X] # key1 43 | X1_reshape = np.mat(X1, dtype=np.uint8).reshape(M, N) 44 | X1_bitplanes = img_bit_decomposition(X1_reshape) # key1的位平面分解 45 | b1 = X1_bitplanes[::2, :, :].ravel() # key1的偶数位平面 46 | b2 = X1_bitplanes[1::2, :, :].ravel() # key1的奇数位平面 47 | 48 | bitplanes = img_bit_decomposition(img) # 位平面分解 49 | C1 = bitplanes[:4, :, :].ravel() 50 | C2 = bitplanes[4:, :, :].ravel() 51 | 52 | L = M * N * 4 53 | for k in range(n_round): 54 | # 逆混淆 55 | sum = np.sum(C1) + np.sum(C2) # C1 和 C2 的和 56 | s0 = (y0 + sum / L) % 1 # key2的初始值s0 57 | S = PWLCM(s0, u2, N0 + 2 * L)[N0:] 58 | S1, S2 = S[:L], S[L:] 59 | Y = [floor(s1 * 1e14) % L for s1 in S1] 60 | Z = [floor(s2 * 1e14) % L for s2 in S2] 61 | 62 | for j in range(L-1, -1, -1): 63 | C2[j], C1[Z[j]] = C1[Z[j]], C2[j] 64 | for i in range(L-1, -1, -1): 65 | C1[i], C2[Y[i]] = C2[Y[i]], C1[i] 66 | 67 | B1, B2 = C1, C2 68 | 69 | # 逆扩散 70 | sum2 = np.sum(B1) # B1 的和 71 | A11 = np.zeros(L, dtype=np.uint8) 72 | A22 = np.zeros(L, dtype=np.uint8) 73 | A22[0] = A22_0[k] 74 | for i in range(1, L): 75 | A22[i] = A22[i - 1] ^ B1[i] ^ B2[i] ^ b2[i] 76 | A2 = np.roll(A22, -1*sum2) # A2 循环左移 sum2 位 77 | sum1 = np.sum(A2) # A2 的和 78 | A11[0] = A11_0[k] 79 | for i in range(1, L): 80 | A11[i] = A11[i - 1] ^ A2[i] ^ B1[i] ^ b1[i] 81 | A1 = np.roll(A11, -1*sum1) # A1 循环左移 sum1 位 82 | C1 = deepcopy(A1) 83 | C2 = deepcopy(A2) 84 | 85 | # A1,A2两个序列合并成原始图像 86 | A = np.append(A1, A2)[::-1].reshape(8, M, N)[:, ::-1, ::-1] 87 | res = np.zeros((M, N), dtype=np.uint8) 88 | for i in range(8): 89 | res = cv2.bitwise_or(res, A[i, :, :] << i) 90 | cv2.imwrite(decrypt_img_path, res) 91 | 92 | # 验证解密得到的图像为原图像 93 | if raw_img_path: 94 | raw_img = cv2.imread(raw_img_path, cv2.IMREAD_GRAYSCALE) 95 | if not np.sum(np.abs(res - raw_img)): 96 | print("解密成功!") 97 | else: 98 | print("解密失败!") 99 | 100 | # 显示图像 101 | if show: 102 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 103 | plt.imshow(res, cmap='gray') 104 | plt.title("解密图像") 105 | plt.show() 106 | 107 | return res 108 | 109 | 110 | if __name__ == "__main__": 111 | encrypt_img_path = "./data/rabbit1_encrypt.png" # 要解密的图像路径 112 | raw_img_path = "./data/rabbit1.jpg" # 原始图像路径 113 | decrypt(encrypt_img_path, raw_img_path) 114 | -------------------------------------------------------------------------------- /gray_encrypt/docs/img/correlation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/docs/img/correlation.png -------------------------------------------------------------------------------- /gray_encrypt/docs/img/decrypt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/docs/img/decrypt.png -------------------------------------------------------------------------------- /gray_encrypt/docs/img/decrypt_sensitivity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/docs/img/decrypt_sensitivity.png -------------------------------------------------------------------------------- /gray_encrypt/docs/img/encrypt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/docs/img/encrypt.png -------------------------------------------------------------------------------- /gray_encrypt/docs/img/encrypt_sensitivity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/docs/img/encrypt_sensitivity.png -------------------------------------------------------------------------------- /gray_encrypt/docs/img/histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/docs/img/histogram.png -------------------------------------------------------------------------------- /gray_encrypt/docs/img/other_analysis_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/docs/img/other_analysis_data.png -------------------------------------------------------------------------------- /gray_encrypt/encrypt.py: -------------------------------------------------------------------------------- 1 | from math import floor 2 | import cv2 3 | import numpy as np 4 | import os 5 | from random import uniform 6 | from copy import deepcopy 7 | from matplotlib import pyplot as plt 8 | from utils import img_bit_decomposition, PWLCM 9 | 10 | 11 | def encrypt( 12 | img_path, 13 | x0=None, u1=None, y0=None, u2=None, # 密钥 14 | n_round=1, # 加密轮数 15 | params_path='params.npz', # 参数保存路径 16 | show=False, # 是否显示图像 17 | use_params=False # 是否使用已有参数 18 | ): 19 | ''' 20 | 加密图像 21 | x0, u1, y0, u2: 混沌序列的初始值和参数 22 | N0: 丢弃前N0个数 23 | n_round: 加密轮数 24 | params_path: 参数保存路径,只需要写文件名+后缀,不需要写绝对路径 25 | show: 是否显示图像 26 | use_params: 是否使用已有参数 27 | ''' 28 | if not use_params: 29 | x0 = uniform(1e-16, 1-1e-16) if not x0 else x0 # key1的初始值x0 30 | u1 = uniform(1e-16, 0.5-1e-16) if not u1 else u1 # key1的初始值u1 31 | y0 = uniform(1e-16, 1-1e-16) if not y0 else y0 # 初始值y0 32 | u2 = uniform(1e-16, 0.5-1e-16) if not u2 else u2 # 初始值u2 33 | else: 34 | use_params_path = f"./params/{params_path}" 35 | if os.path.exists(use_params_path): 36 | params = np.load(use_params_path) 37 | x0 = params['x0'] 38 | u1 = params['u1'] 39 | y0 = params['y0'] 40 | u2 = params['u2'] 41 | n_round = params['n_round'] 42 | else: 43 | raise FileNotFoundError(f"未找到参数文件: {use_params_path}") 44 | filename, ext = img_path.rsplit('.', 1) 45 | encrypt_img_path = f"{filename}_encrypt.png" 46 | 47 | img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) # 读取图像 48 | 49 | M, N = img.shape # M: height, N: width 50 | 51 | if show: 52 | print(f"图像分辨率为: {N} x {M}") 53 | 54 | bitplanes = img_bit_decomposition(img) # 位平面分解 55 | bitplanes = bitplanes[::-1, :, :] # 位平面反序 56 | A1 = bitplanes[:4, :, :].ravel() # 高位平面,第 7 位到第 4 位 57 | A2 = bitplanes[4:, :, :].ravel() # 低位平面,第 3 位到第 0 位 58 | 59 | # Piecewise Logistic Chaotic Map 60 | N0 = 1000 # 丢弃前N0个数 61 | PWLCM_MAP_X = PWLCM(x0, u1, N0 + M*N)[N0:] # 生成长度为N0+M*N的混沌序列 62 | # key1,将[PWLCM_MAP_X]中每个小数转换为整数并对256取模得到0~255之间的整数作为key1的值 63 | X1 = [floor(i * 1e14) % 256 for i in PWLCM_MAP_X] 64 | X1_reshape = np.mat(X1, dtype=np.uint8).reshape(M, N) 65 | X1_bitplanes = img_bit_decomposition(X1_reshape) # key1的位平面分解 66 | b1 = X1_bitplanes[::2, :, :].ravel() # key1的偶数位平面 67 | b2 = X1_bitplanes[1::2, :, :].ravel() # key1的奇数位平面 68 | 69 | L = M * N * 4 70 | A11_0 = [] # A11的第一位,由于可能加密多轮故用列表存储 71 | A22_0 = [] # A22的第一位,由于可能加密多轮故用列表存储 72 | for k in range(n_round): 73 | # 初始化B1和B2 74 | B1 = np.zeros(L, dtype=np.uint8) 75 | B2 = np.zeros(L, dtype=np.uint8) 76 | # 扩散 77 | sum1 = np.sum(A2) # A2 的和 78 | A11 = np.roll(A1, sum1) # 高位平面的循环右移 sum1 位 79 | for i in range(L): 80 | B1[i] = A11[i] ^ A11[i - 1] ^ A2[i] ^ b1[i] 81 | sum2 = np.sum(B1) # B1 的和 82 | A22 = np.roll(A2, sum2) # 低位平面的循环右移 sum2 位 83 | for i in range(L): 84 | B2[i] = A22[i] ^ A22[i - 1] ^ B1[i] ^ b2[i] 85 | 86 | # 生成 Y 和 Z 87 | sum = np.sum(B1) + np.sum(B2) 88 | 89 | s0 = (y0 + sum / L) % 1 # key2的初始值s0 90 | S = PWLCM(s0, u2, N0 + 2 * L)[N0:] 91 | S1, S2 = S[:L], S[L:] 92 | # 将S1中每个小数转换为整数并对L取模得到0~L-1之间的整数作为Y的值 93 | Y = [floor(s1 * 1e14) % L for s1 in S1] 94 | # 将S2中每个小数转换为整数并对L取模得到0~L-1之间的整数作为Z的值 95 | Z = [floor(s2 * 1e14) % L for s2 in S2] 96 | 97 | # 混淆 98 | for i in range(L): 99 | B1[i], B2[Y[i]] = B2[Y[i]], B1[i] 100 | for j in range(L): 101 | B2[j], B1[Z[j]] = B1[Z[j]], B2[j] 102 | A11_0.append(A11[0]) 103 | A22_0.append(A22[0]) 104 | # 用B1和B2更新A1和A2,以作为下一轮加密的输入 105 | A1 = deepcopy(B1) 106 | A2 = deepcopy(B2) 107 | 108 | # C1,C2 序列合并成加密图像 109 | C = np.append(B1, B2).reshape(8, M, N) 110 | res = np.zeros((M, N), dtype=np.uint8) 111 | for i in range(8): 112 | res = cv2.bitwise_or(res, C[i, :, :] << i) 113 | 114 | cv2.imwrite(encrypt_img_path, res) # 保存图像 115 | 116 | # 显示加密图像 117 | if show: 118 | print('加密完成!') 119 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 120 | plt.imshow(res, cmap='gray') 121 | plt.title('加密图像') 122 | plt.show() 123 | 124 | # 保存参数 125 | # 01列表压缩为 int 整数 126 | if not use_params: 127 | A11_0_int = int('1' + ''.join([str(i) for i in A11_0[::-1]]), 2) 128 | A22_0_int = int('1' + ''.join([str(i) for i in A22_0[::-1]]), 2) 129 | if not os.path.exists('./params'): 130 | os.mkdir('./params') 131 | np.savez(f'./params/{params_path}', x0=x0, u1=u1, y0=y0, 132 | u2=u2, A11_0=A11_0_int, A22_0=A22_0_int, n_round=n_round) 133 | return encrypt_img_path, res 134 | 135 | 136 | if __name__ == '__main__': 137 | img_path = "./data/rabbit1.jpg" # 图像路径 138 | params = { 139 | 'x0': None, 140 | 'u1': None, 141 | 'y0': None, 142 | 'u2': None, 143 | 'n_round': 1 # 加密轮数 144 | } 145 | encrypt(img_path, **params) 146 | -------------------------------------------------------------------------------- /gray_encrypt/images/lena.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/images/lena.bmp -------------------------------------------------------------------------------- /gray_encrypt/images/lena.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/images/lena.png -------------------------------------------------------------------------------- /gray_encrypt/images/rabbit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/gray_encrypt/images/rabbit.jpg -------------------------------------------------------------------------------- /gray_encrypt/main.py: -------------------------------------------------------------------------------- 1 | from analysis import * 2 | from encrypt import encrypt 3 | from decrypt import decrypt 4 | img_path = "./images/lena.png" 5 | bifurcation_diagram(0.2, 100, 10) # 分岔图 6 | # encrypt_img_path, res = encrypt(img_path, show=True) # 加密 7 | # decrypt(encrypt_img_path, img_path, show=True) # 解密 8 | # histogram(encrypt_img_path) # 直方图 9 | # correlation(img_path, encrypt_img_path) # 相关性 10 | # entropy(img_path, encrypt_img_path) # 信息熵 11 | # encrypt_sensitivity(img_path) # 加密敏感度 12 | # decrypt_sensitivity(img_path, encrypt_img_path) # 解密敏感度 13 | # differencial(img_path) # 差分攻击,NPCR和UACI 14 | -------------------------------------------------------------------------------- /gray_encrypt/requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==3.7.1 2 | numpy==1.24.2 3 | opencv_python==4.7.0.72 4 | -------------------------------------------------------------------------------- /gray_encrypt/utils.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from numpy import uint8, zeros 3 | 4 | 5 | def img_bit_decomposition(img): 6 | '''图像的位平面分解''' 7 | m, n = img.shape 8 | r = zeros((8, m, n), dtype=uint8) 9 | for i in range(8): 10 | r[i, :, :] = cv2.bitwise_and(img, 2**i) 11 | mask = r[i, :, :] > 0 12 | r[i, mask] = 1 13 | return r 14 | 15 | 16 | def PWLCM(x0, h, num): 17 | '''生成混沌映射序列 18 | x0: 初始值 19 | h: 控制参数 20 | num: 生成序列的长度 21 | ''' 22 | pwlcm = [0] * num 23 | pwlcm[0] = x0 24 | for i in range(1, num): 25 | if pwlcm[i - 1] > 0 and pwlcm[i - 1] < h: 26 | pwlcm[i] = pwlcm[i - 1] / h 27 | elif pwlcm[i - 1] >= h and pwlcm[i - 1] < 0.5: 28 | pwlcm[i] = (pwlcm[i - 1] - h) / (0.5 - h) 29 | elif pwlcm[i - 1] >= 0.5 and pwlcm[i - 1] < 1 - h: 30 | pwlcm[i] = (1 - pwlcm[i - 1] - h) / (0.5 - h) 31 | elif pwlcm[i - 1] >= 1 - h and pwlcm[i - 1] < 1: 32 | pwlcm[i] = (1 - pwlcm[i - 1]) / h 33 | else: 34 | raise ValueError("xi must be in [0, 1]") 35 | return pwlcm 36 | -------------------------------------------------------------------------------- /improvement/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | params/ -------------------------------------------------------------------------------- /improvement/README.md: -------------------------------------------------------------------------------- 1 | # 基于混沌映射与位平面分解的彩色图像加密算法实验 2 | 3 | 数字内容安全结课作业代码 4 | 5 | ## 介绍 6 | 7 | - 本项目为数字内容安全结课作业论文中提出的图像加密算法的 python 实现,完成了加密算法、解密算法以及性能分析。 8 | 9 | ## 目录结构 10 | ``` 11 | - analysis/ 12 | - __init__.py 13 | - bifurcation.py: 分岔图 14 | - correlation.py: 相邻像素相关性分析 15 | - differencial.py: 差分攻击分析 16 | - entropy.py: 信息熵分析 17 | - histogram.py: 直方图分析 18 | - sensitivity.py: 密钥敏感测试 19 | - docs/: 实验结果记录 20 | - img/: 实验截图 21 | - ... 22 | - 实验过程录像.mp4 23 | - images/: 实验图片存放路径 24 | - ... 25 | - params/: 密钥存放路径 26 | - ... 27 | - decrypt.py:(核心算法)加密函数 28 | - encrypt.py:(核心算法)解密函数 29 | - main.py: 主函数,加解密 + 性能分析 30 | - utils.py: 图像的位平面分解 + 生成混沌映射序列 31 | - requirements.txt: 程序所需的 python 第三方依赖库 32 | - result.txt: 数据结果文件 33 | - README.md 34 | ``` 35 | ## 使用方法 36 | 37 | - 需要 python 版本>=3.9 38 | 39 | - 新建 python 虚拟环境。以 anaconda 为例,执行: 40 | 41 | ```shell 42 | conda create -n encrpyt python=3.9 43 | conda activate encrypt 44 | ``` 45 | 46 | - 激活虚拟环境后安装依赖(如果不需要使用虚拟环境则直接安装依赖): 47 | 48 | ```shell 49 | pip install -r requirements.txt 50 | ``` 51 | 52 | - 运行代码 53 | 1. 加解密 + 性能分析:将要处理的图像放到 `images` 目录下,修改 `main.py` 第 7 行的图像名称(注意加后缀,默认为 lena 图),运行 `python main.py` 54 | 2. 如果要单独执行/不执行某一个方法,请自行在 `main.py` 中添加/注释对应的函数(注意传参) 55 | 56 | ## 加密效果展示 57 | 58 | 选择四组不同宽高比例的图像进行加密,得到的结果如下: 59 | 60 | ![实验结果](docs/img/实验结果.png) 61 | 62 | ## 实验过程记录 63 | 64 | 以 lena 图为输入,执行的结果如下 65 | 66 | - 分岔图 67 | 68 | ![分岔图](docs/img/分岔图.png) 69 | 70 | - 加密图像 71 | 72 | ![加密图像](docs/img/加密图像.png) 73 | 74 | - 解密图像 75 | 76 | ![解密图像](docs/img/解密图像.png) 77 | 78 | - 直方图分析 79 | 80 | ![原始图像直方图](docs/img/原始图像直方图.png) 81 | 82 | ![加密图像直方图](docs/img/加密图像直方图.png) 83 | 84 | - 相关性分析 85 | 86 | ![原始图像的相关性分析](docs/img/原始图像相关性分析.png) 87 | 88 | ![加密图像的相关性分析](docs/img/加密图像相关性分析.png) 89 | 90 | - 密钥敏感性分析 91 | 92 | ![加密过程的密钥敏感性分析](docs/img/加密过程的密钥敏感性分析.png) 93 | 94 | ![解密过程的密钥敏感性分析](docs/img/解密过程的密钥敏感性分析.png) 95 | 96 | - 其他分析数据(保存在 `result.txt` 文件中) 97 | 98 | ``` 99 | +---------------------------------+ 100 | | 加解密过程的性能分析 | 101 | +---------------------------------+ 102 | 103 | =======原始图像的各方向的相关系数======= 104 | 通道 Horizontal Vertical Diagonal 105 | R 0.9392 0.9687 0.9024 106 | G 0.9075 0.9439 0.8756 107 | B 0.8991 0.9356 0.8702 108 | 109 | =======加密图像的各方向的相关系数======= 110 | 通道 Horizontal Vertical Diagonal 111 | R 0.0234 0.0420 -0.0096 112 | G -0.0144 0.0076 0.0015 113 | B -0.0075 -0.0095 -0.0041 114 | 115 | ====原图像信息熵==== 116 | 通道R: 7.0345 117 | 通道G: 7.3485 118 | 通道B: 6.9985 119 | 120 | ===加密图像信息熵=== 121 | 通道R: 7.9974 122 | 通道G: 7.9972 123 | 通道B: 7.9973 124 | 125 | ========NPCR======== 126 | Red : 99.6536% 127 | Green: 99.6506% 128 | Blue : 99.5773% 129 | 130 | ========UACI======== 131 | Red : 33.6691% 132 | Green: 33.5097% 133 | Blue : 33.5444% 134 | 135 | 136 | 137 | +---------------------------------+ 138 | | 100次相关性分析和差分攻击分析 | 139 | +---------------------------------+ 140 | 141 | =======原始图像的各方向的相关系数======= 142 | 通道 Horizontal Vertical Diagonal 143 | R 0.9385 0.9701 0.9056 144 | G 0.9090 0.9537 0.8830 145 | B 0.8954 0.9354 0.8555 146 | 147 | =======加密图像的各方向的相关系数======= 148 | 通道 Horizontal Vertical Diagonal 149 | R 0.0016 -0.0052 0.0081 150 | G -0.0027 0.0113 -0.0035 151 | B 0.0034 0.0040 -0.0009 152 | 153 | ========NPCR======== 154 | Red : 99.6246% 155 | Green: 99.6368% 156 | Blue : 99.6323% 157 | 158 | ========UACI======== 159 | Red : 33.4701% 160 | Green: 33.5498% 161 | Blue : 33.3755% 162 | ``` -------------------------------------------------------------------------------- /improvement/analysis/__init__.py: -------------------------------------------------------------------------------- 1 | from .correlation import correlation 2 | from .differencial import differencial 3 | from .entropy import entropy 4 | from .histogram import histogram 5 | from .sensitivity import decrypt_sensitivity, encrypt_sensitivity 6 | from .bifurcation import bifurcation_diagram 7 | -------------------------------------------------------------------------------- /improvement/analysis/bifurcation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from utils import PWLCM 3 | from matplotlib import pyplot as plt 4 | from random import uniform 5 | 6 | 7 | def bifurcation_diagram(seed, n_skip, n_iter, step=1e-4, u_min=1e-16): 8 | ''' 9 | 绘制分岔图 10 | ''' 11 | print("Starting with x0 seed {0}, skip plotting first {1} iterations, then plot next {2} iterations.".format( 12 | seed, n_skip, n_iter)) 13 | # μ 列表, 分岔图的 x 轴 14 | U = [] 15 | # x 列表, 分岔图的 y 轴 16 | X = [] 17 | 18 | a=uniform(40,100) 19 | 20 | # Create the r values to loop. For each r value we will plot n_iter points 21 | u_range = np.linspace(u_min, 0.5-(1e-16), int(1/step)) 22 | for u in u_range: 23 | U.extend([u]*(n_iter+1)) 24 | X.extend(PWLCM(seed, u, a, n_iter+n_skip+1)[n_skip:]) 25 | 26 | # Plot the data 27 | plt.plot(U, X, ls='', marker=',') 28 | plt.ylim(0, 1) 29 | plt.xlim(u_min, 0.5) 30 | plt.xlabel('μ') 31 | plt.ylabel('X') 32 | plt.show() 33 | 34 | 35 | if __name__ == "__main__": 36 | bifurcation_diagram(0.2, 100, 10) 37 | -------------------------------------------------------------------------------- /improvement/analysis/correlation.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | ''' 6 | 分别计算图像通道相邻像素的水平、垂直和对角线的相关系数并返回 7 | ''' 8 | 9 | def RGB_correlation(channel, N): 10 | # 计算channel通道 11 | h, w = channel.shape 12 | # 随机产生pixels个[0,w-1)范围内的整数序列 13 | row = np.random.randint(0, h-1, N) 14 | col = np.random.randint(0, w-1, N) 15 | # 绘制相邻像素相关性图,统计x,y坐标 16 | x = [] 17 | h_y = [] 18 | v_y = [] 19 | d_y = [] 20 | for i in range(N): 21 | # 选择当前一个像素 22 | x.append(channel[row[i]][col[i]]) 23 | # 水平相邻像素是它的右侧也就是同行下一列的像素 24 | h_y.append(channel[row[i]][col[i]+1]) 25 | # 垂直相邻像素是它的下方也就是同列下一行的像素 26 | v_y.append(channel[row[i]+1][col[i]]) 27 | # 对角线相邻像素是它的右下即下一行下一列的那个像素 28 | d_y.append(channel[row[i]+1][col[i]+1]) 29 | # 三个方向的合到一起 30 | x = x*3 31 | y = h_y+v_y+d_y 32 | 33 | # 计算E(x),计算三个方向相关性时,x没有重新选择也可以更改 34 | ex = 0 35 | for i in range(N): 36 | ex += channel[row[i]][col[i]] 37 | ex = ex/N 38 | # 计算D(x) 39 | dx = 0 40 | for i in range(N): 41 | dx += (channel[row[i]][col[i]]-ex)**2 42 | dx /= N 43 | 44 | # 水平相邻像素h_y 45 | # 计算E(y) 46 | h_ey = 0 47 | for i in range(N): 48 | h_ey += channel[row[i]][col[i]+1] 49 | h_ey /= N 50 | # 计算D(y) 51 | h_dy = 0 52 | for i in range(N): 53 | h_dy += (channel[row[i]][col[i]+1]-h_ey)**2 54 | h_dy /= N 55 | # 计算协方差 56 | h_cov = 0 57 | for i in range(N): 58 | h_cov += (channel[row[i]][col[i]]-ex)*(channel[row[i]][col[i]+1]-h_ey) 59 | h_cov /= N 60 | h_Rxy = h_cov/(np.sqrt(dx)*np.sqrt(h_dy)) 61 | 62 | # 垂直相邻像素v_y 63 | # 计算E(y) 64 | v_ey = 0 65 | for i in range(N): 66 | v_ey += channel[row[i]+1][col[i]] 67 | v_ey /= N 68 | # 计算D(y) 69 | v_dy = 0 70 | for i in range(N): 71 | v_dy += (channel[row[i]+1][col[i]]-v_ey)**2 72 | v_dy /= N 73 | # 计算协方差 74 | v_cov = 0 75 | for i in range(N): 76 | v_cov += (channel[row[i]][col[i]]-ex)*(channel[row[i]+1][col[i]]-v_ey) 77 | v_cov /= N 78 | v_Rxy = v_cov/(np.sqrt(dx)*np.sqrt(v_dy)) 79 | 80 | # 对角线相邻像素d_y 81 | # 计算E(y) 82 | d_ey = 0 83 | for i in range(N): 84 | d_ey += channel[row[i]+1][col[i]+1] 85 | d_ey /= N 86 | # 计算D(y) 87 | d_dy = 0 88 | for i in range(N): 89 | d_dy += (channel[row[i]+1][col[i]+1]-d_ey)**2 90 | d_dy /= N 91 | # 计算协方差 92 | d_cov = 0 93 | for i in range(N): 94 | d_cov += (channel[row[i]][col[i]]-ex) * \ 95 | (channel[row[i]+1][col[i]+1]-d_ey) 96 | d_cov /= N 97 | d_Rxy = d_cov/(np.sqrt(dx)*np.sqrt(d_dy)) 98 | 99 | return h_Rxy, v_Rxy, d_Rxy, x, y 100 | 101 | 102 | ''' 103 | 分别计算图像img的各通道相邻像素的相关系数,默认随机选取3000对相邻像素 104 | ''' 105 | 106 | 107 | def show_correlation(img, N=3000, is_raw=True, is_show=True): 108 | img = cv2.imread(img) 109 | h, w, _ = img.shape 110 | B, G, R = cv2.split(img) 111 | R_Rxy = RGB_correlation(R, N) 112 | G_Rxy = RGB_correlation(G, N) 113 | B_Rxy = RGB_correlation(B, N) 114 | 115 | if is_show: 116 | # 结果展示 117 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 118 | plt.subplot(221) 119 | plt.imshow(img[:, :, (2, 1, 0)]) 120 | plt.title('原图像' if is_raw else '加密图像') 121 | # 子图2 122 | plt.subplot(222) 123 | plt.scatter(R_Rxy[3], R_Rxy[4], s=1, c='red') 124 | plt.title('通道R') 125 | 126 | # 子图3 127 | plt.subplot(223) 128 | plt.scatter(G_Rxy[3], G_Rxy[4], s=1, c='green') 129 | plt.title('通道G') 130 | # 子图4 131 | plt.subplot(224) 132 | plt.scatter(B_Rxy[3], B_Rxy[4], s=1, c='blue') 133 | plt.title('通道B') 134 | plt.show() 135 | 136 | return R_Rxy[0:3], G_Rxy[0:3], B_Rxy[0:3] 137 | 138 | 139 | def correlation(img, encrypt_img, is_mean=False, ntimes=1): 140 | with open('result.txt','a+', encoding='utf8') as f: 141 | R_Rxy, G_Rxy, B_Rxy = show_correlation(img, is_show=not is_mean) 142 | f.write("=======原始图像的各方向的相关系数=======\n") 143 | f.write('通道\tHorizontal\tVertical\tDiagonal\n') 144 | f.write(' R\t{: .4f}\t{: .4f}\t{: .4f}\n'.format( 145 | R_Rxy[0], R_Rxy[1], R_Rxy[2])) 146 | f.write(' G\t{: .4f}\t{: .4f}\t{: .4f}\n'.format( 147 | G_Rxy[0], G_Rxy[1], G_Rxy[2])) 148 | f.write(' B\t{: .4f}\t{: .4f}\t{: .4f}\n'.format( 149 | B_Rxy[0], B_Rxy[1], B_Rxy[2])) 150 | f.write('\n') 151 | 152 | R_Rxy_mean = [[],[],[]] 153 | G_Rxy_mean = [[],[],[]] 154 | B_Rxy_mean = [[],[],[]] 155 | for i in range(ntimes): 156 | R_Rxy, G_Rxy, B_Rxy = show_correlation(encrypt_img, is_raw=False, is_show=not is_mean) 157 | for j in range(3): 158 | R_Rxy_mean[j].append(R_Rxy[j]) 159 | G_Rxy_mean[j].append(G_Rxy[j]) 160 | B_Rxy_mean[j].append(B_Rxy[j]) 161 | 162 | with open('result.txt','a+', encoding='utf8') as f: 163 | f.write("=======加密图像的各方向的相关系数=======\n") 164 | f.write('通道\tHorizontal\tVertical\tDiagonal\n') 165 | f.write(' R\t{: .4f}\t{: .4f}\t{: .4f}\n'.format( 166 | np.mean(R_Rxy_mean[0]), np.mean(R_Rxy_mean[1]), np.mean(R_Rxy_mean[2]))) 167 | f.write(' G\t{: .4f}\t{: .4f}\t{: .4f}\n'.format( 168 | np.mean(G_Rxy_mean[0]), np.mean(G_Rxy_mean[1]), np.mean(G_Rxy_mean[2]))) 169 | f.write(' B\t{: .4f}\t{: .4f}\t{: .4f}\n'.format( 170 | np.mean(B_Rxy_mean[0]), np.mean(B_Rxy_mean[1]), np.mean(B_Rxy_mean[2]))) 171 | f.write('\n') 172 | 173 | 174 | if __name__ == '__main__': 175 | img = '../images/lena.png' 176 | encrypt_img = '../images/lena_encrypt.png' 177 | correlation(img, encrypt_img, is_mean=True, ntimes=100) 178 | -------------------------------------------------------------------------------- /improvement/analysis/differencial.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | from encrypt import encrypt 4 | from os import remove 5 | 6 | ''' 7 | 计算像素数变化率 8 | ''' 9 | 10 | 11 | def NPCR(img1, img2): 12 | # opencv颜色通道顺序为BGR 13 | w, h, _ = img1.shape 14 | 15 | # 图像通道拆分 16 | B1, G1, R1 = cv2.split(img1) 17 | B2, G2, R2 = cv2.split(img2) 18 | # 返回数组的排序后的唯一元素和每个元素重复的次数 19 | ar, num = np.unique((R1 != R2), return_counts=True) 20 | R_npcr = (num[0] if ar[0] == True else num[1])/(w*h) 21 | ar, num = np.unique((G1 != G2), return_counts=True) 22 | G_npcr = (num[0] if ar[0] == True else num[1])/(w*h) 23 | ar, num = np.unique((B1 != B2), return_counts=True) 24 | B_npcr = (num[0] if ar[0] == True else num[1])/(w*h) 25 | 26 | return R_npcr, G_npcr, B_npcr 27 | 28 | 29 | ''' 30 | 两张图像之间的平均变化强度 31 | ''' 32 | 33 | 34 | def UACI(img1, img2): 35 | w, h, _ = img1.shape 36 | # 图像通道拆分 37 | B1, G1, R1 = cv2.split(img1) 38 | B2, G2, R2 = cv2.split(img2) 39 | # 元素为uint8类型取值范围:0到255 40 | # print(R1.dtype) 41 | 42 | # 强制转换元素类型,为了运算 43 | R1 = R1.astype(np.int16) 44 | R2 = R2.astype(np.int16) 45 | G1 = G1.astype(np.int16) 46 | G2 = G2.astype(np.int16) 47 | B1 = B1.astype(np.int16) 48 | B2 = B2.astype(np.int16) 49 | 50 | sumR = np.sum(abs(R1-R2)) 51 | sumG = np.sum(abs(G1-G2)) 52 | sumB = np.sum(abs(B1-B2)) 53 | R_uaci = sumR/255/(w*h) 54 | G_uaci = sumG/255/(w*h) 55 | B_uaci = sumB/255/(w*h) 56 | 57 | return R_uaci, G_uaci, B_uaci 58 | 59 | 60 | def differencial(img_path, ntimes=1): 61 | img_path_2 = img_path.rsplit('.', 1)[0] + '_differencial.png' 62 | img = cv2.imread(img_path) 63 | img[0][0][0] = img[0][0][0] ^ 1 # 修改B通道第一个像素值的第5位 64 | cv2.imwrite(img_path_2, img) 65 | _, img1 = encrypt(img_path) 66 | _, img2 = encrypt(img_path_2) 67 | R_npcr_mean = [] 68 | G_npcr_mean = [] 69 | B_npcr_mean = [] 70 | for i in range(ntimes): 71 | R_npcr, G_npcr, B_npcr = NPCR(img1, img2) 72 | R_npcr_mean.append(R_npcr) 73 | G_npcr_mean.append(G_npcr) 74 | B_npcr_mean.append(B_npcr) 75 | # print('\n *差分攻击* ') 76 | with open('result.txt','a+', encoding='utf8') as f: 77 | f.write('========NPCR========\n') 78 | # 百分数表示,保留小数点后4位 79 | f.write('Red :\t{:.4%}\n'.format(np.mean(R_npcr_mean))) 80 | f.write('Green:\t{:.4%}\n'.format(np.mean(G_npcr_mean))) 81 | f.write('Blue :\t{:.4%}\n'.format(np.mean(B_npcr_mean))) 82 | f.write('\n') 83 | 84 | R_uaci_mean = [] 85 | G_uaci_mean = [] 86 | B_uaci_mean = [] 87 | for i in range(100): 88 | R_uaci, G_uaci, B_uaci = UACI(img1, img2) 89 | R_uaci_mean.append(R_uaci) 90 | G_uaci_mean.append(G_uaci) 91 | B_uaci_mean.append(B_uaci) 92 | with open('result.txt', 'a+', encoding='utf8') as f: 93 | f.write('========UACI========\n') 94 | # 百分数表示,保留小数点后4位 95 | f.write('Red :\t{:.4%}\n'.format(np.mean(R_uaci_mean))) 96 | f.write('Green:\t{:.4%}\n'.format(np.mean(G_uaci_mean))) 97 | f.write('Blue :\t{:.4%}\n'.format(np.mean(B_uaci_mean))) 98 | f.write('\n') 99 | remove(img_path_2) 100 | remove(img_path_2.rsplit('.', 1)[0] + '_encrypt.png') 101 | 102 | 103 | if __name__ == '__main__': 104 | img_path = '../images/lena.png' 105 | differencial(img_path, ntimes=100) 106 | -------------------------------------------------------------------------------- /improvement/analysis/entropy.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import math 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | 7 | ''' 8 | 计算图像的信息熵 9 | ''' 10 | 11 | 12 | def _entropy(img): 13 | img = cv2.imread(img) 14 | w, h, _ = img.shape 15 | B, G, R = cv2.split(img) 16 | gray, num1 = np.unique(R, return_counts=True) 17 | gray, num2 = np.unique(G, return_counts=True) 18 | gray, num3 = np.unique(B, return_counts=True) 19 | R_entropy = 0 20 | G_entropy = 0 21 | B_entropy = 0 22 | 23 | for i in range(len(gray)): 24 | p1 = num1[i]/(w*h) 25 | p2 = num2[i]/(w*h) 26 | p3 = num3[i]/(w*h) 27 | R_entropy -= p1*(math.log(p1, 2)) 28 | G_entropy -= p2*(math.log(p2, 2)) 29 | B_entropy -= p3*(math.log(p3, 2)) 30 | return R_entropy, G_entropy, B_entropy 31 | 32 | 33 | def entropy(raw_img, encrypt_img): 34 | with open('result.txt','a+', encoding='utf8') as f: 35 | R_entropy, G_entropy, B_entropy = _entropy(raw_img) 36 | f.write('====原图像信息熵====\n') 37 | f.write('通道R:\t\t{:.5}\n'.format(R_entropy)) 38 | f.write('通道G:\t\t{:.5}\n'.format(G_entropy)) 39 | f.write('通道B:\t\t{:.5}\n'.format(B_entropy)) 40 | f.write('\n') 41 | R_entropy, G_entropy, B_entropy = _entropy(encrypt_img) 42 | f.write('===加密图像信息熵===\n') 43 | f.write('通道R:\t\t{:.5}\n'.format(R_entropy)) 44 | f.write('通道G:\t\t{:.5}\n'.format(G_entropy)) 45 | f.write('通道B:\t\t{:.5}\n'.format(B_entropy)) 46 | f.write('\n') 47 | 48 | 49 | if __name__ == '__main__': 50 | img = '../images/lena.png' 51 | encrypt_img = '../images/lena_encrypt.png' 52 | entropy(img, encrypt_img) 53 | -------------------------------------------------------------------------------- /improvement/analysis/histogram.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import matplotlib.pyplot as plt 3 | 4 | ''' 5 | 绘制灰度直方图 6 | ''' 7 | 8 | 9 | def hist(img, is_raw=True): 10 | img = cv2.imread(img) 11 | B, G, R = cv2.split(img) 12 | # 转成一维 13 | R = R.flatten(order='C') 14 | G = G.flatten(order='C') 15 | B = B.flatten(order='C') 16 | 17 | # 结果展示 18 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 19 | plt.subplot(221) 20 | plt.hist(img.flatten(order='C'), bins=range(257), color='gray') 21 | plt.title('原始图像' if is_raw else '加密图像') 22 | 23 | # 子图2,通道R 24 | plt.subplot(222) 25 | # imshow()对图像进行处理,画出图像,show()进行图像显示 26 | plt.hist(R, bins=range(257), color='red') 27 | plt.title('通道R') 28 | 29 | # 子图3,通道G 30 | plt.subplot(223) 31 | plt.hist(G, bins=range(257), color='green') 32 | plt.title('通道G') 33 | 34 | # 子图4,通道B 35 | plt.subplot(224) 36 | plt.hist(B, bins=range(257), color='blue') 37 | plt.title('通道B') 38 | # #设置子图默认的间距 39 | plt.tight_layout() 40 | plt.show() 41 | 42 | 43 | def histogram(raw_img_path, encrypt_img_path): 44 | hist(raw_img_path) 45 | hist(encrypt_img_path, is_raw=False) 46 | 47 | 48 | if __name__ == '__main__': 49 | img_path = "../images/lena_encrypt.png" 50 | histogram(img_path) 51 | -------------------------------------------------------------------------------- /improvement/analysis/sensitivity.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from matplotlib import pyplot as plt 3 | from encrypt import encrypt 4 | from decrypt import decrypt 5 | import numpy as np 6 | 7 | 8 | def encrypt_sensitivity(img_path, key=None, modified_key=None): 9 | key = [0.35064345739679, 0.18323119961402, 10 | 0.35575518510453, 0.24485837450082, 11 | 86.720536734684, 58.084300779634] if not key else key 12 | modified_key = [0.35064345739679, 0.18323119961402, 13 | 0.35575518510454, 0.24485837450082, 14 | 86.720536734684, 58.084300779634] if not modified_key else modified_key 15 | 16 | # 结果展示 17 | # 原图像 18 | r_img = cv2.imread(img_path) 19 | b, g, r = cv2.split(r_img) 20 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 21 | plt.subplot(221) 22 | plt.imshow(cv2.merge([r, g, b])) 23 | plt.title('原图像') 24 | 25 | # key加密的图像 26 | _, key_img = encrypt(img_path, *key) 27 | plt.subplot(222) 28 | b, g, r = cv2.split(key_img) 29 | plt.imshow(cv2.merge([r, g, b])) 30 | plt.title('key加密的图像') 31 | 32 | # 修改过的key加密的图像 33 | _, modified_key_img = encrypt(img_path, *modified_key) 34 | plt.subplot(223) 35 | b, g, r = cv2.split(modified_key_img) 36 | plt.imshow(cv2.merge([r, g, b])) 37 | plt.title('修改过的key加密的图像') 38 | 39 | # 两者差值 40 | plt.subplot(224) 41 | plt.imshow(np.abs(modified_key_img - key_img)) 42 | plt.title('两者差值') 43 | plt.show() 44 | 45 | 46 | def decrypt_sensitivity(img_path, encrypt_img_path, key=None, incorrect_key=None): 47 | key = [0.35064345739679, 0.18323119961402, 48 | 0.35575518510453, 0.24485837450082, 49 | 86.720536734684, 58.084300779634] if not key else key 50 | if not incorrect_key: 51 | incorrect_key = [0.35064345739679, 0.18323119961402, 52 | 0.35575518510454, 0.24485837450082, 53 | 86.720536734684, 58.084300779634] 54 | 55 | # 结果展示 56 | # 原图像 57 | r_img = cv2.imread(img_path) 58 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 59 | plt.subplot(221) 60 | b, g, r = cv2.split(r_img) 61 | plt.imshow(cv2.merge([r, g, b])) 62 | plt.title('原图像') 63 | 64 | # 原始key加密的图像 65 | _, key_img = encrypt(img_path, *key) 66 | plt.subplot(222) 67 | b, g, r = cv2.split(key_img) 68 | plt.imshow(cv2.merge([r, g, b])) 69 | plt.title('原始key加密的图像') 70 | 71 | # 修改过的key解密的图像 72 | # 读取参数 73 | raw_params = np.load('./params/params.npz') 74 | np.savez('./params/incorrect_params.npz', 75 | x0=incorrect_key[0], u1=incorrect_key[1], 76 | y0=incorrect_key[2], u2=incorrect_key[3], 77 | a1=incorrect_key[4], a2=incorrect_key[5], 78 | A11_0=raw_params['A11_0'], A22_0=raw_params['A22_0'], 79 | n_round=raw_params['n_round']) 80 | incorrect_decrypt_img = decrypt( 81 | encrypt_img_path, params_path='incorrect_params.npz') 82 | plt.subplot(223) 83 | b, g, r = cv2.split(incorrect_decrypt_img) 84 | plt.imshow(cv2.merge([r, g, b])) 85 | plt.title('修改过的key解密的图像') 86 | 87 | # 原始key解密的图像 88 | decrypt_img = decrypt(encrypt_img_path, params_path='params.npz') 89 | plt.subplot(224) 90 | b, g, r = cv2.split(decrypt_img) 91 | plt.imshow(cv2.merge([r, g, b])) 92 | plt.title('原始key解密的图像') 93 | plt.show() 94 | 95 | 96 | if __name__ == "__main__": 97 | img_path = "../images/lena.png" 98 | encrypt_img_path = "../images/lena_encrypt.png" 99 | encrypt_sensitivity(img_path) 100 | decrypt_sensitivity(img_path, encrypt_img_path, None, None) 101 | -------------------------------------------------------------------------------- /improvement/decrypt.py: -------------------------------------------------------------------------------- 1 | from math import floor 2 | import cv2 3 | import numpy as np 4 | from copy import deepcopy 5 | from matplotlib import pyplot as plt 6 | from utils import PWLCM, img_bit_decomposition 7 | 8 | 9 | def decrypt(encrypt_img_path, raw_img_path=None, params_path='params.npz', show=False): 10 | ''' 11 | 解密图像 12 | ''' 13 | npz_file = np.load(f"./params/{params_path}") # 加载参数 14 | x0, u1, y0, u2, a1, a2, A11_0, A22_0, n_round = \ 15 | npz_file['x0'], \ 16 | npz_file['u1'], \ 17 | npz_file['y0'], \ 18 | npz_file['u2'], \ 19 | npz_file['a1'], \ 20 | npz_file['a2'], \ 21 | npz_file['A11_0'], \ 22 | npz_file['A22_0'], \ 23 | npz_file['n_round'] 24 | A11_0 = [int(i) for i in list(bin(A11_0)[2:])[1:]] 25 | A11_0 = [A11_0[2*len(A11_0)//3:], A11_0[len(A11_0)//3:2 * 26 | len(A11_0)//3], A11_0[:len(A11_0)//3]] 27 | A22_0 = [int(i) for i in list(bin(A22_0)[2:])[1:]] 28 | A22_0 = [A22_0[2*len(A22_0)//3:], A22_0[len(A22_0)//3:2 * 29 | len(A22_0)//3], A22_0[:len(A22_0)//3]] 30 | # print( 31 | # f"参数:\nx0: {x0}, u1: {u1},\ny0: {y0}, u2: {u2},\nA11_0: {A11_0}, A22_0: {A22_0},\nn_round: {n_round}" 32 | # ) 33 | filename, ext = encrypt_img_path.rsplit('.', 1) 34 | decrypt_img_path = f"{filename}_decrypt.{ext}" 35 | 36 | img = cv2.imread(encrypt_img_path) # 读取图像 37 | 38 | M, N, _ = img.shape # M: height, N: width 39 | 40 | B, G, R = cv2.split(img) # BGR 41 | 42 | A = [] 43 | 44 | if M != M or N != N: 45 | raise ValueError("The shape of image is not correct!") 46 | 47 | if show: 48 | print(f"图像分辨率为: {N} x {M}") 49 | 50 | N0 = 1000 # 舍弃前N0个数 51 | for ib, b in enumerate([B, G, R]): 52 | C = b 53 | PWLCM_MAP_X = PWLCM(x0, u1, a1, N0 + M*N)[N0:] 54 | X1 = [floor(i * 1e14) % 256 for i in PWLCM_MAP_X] # key1 55 | X1_reshape = np.mat(X1, dtype=np.uint8).reshape(M, N) 56 | X1_bitplanes = img_bit_decomposition(X1_reshape) # key1的位平面分解 57 | b1 = X1_bitplanes[::2, :, :].ravel() # key1的偶数位平面 58 | b2 = X1_bitplanes[1::2, :, :].ravel() # key1的奇数位平面 59 | 60 | bitplanes = img_bit_decomposition(C) # 位平面分解 61 | C1 = bitplanes[:4, :, :].ravel() 62 | C2 = bitplanes[4:, :, :].ravel() 63 | 64 | L = M * N * 4 65 | for k in range(n_round): 66 | # 逆混淆 67 | sum = np.sum(C1) + np.sum(C2) # C1 和 C2 的和 68 | s0 = (y0 + sum / L) % 1 # key2的初始值s0 69 | S = PWLCM(s0, u2, a2, N0 + 2 * L)[N0:] 70 | S1, S2 = S[:L], S[L:] 71 | Y = [floor(s1 * 1e14) % L for s1 in S1] 72 | Z = [floor(s2 * 1e14) % L for s2 in S2] 73 | 74 | for j in range(L-1, -1, -1): 75 | C2[j], C1[Z[j]] = C1[Z[j]], C2[j] 76 | for i in range(L-1, -1, -1): 77 | C1[i], C2[Y[i]] = C2[Y[i]], C1[i] 78 | 79 | B1, B2 = C1, C2 80 | 81 | # 逆扩散 82 | sum2 = np.sum(B1) # B1 的和 83 | A11 = np.zeros(L, dtype=np.uint8) 84 | A22 = np.zeros(L, dtype=np.uint8) 85 | A22[0] = A22_0[ib][k] 86 | for i in range(1, L): 87 | A22[i] = A22[i - 1] ^ B1[i] ^ B2[i] ^ b2[i] 88 | A2 = np.roll(A22, -1*sum2) # A2 循环左移 sum2 位 89 | sum1 = np.sum(A2) # A2 的和 90 | A11[0] = A11_0[ib][k] 91 | for i in range(1, L): 92 | A11[i] = A11[i - 1] ^ A2[i] ^ B1[i] ^ b1[i] 93 | A1 = np.roll(A11, -1*sum1) # A1 循环左移 sum1 位 94 | C1 = deepcopy(A1) 95 | C2 = deepcopy(A2) 96 | A.append([A1, A2]) 97 | 98 | A_BGR = [] 99 | for e in A: 100 | A_IMG = np.append(e[0], e[1])[::-1].reshape(8, M, N)[:, ::-1, ::-1] 101 | res = np.zeros((M, N), dtype=np.uint8) 102 | for i in range(8): 103 | res = cv2.bitwise_or(res, A_IMG[i, :, :] << i) 104 | A_BGR.append(res) 105 | I = cv2.merge(A_BGR[::-1]) 106 | 107 | cv2.imwrite(decrypt_img_path, I) 108 | 109 | # 验证解密得到的图像为原图像 110 | if raw_img_path: 111 | raw_img = cv2.imread(raw_img_path) 112 | r_B, r_G, r_R = cv2.split(raw_img) 113 | R, G, B = A_BGR 114 | if not np.sum(np.abs(r_B-B)) and not np.sum(np.abs(r_G-G)) and not np.sum(np.abs(r_R-R)): 115 | print("解密成功!") 116 | else: 117 | print("解密失败!") 118 | 119 | # 显示图像 120 | if show: 121 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 122 | plt.imshow(cv2.merge(A_BGR)) 123 | plt.title("解密图像") 124 | plt.show() 125 | 126 | return I 127 | 128 | 129 | if __name__ == "__main__": 130 | encrypt_img_path = "./data/rabbit1_encrypt.png" # 要解密的图像路径 131 | raw_img_path = "./data/rabbit1.jpg" # 原始图像路径 132 | decrypt(encrypt_img_path, raw_img_path) 133 | -------------------------------------------------------------------------------- /improvement/docs/img/分岔图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/分岔图.png -------------------------------------------------------------------------------- /improvement/docs/img/加密图像.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/加密图像.png -------------------------------------------------------------------------------- /improvement/docs/img/加密图像直方图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/加密图像直方图.png -------------------------------------------------------------------------------- /improvement/docs/img/加密图像相关性分析.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/加密图像相关性分析.png -------------------------------------------------------------------------------- /improvement/docs/img/加密过程的密钥敏感性分析.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/加密过程的密钥敏感性分析.png -------------------------------------------------------------------------------- /improvement/docs/img/原始图像直方图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/原始图像直方图.png -------------------------------------------------------------------------------- /improvement/docs/img/原始图像相关性分析.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/原始图像相关性分析.png -------------------------------------------------------------------------------- /improvement/docs/img/实验结果.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/实验结果.png -------------------------------------------------------------------------------- /improvement/docs/img/解密图像.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/解密图像.png -------------------------------------------------------------------------------- /improvement/docs/img/解密过程的密钥敏感性分析.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/docs/img/解密过程的密钥敏感性分析.png -------------------------------------------------------------------------------- /improvement/encrypt.py: -------------------------------------------------------------------------------- 1 | from math import floor 2 | import cv2 3 | import numpy as np 4 | import os 5 | from random import uniform 6 | from copy import deepcopy 7 | from matplotlib import pyplot as plt 8 | from functools import reduce 9 | from utils import img_bit_decomposition, PWLCM 10 | 11 | 12 | def encrypt( 13 | img_path, 14 | x0=None, u1=None, y0=None, u2=None, a1=None, a2=None, # 密钥 15 | n_round=1, # 加密轮数 16 | params_path='params.npz', # 参数保存路径 17 | show=False, # 是否显示图像 18 | use_params=False # 是否使用已有参数 19 | ): 20 | ''' 21 | 加密图像 22 | x0, u1, y0, u2: 混沌序列的初始值和参数 23 | N0: 丢弃前N0个数 24 | n_round: 加密轮数 25 | params_path: 参数保存路径,只需要写文件名+后缀,不需要写绝对路径 26 | show: 是否显示图像 27 | use_params: 是否使用已有参数 28 | ''' 29 | if not use_params: 30 | x0 = uniform(1e-16, 1-1e-16) if not x0 else x0 # key1的初始值x0 31 | u1 = uniform(1e-16, 0.5-1e-16) if not u1 else u1 # key1的初始值u1 32 | y0 = uniform(1e-16, 1-1e-16) if not y0 else y0 # 初始值y0 33 | u2 = uniform(1e-16, 0.5-1e-16) if not u2 else u2 # 初始值u2 34 | a1 = uniform(40,100) if not a1 else a1 35 | a2 = uniform(40,100) if not a2 else a2 36 | else: 37 | use_params_path = f"./params/{params_path}" 38 | if os.path.exists(use_params_path): 39 | params = np.load(use_params_path) 40 | x0 = params['x0'] 41 | u1 = params['u1'] 42 | y0 = params['y0'] 43 | u2 = params['u2'] 44 | a1 = params['a1'] 45 | a2 = params['a2'] 46 | n_round = params['n_round'] 47 | else: 48 | raise FileNotFoundError(f"未找到参数文件: {use_params_path}") 49 | # print(f"使用的参数为: \nx0={x0},\nu1={u1},\ny0={y0},\nu2={u2},\na1={a1},\na2={a2}") 50 | filename, ext = img_path.rsplit('.', 1) 51 | encrypt_img_path = f"{filename}_encrypt.png" 52 | 53 | img = cv2.imread(img_path) # 读取图像 54 | 55 | M, N, _ = img.shape # M: height, N: width 56 | 57 | B, G, R = cv2.split(img) 58 | 59 | if show: 60 | print(f"图像分辨率为: {N} x {M}") 61 | 62 | B_bitplanes = img_bit_decomposition(B)[::-1, :, :] # 位平面分解 63 | G_bitplanes = img_bit_decomposition(G)[::-1, :, :] 64 | R_bitplanes = img_bit_decomposition(R)[::-1, :, :] 65 | B_A1 = B_bitplanes[:4, :, :].ravel() # B的高位平面 66 | B_A2 = B_bitplanes[4:, :, :].ravel() # B的低位平面 67 | G_A1 = G_bitplanes[:4, :, :].ravel() # G的高位平面 68 | G_A2 = G_bitplanes[4:, :, :].ravel() # G的低位平面 69 | R_A1 = R_bitplanes[:4, :, :].ravel() # R的高位平面 70 | R_A2 = R_bitplanes[4:, :, :].ravel() # R的低位平面 71 | E_BGR = [] 72 | A11_0 = [[], [], []] 73 | A22_0 = [[], [], []] 74 | for ib, b in enumerate([(B_A1, B_A2), (G_A1, G_A2), (R_A1, R_A2)]): 75 | A1, A2 = b 76 | # Piecewise Logistic Chaotic Map 77 | N0 = 1000 # 丢弃前N0个数 78 | PWLCM_MAP_X = PWLCM(x0, u1, a1, N0 + M*N)[N0:] # 生成长度为N0+M*N的混沌序列 79 | # key1,将[PWLCM_MAP_X]中每个小数转换为整数并对256取模得到0~255之间的整数作为key1的值 80 | X1 = [floor(i * 1e14) % 256 for i in PWLCM_MAP_X] 81 | X1_reshape = np.mat(X1, dtype=np.uint8).reshape(M, N) 82 | X1_bitplanes = img_bit_decomposition(X1_reshape) # key1的位平面分解 83 | b1 = X1_bitplanes[::2, :, :].ravel() # key1的偶数位平面 84 | b2 = X1_bitplanes[1::2, :, :].ravel() # key1的奇数位平面 85 | 86 | L = M * N * 4 87 | for k in range(n_round): 88 | # 初始化B1和B2 89 | B1 = np.zeros(L, dtype=np.uint8) 90 | B2 = np.zeros(L, dtype=np.uint8) 91 | # 扩散 92 | sum1 = np.sum(A2) # A2 的和 93 | A11 = np.roll(A1, sum1) # 高位平面的循环右移 sum1 位 94 | for i in range(L): 95 | B1[i] = A11[i] ^ A11[i - 1] ^ A2[i] ^ b1[i] 96 | sum2 = np.sum(B1) # B1 的和 97 | A22 = np.roll(A2, sum2) # 低位平面的循环右移 sum2 位 98 | for i in range(L): 99 | B2[i] = A22[i] ^ A22[i - 1] ^ B1[i] ^ b2[i] 100 | 101 | # 生成 Y 和 Z 102 | sum = np.sum(B1) + np.sum(B2) 103 | 104 | s0 = (y0 + sum / L) % 1 # key2的初始值s0 105 | S = PWLCM(s0, u2, a2, N0 + 2 * L)[N0:] 106 | S1, S2 = S[:L], S[L:] 107 | # 将S1中每个小数转换为整数并对L取模得到0~L-1之间的整数作为Y的值 108 | Y = [floor(s1 * 1e14) % L for s1 in S1] 109 | # 将S2中每个小数转换为整数并对L取模得到0~L-1之间的整数作为Z的值 110 | Z = [floor(s2 * 1e14) % L for s2 in S2] 111 | 112 | # 混淆 113 | for i in range(L): 114 | B1[i], B2[Y[i]] = B2[Y[i]], B1[i] 115 | for j in range(L): 116 | B2[j], B1[Z[j]] = B1[Z[j]], B2[j] 117 | A11_0[ib].append(A11[0]) 118 | A22_0[ib].append(A22[0]) 119 | # 用B1和B2更新A1和A2,以作为下一轮加密的输入 120 | A1 = deepcopy(B1) 121 | A2 = deepcopy(B2) 122 | # C1,C2 序列合并成加密图像 123 | C_bitplanes = np.append(B1, B2).reshape(8, M, N) 124 | C = np.zeros((M, N), dtype=np.uint8) 125 | for i in range(8): 126 | C = cv2.bitwise_or(C, C_bitplanes[i, :, :] << i) 127 | E = C 128 | E_BGR.append(E) 129 | E_BGR = E_BGR[::-1] 130 | E = cv2.merge(E_BGR) 131 | cv2.imwrite(encrypt_img_path, E) # 保存图像 132 | 133 | # 显示加密图像 134 | if show: 135 | print('加密完成!') 136 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码 137 | plt.imshow(E, cmap='gray') 138 | plt.title('加密图像') 139 | plt.show() 140 | 141 | # 保存参数 142 | # 01列表压缩为 int 整数 143 | if not use_params: 144 | A11_0_int = int( 145 | '1' + ''.join(map(lambda x: str(reduce(lambda m, n: str(m)+str(n), x)), A11_0)), 2) 146 | A22_0_int = int( 147 | '1' + ''.join(map(lambda x: str(reduce(lambda m, n: str(m)+str(n), x)), A22_0)), 2) 148 | if not os.path.exists('./params'): 149 | os.mkdir('./params') 150 | np.savez(f'./params/{params_path}', x0=x0, u1=u1, y0=y0, 151 | u2=u2, a1=a1, a2=a2, A11_0=A11_0_int, A22_0=A22_0_int, n_round=n_round) 152 | return encrypt_img_path, E 153 | 154 | 155 | if __name__ == '__main__': 156 | img_path = "./data/rabbit1.jpg" # 图像路径 157 | params = { 158 | 'x0': None, 159 | 'u1': None, 160 | 'y0': None, 161 | 'u2': None, 162 | 'n_round': 1 # 加密轮数 163 | } 164 | encrypt(img_path, **params) 165 | -------------------------------------------------------------------------------- /improvement/images/astesia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/images/astesia.jpg -------------------------------------------------------------------------------- /improvement/images/lena.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/images/lena.png -------------------------------------------------------------------------------- /improvement/images/pvz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/images/pvz.jpg -------------------------------------------------------------------------------- /improvement/images/rabbit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pigeoner/A_novel_bit-level_image_encryption_algorithm_based_on_chaotic_maps/f6b5f9160ebfacf6013e2e5e46d7154c81048fbd/improvement/images/rabbit.jpg -------------------------------------------------------------------------------- /improvement/main.py: -------------------------------------------------------------------------------- 1 | from analysis import * 2 | from encrypt import encrypt 3 | from decrypt import decrypt 4 | import os 5 | img_path_base = "./images/" 6 | 7 | img_name = "lena.png" # 自行修改图片名,默认为 lena 图 8 | 9 | img_path = img_path_base + img_name 10 | 11 | if os.path.exists('result.txt'): 12 | os.remove('result.txt') 13 | if not os.path.exists('params/'): 14 | os.mkdir('params/') 15 | 16 | # 加解密过程及性能分析 17 | with open('result.txt','w', encoding='utf8') as f: 18 | f.write( 19 | """ +---------------------------------+ 20 | | 加解密过程的性能分析 | 21 | +---------------------------------+ 22 | 23 | """) 24 | bifurcation_diagram(0.2, 100, 10) # 分岔图 25 | encrypt_img_path, res = encrypt(img_path, show=True) # 加密 26 | decrypt(encrypt_img_path, img_path, show=True) 27 | histogram(img_path, encrypt_img_path) # 直方图 28 | correlation(img_path, encrypt_img_path) # 相关性 29 | entropy(img_path, encrypt_img_path) # 信息熵 30 | encrypt_sensitivity(img_path) # 加密敏感度 31 | decrypt_sensitivity(img_path, encrypt_img_path) # 解密敏感度 32 | differencial(img_path) # 差分攻击,NPCR和UACI 33 | 34 | # 100次相关性分析和差分攻击分析 35 | with open('result.txt','a+', encoding='utf8') as f: 36 | f.write(""" 37 | 38 | +---------------------------------+ 39 | | 100次相关性分析和差分攻击分析 | 40 | +---------------------------------+ 41 | 42 | """) 43 | correlation(img_path, encrypt_img_path, is_mean=True, ntimes=100) # 100次相关性分析结果平均值 44 | differencial(img_path, ntimes=100) # 100次差分攻击结果平均值 45 | 46 | print('程序执行完毕,结果已保存至result.txt') -------------------------------------------------------------------------------- /improvement/requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==3.7.1 2 | numpy==1.24.2 3 | opencv_python==4.7.0.72 4 | -------------------------------------------------------------------------------- /improvement/result.txt: -------------------------------------------------------------------------------- 1 | +---------------------------------+ 2 | | 加解密过程的性能分析 | 3 | +---------------------------------+ 4 | 5 | =======原始图像的各方向的相关系数======= 6 | 通道 Horizontal Vertical Diagonal 7 | R 0.9392 0.9687 0.9024 8 | G 0.9075 0.9439 0.8756 9 | B 0.8991 0.9356 0.8702 10 | 11 | =======加密图像的各方向的相关系数======= 12 | 通道 Horizontal Vertical Diagonal 13 | R 0.0234 0.0420 -0.0096 14 | G -0.0144 0.0076 0.0015 15 | B -0.0075 -0.0095 -0.0041 16 | 17 | ====原图像信息熵==== 18 | 通道R: 7.0345 19 | 通道G: 7.3485 20 | 通道B: 6.9985 21 | 22 | ===加密图像信息熵=== 23 | 通道R: 7.9974 24 | 通道G: 7.9972 25 | 通道B: 7.9973 26 | 27 | ========NPCR======== 28 | Red : 99.6536% 29 | Green: 99.6506% 30 | Blue : 99.5773% 31 | 32 | ========UACI======== 33 | Red : 33.6691% 34 | Green: 33.5097% 35 | Blue : 33.5444% 36 | 37 | 38 | 39 | +---------------------------------+ 40 | | 100次相关性分析和差分攻击分析 | 41 | +---------------------------------+ 42 | 43 | =======原始图像的各方向的相关系数======= 44 | 通道 Horizontal Vertical Diagonal 45 | R 0.9385 0.9701 0.9056 46 | G 0.9090 0.9537 0.8830 47 | B 0.8954 0.9354 0.8555 48 | 49 | =======加密图像的各方向的相关系数======= 50 | 通道 Horizontal Vertical Diagonal 51 | R 0.0016 -0.0052 0.0081 52 | G -0.0027 0.0113 -0.0035 53 | B 0.0034 0.0040 -0.0009 54 | 55 | ========NPCR======== 56 | Red : 99.6246% 57 | Green: 99.6368% 58 | Blue : 99.6323% 59 | 60 | ========UACI======== 61 | Red : 33.4701% 62 | Green: 33.5498% 63 | Blue : 33.3755% -------------------------------------------------------------------------------- /improvement/utils.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from numpy import uint8, zeros, sin, pi, cos 3 | from random import uniform 4 | 5 | 6 | def img_bit_decomposition(img): 7 | '''图像的位平面分解''' 8 | m, n = img.shape 9 | r = zeros((8, m, n), dtype=uint8) 10 | for i in range(8): 11 | r[i, :, :] = cv2.bitwise_and(img, 2**i) 12 | mask = r[i, :, :] > 0 13 | r[i, mask] = 1 14 | return r 15 | 16 | 17 | def PWLCM(x0, h, u, num): 18 | '''生成混沌映射序列 19 | x0: 初始值 20 | h: 控制参数 21 | num: 生成序列的长度 22 | ''' 23 | pwlcm = [0] * num 24 | pwlcm[0] = x0 25 | for i in range(1, num): 26 | xn = pwlcm[i - 1] 27 | if xn > 0 and xn < h: 28 | pwlcm[i] = (xn/h+u*sin(u*(pi*xn))) % 1 29 | elif xn >= h and xn < 0.5: 30 | pwlcm[i] = ((xn-h)/(0.5-h)+u*sin(u*(pi*xn))) % 1 31 | elif xn >= 0.5 and xn < 1 - h: 32 | pwlcm[i] = ((1-xn-h)/(0.5-h)+u*sin(u*(pi*(1-xn)))) % 1 33 | elif xn >= 1 - h and xn < 1: 34 | pwlcm[i] = ((1-xn)/h+u*sin(u*(pi*(1-xn)))) % 1 35 | else: 36 | raise ValueError("xi must be in [0, 1]") 37 | return pwlcm 38 | --------------------------------------------------------------------------------