基于Python的图像信息隐藏与LSB隐写算法毕业设计解析
发布时间:2026/9/10 15:17:58 锦皓数字建站

简介这份毕业设计项目资料面向计算机相关专业学生围绕Python图像信息隐藏技术提供可运行源码、MySQL数据库及说明文档适合毕业设计选题、课程设计参考以及图像隐写算法入门实践。系统采用Python和MySQL开发内容覆盖信息隐藏基本模型、图像隐藏性能指标、静止图像数据隐藏技术及系统搭建过程并展示了网站登录注册、首页、新增图像隐藏、用户管理等核心模块的实现效果。压缩包大小约39.21MB包含源码、数据库与说明文档目录结构清晰便于直接部署或进行功能扩展。目前已有282人学习说明文档按照第2章综述、第3章算法实践分析与系统实现、第4章总结展望的顺序展开层层递进既能帮助理解隐写技术原理也能为毕业设计论文撰写和系统二次开发提供实用的参照与支撑。1. 图像信息隐藏Python毕业设计要解决的核心问题图像信息隐藏通俗讲就是把一段秘密信息嵌入到一张正常图像中让外人看不出图被改过。它和加密不同加密产出乱码隐藏让信息“消失”在像素里。这项技术用于版权水印、隐私标记、防伪溯源也是毕业设计里视觉反馈明显、算法可扩展、代码量可控的好题目。用Python做它优先能借助Pillow、NumPy、PyCryptodome等库再配合SQLite存储记录就能组成完整系统。这篇文章会按实际带项目的顺序从算法选型、数据库设计、参数调优到文档写作带你把它做成一个能通过答辩的毕设。2. LSB隐写算法与Python最小实现从像素位到可运行代码2.1 为什么LSB是入门首选原理与选型理由LSBLeast Significant Bit是图像隐写里最基础也最好解释的一块。数字图像里每个像素有R、G、B三个分量每个分量的值在0到255之间。人眼对颜色的小幅变化很不敏感尤其对亮度较低的位。把每个字节的最低位第0位替换成秘密信息的位人眼几乎分辨不出差别。但从数学上讲每个像素最多能藏3比特一张1024×768的图能藏约288KB的信息足够藏一段长文本。常见做法里LSB之后是DCT和DWT。DCT离散余弦变换适合JPEG压缩场景水印嵌在频域系数上抗压缩能力强DWT离散小波变换多分辨率特性更好但实现复杂、需要引入变换库。我做毕设选了LSB为主、再加一层AES加密作为进阶点原因很简单LSB能用手从头实现代码好答辩而加密部分可以单独写一个模块难度梯度清晰。下表是三种算法的对比算法容量鲁棒性实现难度适合载体LSB高约1/8载体大小低易被压缩破坏低PNG、BMPDCT中中可抗JPEG有损压缩中JPEGDWT中中高高通用实际选型时如果你的毕设要求里有“抗JPEG压缩”或“数字水印”的字眼建议做DCT如果只要求“信息隐藏”和“提取恢复”LSB就够了。后面几章我会按LSB加数据库的方式展开DCT的思路差别主要在嵌入域代码框架是一致的。2.2 一个可运行的Python LSB嵌入示例在写代码前先确认你的python环境。我一般用Python 3.8以上版本配合Pillow和NumPy。如果还没装执行pip install pillow numpy就能完成基础依赖。下面这段代码是最小化的LSB嵌入示例它把一串字节隐藏进一张PNG图片的蓝色通道最低位import numpy as np from PIL import Image def embed_lsb(image_path, secret_bytes, output_path): # 读取图片并转为RGB模式保证通道数一致 img Image.open(image_path).convert(RGB) arr np.array(img) height, width, channels arr.shape # 把秘密信息转为二进制位串并拼接结束符便于提取时知道在哪停 bits .join(format(byte, 08b) for byte in secret_bytes) bits 1111111111111110 # 结束标记连续的1和0极少在文本中出现 flat arr[:, :, 2].flatten() # 取蓝色通道一维展开 if len(bits) len(flat): raise ValueError(秘密信息太长请换一张更大的图片) for i, bit in enumerate(bits): # 最低位清零后按位或写入当前bit if bit 1: flat[i] flat[i] | 1 else: flat[i] flat[i] 0xFE # 清除最低位 arr[:, :, 2] flat.reshape((height, width)) Image.fromarray(arr).save(output_path, formatPNG) return len(bits) // 8这段代码的关键逻辑在最后几行flat[i] flat[i] | 1和flat[i] flat[i] 0xFE前者强制把最低位变成1后者把最低位清0。这样每次只改像素值的最低位最多产生±1的颜色变化肉眼根本察觉不到。参数方面bits 1111111111111110是结束标记你也可以在提取方单独传一个长度变量但你做毕设时用标记法更方便演示。还需要注意原始秘密字节要先经过format(byte, 08b)转成8位二进制因为一个字节必须是8位否则位串长度会错位。2.3 提取代码与边界条件有嵌入就得有提取提取是嵌入的逆过程。下面是我的提取函数def extract_lsb(image_path): img Image.open(image_path).convert(RGB) arr np.array(img) flat arr[:, :, 2].flatten() bits for pixel in flat: bits str(pixel 1) # 与1做与运算取出最低位 # 以16个比特为一组查找结束标记 marker 1111111111111110 idx bits.find(marker) if idx -1: raise ValueError(未找到结束标记图片可能未隐藏信息或已经被修改) data_bits bits[:idx] # 每8位一组转回字节 secret_bytes bytes(int(data_bits[i:i8], 2) for i in range(0, len(data_bits), 8)) return secret_bytes提取时的第一个坑是位顺序嵌入时是逐位写入提取时也必须按同一顺序读否则恢复出的字节全是乱的。第二个坑是图片格式提取方必须拿到PNG或BMP这类无损格式如果中间经过JPEG压缩蓝色通道的最低位会被压缩算法改写结束标记找不到是常有的事。我在给学弟学妹调试时见过最多的错误是他们嵌完信息后用微信传给另一台电脑微信默认把图片转成JPEG结果提取直接失败。所以提取前一定要确认图像数据是原始的没有经过任何有损缩放或格式转换。这一章里我们已经有了可运行的嵌入和提取代码接下来要把它放进一个正经项目里这就得引入数据库了。3. 毕业设计项目结构数据库表设计与Python模块划分3.1 数据库为什么出现在这个题目里需求和选型很多同学拿到题目会问“图像隐写不是算法题吗为什么要数据库”这是毕设出题人的典型思路算法题也要能看出软件工程能力。数据库在这里不是核心算法而是工程化的辅助模块。常见做法是记录三类数据用户信息、嵌入历史、载体图片元数据。比如你每次嵌入了一段信息把图片路径、秘密信息长度、嵌入时间、操作人写进数据库之后做历史查询、权限控制、审计追踪都方便也能在答辩时展示你对数据库设计的理解。从源码工程角度看数据库还能让图像算法模块和业务逻辑解耦。选型上优先推荐SQLite。原因有三个第一它是Python标准库的一部分不需要单独安装数据库服务老师看代码和演示时跑一次就能通第二文件型数据库方便打包提交不会出现“换台电脑连不上MySQL”的问题第三SQLite对并发要求不高毕设场景完全够用。如果你的项目要同时支持Web端访问或多人操作再换成MySQL不迟连接方式我下面会提。3.2 表结构设计三张核心表及其字段设计数据库表是毕业设计里容易被扣分的地方标准要求是“三范式、主外键清晰、字段类型合理”。针对这个题目我一般会设计三张表结构如下-- 用户表存放登录用户的基本信息 CREATE TABLE user ( user_id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, -- 存储哈希值不存明文 role TEXT DEFAULT normal, -- 角色admin / normal created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 图片记录表存储载体图片与隐藏图片的文件信息 CREATE TABLE image_record ( record_id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, cover_path TEXT NOT NULL, -- 载体图片路径 output_path TEXT, -- 嵌入后图片路径 secret_length INTEGER, -- 秘密信息的字节数 algorithm TEXT DEFAULT LSB, -- 使用的算法 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES user(user_id) ); -- 嵌入日志表记录每次嵌入与提取操作 CREATE TABLE embedding_log ( log_id INTEGER PRIMARY KEY AUTOINCREMENT, record_id INTEGER NOT NULL, operation TEXT, -- embed / extract status TEXT DEFAULT success, -- success / failed message TEXT, -- 失败原因或备注 FOREIGN KEY (record_id) REFERENCES image_record(record_id) );这三张表的字段都经过了删减保留了展示逻辑的关键项。password_hash用哈希值存储是安全课程里强调过的点secret_length存秘密信息长度方便提取时不依赖结束标记这是给扩展功能留的口子embedding_log则让项目变成可审计的系统。外键关系在SQLite里默认不强制但建表时写清楚能让老师看出你的基本功。3.3 Python中的数据库操作连接、插入与查询示例数据库操作在Python里用标准库sqlite3就能完成。注意两点第一写完连接代码后要commit()否则数据不会真正落盘第二所有SQL参数必须用?占位符防止拼接注入。下面是一段典型的插入代码import sqlite3 def add_user(username, password_hash): conn sqlite3.connect(stego.db) cursor conn.cursor() try: cursor.execute( INSERT INTO user (username, password_hash) VALUES (?, ?), (username, password_hash) ) conn.commit() return cursor.lastrowid # 返回新插入记录的ID except sqlite3.IntegrityError: # 用户名重复时触发唯一约束 print(用户名已存在插入失败) return None finally: conn.close()这里的cursor.execute第二参数是元组SQL中的?会依次被替换成username和password_hash。lastrowid可以拿到刚插入的主键但要注意在commit()之后调用。查询历史的代码也类似只需要把INSERT换成SELECT并用fetchall()取结果。我在项目源码里把数据库操作独立成一个database.py模块只暴露init_db()、add_user()、insert_record()等方法。这样图像隐写模块只关心图片数据不关心数据库细节源码结构清晰答辩时也好讲。下一章就把这两部分拼起来组成完整的嵌入与提取流程。4. 嵌入与提取全流程Python代码实现、参数调优与排错4.1 完整流程设计从输入到落库把第二章的算法和第三章的数据库拼起来毕设的核心功能才算完整。我在做这类系统时会把一条嵌入操作拆成五个步骤接收用户上传的载体图片和秘密信息文件对秘密信息做AES加密可选增强安全性调用LSB嵌入函数生成隐写图片把图片路径、长度、算法等信息写入数据库返回带校验码的结果前端展示前后对比。其中第2步是可选的但它能明显提升课题档次。而且PyCryptodome库安装简单核心加密代码不到十行。在运行下面的代码前需要先执行pip install pycryptodome否则from Crypto.Cipher import AES会直接报错。下面给出加密预处理和完整嵌入控制流的示例。4.2 核心代码带加密控制流的完整实现from Crypto.Cipher import AES import hashlib import os import database # 上一章的自定义模块 def aes_encrypt(data: bytes, key: str) - bytes: # 用SHA256把任意长度密码转成32字节AES密钥 key_bytes hashlib.sha256(key.encode(utf-8)).digest() cipher AES.new(key_bytes, AES.MODE_EAX) nonce cipher.nonce ciphertext, tag cipher.encrypt_and_digest(data) # 返回nonce、tag、密文三者的拼接后续解密时需要分开 return nonce tag ciphertext def embed_with_record(cover_path, secret_data, password, user_id): # 对秘密数据加密 encrypted aes_encrypt(secret_data, password) # 调用第二章的embed_lsb函数这里假设它在lsb.py里 output_path output_ os.path.basename(cover_path) byte_len embed_lsb(cover_path, encrypted, output_path) # 写入数据库 record_id database.insert_record( user_iduser_id, cover_pathcover_path, output_pathoutput_path, secret_lengthbyte_len, algorithmLSBAES ) return record_id, output_path这段代码的关键参数有三个data是原始秘密字节key是用户输入的口令cover_path是载体图片路径。aes_encrypt里encrypt_and_digest会同时生成密文和认证标签tag用于解密时校验数据完整性防止图像被篡改后提取出错误信息。解密函数要注意按顺序拆开nonce、tag和ciphertext我见过同学把三块数据当成一个整体直接丢给AES结果解密失败。提示nonce、tag和ciphertext必须一起保存否则解密时无法还原原始数据。4.3 参数调优图片格式、位平面与嵌入密度参数调优是毕设答辩里最能让老师觉得你“有工程经验”的部分。第一个参数是载体格式。LSB只能配合PNG、BMP这类无损格式如果载体是JPEG请先转成PNG再嵌入否则嵌入后的图片保存为JPEG会瞬间破坏所有低位数据。第二个参数是选择哪个通道嵌入。我的默认做法是只嵌入蓝色通道因为人眼对蓝色变化最不敏感同等嵌入量下PSNR略高如果你追求容量可以三个通道全用但隐藏痕迹也会明显一些。第三个参数是嵌入密度即每个字节的多少位被用来写信息。上面的代码只用了最低位容量是1/8如果你把每个字节的低二位都用来写信息容量翻倍但图像质量会下降。下面是一组对比嵌入位单像素容量图像失真程度适用场景1位3比特几乎无感知默认推荐2位6比特轻微噪点高容量需求4位12比特可见条纹不推荐作为毕设主方案实现二位的嵌入只需要把写入和读取的最低有效位数量从1改成2读取时用pixel 0x03写入时先清掉低二位再按位或。我建议在主代码里加一个n_lsb参数默认2因为在答辩演示时可以现场调这个参数让老师看到容量与画质的权衡。4.4 常见排错提取失败时的排查顺序我做这个题目到验收阶段遇到过最典型的四类问题图片格式不对嵌入后保存为JPG提取时结束标记找不到。解决强制用PNG保存。中文乱码秘密信息是中文直接调用encode(utf-8)没问题但提取后要用同一个编码decode(utf-8)。我见过同学用GBK编码换台电脑就乱。位宽不一致嵌入时按2位写提取时用1位读所有低位都错位。解决把n_lsb写进图片记录表提取时读取该参数。数据库写入失败SQLite的database is locked错误多半是连接没有关闭或多个线程共用一个连接。解决每次操作独立连接加conn.close()。排查时可以按“先看图片是否无损 → 再看位宽参数 → 再看编码 → 最后看数据库字段”的顺序来。这一章的内容已经足以支撑一个完整功能下一章说说怎么验证成果和写说明文档。5. 验证隐藏效果与撰写说明文档的四个关键步骤5.1 用PSNR量化隐藏不可见性PSNR峰值信噪比是衡量隐写后图像质量最常用的指标。它比较原始图和隐写图每个像素的差异数值越高说明画质损失越小通常来讲超过30dB肉眼就难以分辨。可以用NumPy算出两图的均方误差再套公式。三十行内能写完import numpy as np from PIL import Image def psnr(img1_path, img2_path): img1 np.array(Image.open(img1_path).convert(RGB), dtypenp.float64) img2 np.array(Image.open(img2_path).convert(RGB), dtypenp.float64) mse np.mean((img1 - img2) ** 2) if mse 0: return float(inf) return 10 * np.log10(255**2 / mse)在文档中把原始图、隐写图和直方图对比放在一起再给出PSNR数值就能直观证明隐藏的效果。用该函数对比同一张图在1位、2位嵌入下的PSNR你会看到数值从约45dB降到约35dB这个数据可以直接写进测试报告。5.2 鲁棒性测试与常见坑毕设里另一个加分的验证是做鲁棒性测试把隐写图做旋转、加噪声、重新缩放然后看能不能提取出信息。LSB对这类操作几乎零鲁棒性但你可以把测试结果作为“算法局限性”写进文档然后提出改进方向比如换成DCT。注意做测试时不要用手机拍屏幕那种照片的光学畸变和摩尔纹不属于常规信号处理范围做了只会得到一堆没有意义的失败数据。5.3 说明文档的结构建议说明文档是毕设评分的重要部分我推荐的顺序是需求分析强调系统要解决什么问题、总体设计模块划分和数据库ER图、详细设计LSB嵌入流程、AES加解密流程、测试报告功能测试、性能测试、鲁棒性测试、使用手册从python安装、依赖安装到启动命令。其中“使用手册”部分要写出实际可复制的命令比如python main.py --mode embed --cover cover.png --secret secret.txt --password 123456而不是只写“运行程序”。5.4 答辩演示时的一个技巧最后留一个具体技巧答辩时准备一个debug.sh或run_test.py用三百行的自动化脚本把“嵌入→提取→比对→显示PSNR”跑通现场演示时不用点鼠标一句python run_test.py就能输出完整日志。这比临时打开控制台敲命令要稳得多也能体现你对工程质量的理解。把脚本和源码一起提交到Git仓库说明文档里附上运行结果截图整个毕设的可信度就会上一个台阶。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。