图像信息隐藏毕设实战:LSB算法+Flask+Vue+MySQL全链路实现
简介这是一套面向高校计算机相关专业学生与信息安全入门开发者的Python图像信息隐藏技术毕业设计源码包可用于课程设计、毕业设计参考或隐写术学习实践。资源共322个文件压缩包约37.16MB包含36个py源码文件、34个js与22个css前端资源、9个html页面、1个sql数据库脚本及说明文档等前后端与数据库结构完整。项目基于Python 3.6.8、MySQL 5.7与PyCharm开发实现将机密信息嵌入图片载体、肉眼难以察觉的隐蔽传输效果涵盖图像处理算法、信息隐藏逻辑与数据库交互等核心模块。已有78人学习关注。读者可获得完整可复现的工程源码、数据库脚本与项目说明文档便于理解隐写术实现原理、梳理前后端调用流程并在此基础上进行二次开发或撰写论文。1. 图像信息隐藏毕设从一张 PNG 里塞进整份文档到底难在哪图像信息隐藏这个词第一次接触的人容易想歪以为是把文件加密后改个后缀。真做过一轮就明白它要解决的是另一件事把一份数据嵌进一张看起来完全正常的图片里图片照常能打开、照常能发出去而嵌进去的数据还能被完整取回来。毕业设计里常见的形态是「完整前后端 MySQL 说明文档」前端负责上传载体图、输入待隐藏文本、下载含密图后端负责跑嵌入与提取算法MySQL 存任务记录和用户信息。这套东西的价值不在于算法多前沿而在于它把「算法—接口—数据库—前端交互」整条链路串通了是少见的能同时练 Python 图像处理和前后端分离的项目。适合谁适合已经会写 Python 基础语法、想找一个能写进简历、答辩时又讲得出技术细节的选题的人。难点从来不是调库而是嵌入容量、图像质量和提取鲁棒性这三者之间的取舍。2. 先想清楚算法选型LSB、DCT 还是空域加密组合2.1 三种主流方案的能力边界对比图像信息隐藏的算法路线大致分三类选错了后面全是返工。空域 LSB最低有效位替换是最容易上手的把像素值最低位换成数据位人眼几乎看不出差别代码量小适合毕设快速跑通。缺点是抗攻击能力弱图片一旦被重新压缩成 JPEG嵌入的数据基本全丢。DCT离散余弦变换域方法把数据嵌到频域系数里抗压缩能力明显更强但实现复杂、容量小、调试周期长。第三种是组合方案先对秘密数据做加密或置乱再走 LSB 嵌入兼顾安全性和实现难度。对毕业设计来说我一般推荐「LSB 置乱」这条路线。理由是答辩时你能讲清楚两层逻辑置乱解决安全性LSB 解决不可见性工作量可控演示效果直观。如果导师明确要求抗压缩再上 DCT但要预留至少两周调试时间。方案嵌入容量抗压缩实现难度适合场景空域 LSB高约 1/8 图像大小弱低毕设快速落地、演示DCT 域中较强高有抗攻击指标要求LSB 置乱高弱中兼顾安全性与工作量2.2 用 Python 跑通 LSB 嵌入与提取的最小闭环先不碰前后端把算法核心跑通。下面这段代码用 Pillow 和 NumPy 实现最基础的 LSB 嵌入与提取载体图必须是 PNG 这类无损格式JPEG 会在保存时破坏最低位。import numpy as np from PIL import Image def text_to_bits(text): # 把文本转成二进制位串每个字符 8 位 return .join(format(ord(c), 08b) for c in text) def bits_to_text(bits): # 每 8 位还原成一个字符 chars [chr(int(bits[i:i8], 2)) for i in range(0, len(bits), 8)] return .join(chars) def embed(image_path, secret, out_path): img Image.open(image_path).convert(RGB) arr np.array(img) flat arr.flatten() bits text_to_bits(secret) # 用 32 位长度头记录秘密信息长度方便提取时截断 header format(len(bits), 032b) payload header bits if len(payload) len(flat): raise ValueError(载体图容量不足换大图或缩短文本) for i, b in enumerate(payload): # 把每个像素值最低位替换成数据位 flat[i] (flat[i] 0xFE) | int(b) new_arr flat.reshape(arr.shape) Image.fromarray(new_arr.astype(uint8)).save(out_path, PNG) def extract(image_path): img Image.open(image_path).convert(RGB) flat np.array(img).flatten() # 先读 32 位长度头 header_bits .join(str(flat[i] 1) for i in range(32)) length int(header_bits, 2) data_bits .join(str(flat[i] 1) for i in range(32, 32 length)) return bits_to_text(data_bits) if __name__ __main__: embed(cover.png, hello hidden world, stego.png) print(extract(stego.png))逻辑说明text_to_bits把文本逐字符转成 8 位二进制embed先写 32 位长度头再写正文这样提取时才知道该读多少位。flat[i] 0xFE是把最低位清零| int(b)再写入目标位这是 LSB 的核心操作。参数上载体图建议选 512×512 以上的 PNG容量约等于像素总数除以 8 再减去 32 位头一张 512×512 的 RGB 图能藏约 98KB 文本。跑完对比原图和含密图肉眼应该看不出差异用工具算 PSNR 一般在 50dB 以上。3. 前后端分离怎么搭Flask 接口 Vue 页面 MySQL 落库3.1 后端接口设计与数据库表结构算法跑通后把它包成 HTTP 接口。后端用 Flask 足够轻量、上手快毕设场景不需要上重型框架。核心接口三个上传载体图并嵌入、提取含密图、查询历史任务。数据库用 MySQL 存任务记录表结构设计如下。CREATE TABLE hide_task ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(64) NOT NULL, cover_name VARCHAR(255), stego_name VARCHAR(255), secret_len INT DEFAULT 0, status TINYINT DEFAULT 0 COMMENT 0待处理 1成功 2失败, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;status字段用 TINYINT 而不是字符串查询和统计都方便secret_len记录嵌入长度方便前端展示容量占用。注意create_time给默认值 CURRENT_TIMESTAMP插入时不用手动传时间少一个出错点。后端接口用 Flask 实现嵌入接口接收图片和文本调用上一节的embed函数落库后返回含密图下载地址。from flask import Flask, request, jsonify, send_file import pymysql, uuid, os app Flask(__name__) UPLOAD static/upload os.makedirs(UPLOAD, exist_okTrue) def get_conn(): # 每次请求新建连接毕设并发低够用 return pymysql.connect(host127.0.0.1, userroot, passwordyour_pwd, databasestego, charsetutf8mb4) app.route(/api/embed, methods[POST]) def api_embed(): file request.files[image] secret request.form.get(secret, ) if not secret: return jsonify({code: 1, msg: 秘密文本不能为空}) cover_path os.path.join(UPLOAD, f{uuid.uuid4().hex}.png) stego_path os.path.join(UPLOAD, f{uuid.uuid4().hex}_s.png) file.save(cover_path) try: embed(cover_path, secret, stego_path) except ValueError as e: return jsonify({code: 2, msg: str(e)}) conn get_conn() with conn.cursor() as cur: cur.execute( INSERT INTO hide_task(username, cover_name, stego_name, secret_len, status) VALUES(%s,%s,%s,%s,%s), (default, os.path.basename(cover_path), os.path.basename(stego_path), len(secret), 1)) conn.commit() conn.close() return jsonify({code: 0, url: f/static/upload/{os.path.basename(stego_path)}})逻辑说明uuid4().hex生成唯一文件名避免同名覆盖这是血泪经验早期用时间戳在高并发下会撞名。get_conn每次新建连接毕设访问量小够用如果要做连接池可以引 DBUtils但没必要为答辩加复杂度。参数上secret_len存的是字符数不是位数前端展示更直观。3.2 前端上传与提取交互的关键处理前端用 Vue 的话核心是两个页面嵌入页和提取页。嵌入页要处理文件上传和文本输入提取页要能预览含密图并展示提取结果。上传用 FormData注意不要手动设置 Content-Type让浏览器自己带 boundary。// 嵌入请求 async function doEmbed(file, secret) { const fd new FormData(); fd.append(image, file); fd.append(secret, secret); const res await fetch(/api/embed, { method: POST, body: fd }); const data await res.json(); if (data.code ! 0) { alert(data.msg); // 容量不足等错误直接提示 return; } stegoUrl.value data.url; }逻辑说明fetch不设 headers 里的 Content-Type浏览器会自动生成 multipart 边界手动设反而会导致后端解析失败这是前后端联调最常见的翻车点之一。data.code用数字约定状态0 成功、1 参数错、2 容量不足前端按码分支处理。提取页同理把含密图 POST 给/api/extract后端读最低位还原文本返回。4. 避坑与排查那些让毕设卡三天的具体问题4.1 含密图保存成 JPEG 后数据全丢现象嵌入成功提取时返回乱码或空字符串。原因JPEG 是有损压缩保存时会重新量化像素值最低位被改得面目全非。解决载体图和含密图一律用 PNG 或 BMP代码里Image.save显式指定格式别依赖后缀名推断。前端下载时也要保证服务端返回的是 PNG 字节流。4.2 MySQL 连接报 2002 socket 错误现象后端启动后第一次请求就抛error 2002 (HY000): cant connect to local MySQL server through socket。原因MySQL 服务没启动或者 pymysql 连接时 host 写成 localhost 走了 socket 而不是 TCP。解决先确认 MySQL 服务在跑然后把 host 改成127.0.0.1强制走 TCP端口显式写 3306。Linux 下还要检查 MySQL 是否只监听了 socket。4.3 中文文本提取出来是乱码现象嵌入英文正常嵌入中文提取后变成问号或乱码。原因ord(c)对中文返回的是 Unicode 码点可能超过 8 位format(ord(c), 08b)会截断或报错。解决先把文本用 UTF-8 编码成字节串再逐字节转二进制。提取时反向操作把字节串 decode 回 UTF-8。def text_to_bits(text): # 先 UTF-8 编码再逐字节转位中文才不会丢 data text.encode(utf-8) return .join(format(b, 08b) for b in data) def bits_to_text(bits): data bytes(int(bits[i:i8], 2) for i in range(0, len(bits), 8)) return data.decode(utf-8, errorsignore)4.4 容量判断没做导致数组越界现象嵌入长文本时程序崩溃或图片损坏。原因没检查 payload 长度是否超过载体图可容纳的位数直接往 flat 数组里写就越界了。解决嵌入前先算len(payload) len(flat)就抛异常前端捕获后提示用户换大图或缩短文本。这个判断必须放在写位之前不能事后补救。4.5 提取时长度头读错位现象提取结果总是多几个字符或少几个字符。原因长度头用了 32 位但提取时起始偏移写错或者嵌入和提取的位序不一致。解决把长度头的位数定义成常量嵌入和提取共用同一个常量别在两处各写一个数字。位序统一用高位在前format(n, 032b)默认就是高位在前保持一致即可。5. 把鲁棒性验证做扎实PSNR、容量与抗攻击测试毕设答辩最容易被问的就是「你怎么证明藏进去看不出来、取出来不会错」。光说「我试了没问题」不够得拿数据。我一般会做三组验证写进说明文档里答辩时直接翻。第一组是不可见性验证算 PSNR 和 SSIM。PSNR 高于 40dB 人眼基本无法察觉LSB 方案通常能到 50dB 以上。用 scikit-image 两行就能算。from skimage.metrics import peak_signal_noise_ratio as psnr from skimage.metrics import structural_similarity as ssim import numpy as np from PIL import Image cover np.array(Image.open(cover.png).convert(RGB)) stego np.array(Image.open(stego.png).convert(RGB)) print(PSNR:, psnr(cover, stego, data_range255)) print(SSIM:, ssim(cover, stego, channel_axis2, data_range255))第二组是容量测试记录不同尺寸载体图能藏多少字节做成表格放进文档。512×512 的 RGB 图理论容量约 98KB实际留出长度头和安全余量按 90KB 算比较稳。第三组是抗攻击测试这也是 LSB 的软肋要如实写。对含密图做缩放、加噪、裁剪后再提取看数据是否还能还原。结论通常是无损格式下传输没问题一旦经过有损压缩或几何变换就失效。这个结论不丢人反而说明你清楚方案的边界。如果导师要求抗攻击就在这一章引出 DCT 方案的改进方向作为后续工作。一个具体技巧提取接口加一个校验位。在长度头后面再嵌 16 位 CRC 校验码提取时先校验再返回文本校验不过就明确报「数据已损坏」而不是返回一堆乱码让用户猜。这个改动只有几行代码但让整个系统的可靠性上了一个台阶答辩时是个加分项。我自己做这类项目最大的教训是别一上来就搭前后端先把算法在 Jupyter 里跑通、把 PSNR 和容量数据测出来再包接口。顺序反了后面调 bug 时你分不清是算法错还是接口错那才叫真的踩坑。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Agent Harness实战指南:LangGraph生产部署与MCP协议集成

Agent Harness实战指南:LangGraph生产部署与MCP协议集成

1. 这不是“又一个AI框架教程”,而是一份能让你真正跑通Agent Harness的实操手记 Agent Harness这个词最近在技术社区里频繁出现,但很多人搜了一圈发现:要么是零散的GitHub issue讨论,要么是LangGraph官方文档里一笔带过的概念&am…

2026/10/2 15:52:19 阅读更多 →
大模型出海游戏避坑指南:从本地化到合规的五大暗礁

大模型出海游戏避坑指南:从本地化到合规的五大暗礁

过去两年,我几乎每周都在和做出海游戏的人聊大模型。聊得多了以后,我发现大家真正关心的不是排行榜上哪个模型又涨了几分,而是同一件事:我们发往海外的游戏,那些持续烧钱、挨骂、踩坑的风险,到底能不能靠大…

2026/10/1 13:53:32 阅读更多 →
RAW噪声模型与标定:从泊松-高斯到光子转移曲线

RAW噪声模型与标定:从泊松-高斯到光子转移曲线

前阵子帮朋友调试一颗工业相机,他抱怨raw直出的图噪点特别多,换了好几个降噪算法都不理想。我问他有没有先做过噪声标定,他愣了一下。其实这个问题在相机开发里太典型了:raw数据不是“没调好”的图,它是传感器光电转换…

2026/10/1 13:53:32 阅读更多 →

最新新闻

claude code(十):【Claude Code官方最佳实践8️⃣】:用 git worktrees 与 headless mode 搭建多 Claude 工作流程

claude code(十):【Claude Code官方最佳实践8️⃣】:用 git worktrees 与 headless mode 搭建多 Claude 工作流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 16:55:26 阅读更多 →
国产MCU与射频芯片选型指南:如何甄别车规AEC-Q100与工规认证真伪

国产MCU与射频芯片选型指南:如何甄别车规AEC-Q100与工规认证真伪

1. 从一次选型翻车说起:为什么“有认证”和“真能过认证”是两码事去年帮一个做车载域控制器的团队做供应链梳理,他们之前选了一颗标称“工业级”的MCU,样机阶段跑得好好的,结果小批量装车做高低温循环测试,零下40度冷…

2026/10/2 16:55:26 阅读更多 →
烘焙魔法师:用ModelEngine把蛋糕店搬进AI世界,TaoToken统一Key打通智能体编排

烘焙魔法师:用ModelEngine把蛋糕店搬进AI世界,TaoToken统一Key打通智能体编排

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 16:55:26 阅读更多 →
Claude 官方 Harness 发布后,用 TaoToken 统一 Key 理清 LLM 到 Agent 的设施层次

Claude 官方 Harness 发布后,用 TaoToken 统一 Key 理清 LLM 到 Agent 的设施层次

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 16:55:26 阅读更多 →
直启盘光纤中继模块可编程联动公式配置与实战

直启盘光纤中继模块可编程联动公式配置与实战

1. 直启盘光纤/网络中继模块到底解决了什么问题1.1 从一个现场故障说起去年冬天,一个做工业自动化的朋友半夜给我打电话,说他们厂区一条产线上的直启盘突然“失联”了。PLC那边显示通讯超时,现场操作员按了急停,整条线停了四个小时…

2026/10/2 16:55:26 阅读更多 →
LILYGO T-Display P4:嵌入式无线电开发实战指南

LILYGO T-Display P4:嵌入式无线电开发实战指南

1. 项目概述:为什么一块小屏幕能成为无线电爱好者的掌上中枢?“LILYGO T-Display P4 变成掌上无线电瑞士军刀”——这个标题乍看像极了极客圈里常见的夸张修辞,但实打实拆开来看,它背后是一整套嵌入式系统工程的浓缩落地。我第一次…

2026/10/2 16:54:25 阅读更多 →

日新闻

从零搭建AI工程化:模型之外的完整闭环

从零搭建AI工程化:模型之外的完整闭环

先搞清楚一件事:从零开始做 AI 工程化,难的从来不是调模型、写提示词,而是把一套原型 Demo 变成长得像是“正经系统”的东西。你手里可能已经有了能跑通的代码,也可能刚读完一些概念,但真到了要把它变成可维护、可观测…

2026/10/2 0:00:20 阅读更多 →
大模型训练显存估计与混合精度训练实战指南

大模型训练显存估计与混合精度训练实战指南

1. 大模型训练显存估计与混合精度训练详解显存不够用,几乎是每个做大模型训练的人都会撞上的第一堵墙。你可能也经历过:模型代码写完了,数据管道跑通了,满心欢喜地按下训练启动脚本,结果几秒钟后终端弹出一行红字——C…

2026/10/2 0:00:20 阅读更多 →
小样本学习数据集选型指南:27个真正可用的高质量数据集

小样本学习数据集选型指南:27个真正可用的高质量数据集

1. 小样本学习的“弹药库”:为什么你总在找数据集,却总找不到真正能用的? 小样本、数据集——这两个词最近半年在我处理的200多个AI项目咨询里,出现频率排进前三。不是模型调不好,不是代码写不对,而是卡在…

2026/10/2 0:00:20 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 19:40:48 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/1 19:41:40 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/1 20:05:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 5:26:06 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 6:09:11 阅读更多 →