⌈ 传知代码 ⌋ 基于扩散模型的无载体图像隐写术

💛前情提要💛

本文是传知代码平台中的相关前沿知识与技术的分享~

接下来我们即将进入一个全新的空间,对技术有一个全新的视角~

本文所涉及所有资源均在传知代码平台可获取

以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦!!!

以下内容干货满满,跟上步伐吧~


📌导航小助手📌

  • 💡本章重点
  • 🍞一. 概述
  • 🍞二. 论文思路
  • 🍞三. 方法原理
  • 🍞四. 实验过程
  • 🍞五. 使用方式
  • 🫓总结


💡本章重点

  • 基于扩散模型的无载体图像隐写术

🍞一. 概述

当前的图像隐写技术主要集中在基于载体图(cover image)的方法上,这些方法通常存在泄露隐藏图(secret image)的风险和对退化容器图(container image)不鲁棒的风险。受到最近扩散模型(diffusion models)发展的启发,作者发现了扩散模型的两个特性,即无需训练即可实现两张图像之间的转换以及对噪声数据有天然的鲁棒性。这些特性可以用来增强图像隐写任务中的安全性和鲁棒性。这是首次将扩散模型引入图像隐写领域的尝试。与基于载体图的图像隐写方法相比,作者提出的CRoSS框架在可控性、鲁棒性和安全性方面具有明显优势。


🍞二. 论文思路

💡技术要点:

本文将无载体图图像隐写任务表示为三个图像和两个过程组成:这三个图像指的是秘密图像xsec、容器图像xcont和揭示图像xrev,而这两个过程是隐藏过程和揭示过程。秘密图像xsec是我们想要隐藏的图像,并通过隐藏过程隐藏在容器图像xcont中。通过互联网传输后,容器图像xcont可能会退化,得到容器图像的退化图像x’cont,我们通过揭示过程从中提取显示的图像xrev。根据上述定义,我们可以将隐藏过程视为秘密图像xsec和容器图像xcont之间的翻译,将揭示过程视为隐藏过程的反向过程。

在这里插入图片描述
本文使用条件扩散模型来将秘密图像进行加密使之转换为容器图像,并使用DDIM反转来实现图像分布和噪声分布之间的双向转换,允许可逆图像转换,这样的方法使得容器图像能够成功被还原为秘密图像。

在这里插入图片描述


🍞三. 方法原理

1、CRoSS的隐藏过程
(1)原理:使用 DDIM 的前后向过程对秘密图像进行处理,得到容器图像。首先,使用一个私钥作为条件,对秘密图像进行加噪(前向过程),接着使用一个公钥作为条件,进行去噪(后向过程),这样就可以生成一个可以在互联网上传播的容器图像了。私钥用于描述秘密图像中的内容,而公钥用于控制容器图像中的内容。

在这里插入图片描述
如上图所示,prompt1是私钥,prompt2是公钥。并列的三幅图中,第一幅是秘密图像,第二幅是容器图像,第三幅是揭示图像。

(2)算法思路
输入:将被隐藏的秘密图像xsec,带有噪声估计器εθ的预训练条件扩散模型,采样时间步数T,以及作为私钥和公钥的两个不同条件kpri和kpub。
输出:用于隐藏秘密图像xsec的容器图像xcont。

在这里插入图片描述
2、CRoss的揭示过程
(1)原理:在揭示阶段,假设容器图像已通过互联网传输,并可能已损坏为x’cont,接收器需要使用相同的条件扩散模型和相应提示词,通过相同的正向和后向过程的逆过程将其显示回秘密图像。在整个无载体图像隐写过程中,我们不专门为图像隐写任务训练或微调扩散模型,而是依靠DDIM反转保证的固有可逆图像翻译。

(2)算法思路
输入:通过互联网传输的容器图像x’cont(可能从xcont退化),带有噪声估计器εθ的预训练条件扩散模型,采样时间步数T,私钥kpri和公钥kpub。
输出:从容器图像中揭示出的图像xrev。


🍞四. 实验过程

1、实验设置
实验选择了稳定Stable Diffusion v1.5作为条件扩散模型,并使用了确定性DDIM采样算法。由秘密图像生成噪声图和由噪声图生成容器图各自都由50步组成。为了实现可逆图像转换,我们将稳定扩散的引导刻度设置为1。对于作为私钥和公钥的给定条件,我们有三个选项:prompts(提示词)、ControlNets条件(depth maps, scribbles, segmentation maps)和LoRAs。

2、数据准备
实验收集了总共260张图像,并生成专门为无载体图像隐写术量身定制的提示词,称为Stego260。实验将数据集分为三类,即人类、动物和一般物体(如建筑、植物、食物、家具等)。数据集中的图像来自公开的数据集和谷歌搜索引擎。为了生成提示密钥,我们使用BLIP生成私钥,并使用ChatGPT或人工调整来执行语义修改并批量生成公钥。
下图为使用ChatGPT生成公钥的过程。

在这里插入图片描述
3、核心代码

class ODESolve:

    def __init__(self, model, NUM_DDIM_STEPS=50):
        scheduler = DDIMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", clip_sample=False,
                                  set_alpha_to_one=False)
        self.model = model
        self.num_ddim_steps = NUM_DDIM_STEPS
        self.tokenizer = self.model.tokenizer
        self.model.scheduler.set_timesteps(self.num_ddim_steps)
        self.prompt = None
        self.context = None

    def prev_step(self, model_output: Union[torch.FloatTensor, np.ndarray], timestep: int, sample: Union[torch.FloatTensor, np.ndarray]):
        prev_timestep = timestep - self.scheduler.config.num_train_timesteps // self.scheduler.num_inference_steps
        alpha_prod_t = self.scheduler.alphas_cumprod[timestep]
        alpha_prod_t_prev = self.scheduler.alphas_cumprod[prev_timestep] if prev_timestep >= 0 else self.scheduler.final_alpha_cumprod
        beta_prod_t = 1 - alpha_prod_t
        pred_original_sample = (sample - beta_prod_t ** 0.5 * model_output) / alpha_prod_t ** 0.5
        pred_sample_direction = (1 - alpha_prod_t_prev) ** 0.5 * model_output
        prev_sample = alpha_prod_t_prev ** 0.5 * pred_original_sample + pred_sample_direction
        return prev_sample
    
    def next_step(self, model_output: Union[torch.FloatTensor, np.ndarray], timestep: int, sample: Union[torch.FloatTensor, np.ndarray]):
        timestep, next_timestep = min(timestep - self.scheduler.config.num_train_timesteps // self.scheduler.num_inference_steps, 999), timestep
        alpha_prod_t = self.scheduler.alphas_cumprod[timestep] if timestep >= 0 else self.scheduler.final_alpha_cumprod
        alpha_prod_t_next = self.scheduler.alphas_cumprod[next_timestep]
        beta_prod_t = 1 - alpha_prod_t
        next_original_sample = (sample - beta_prod_t ** 0.5 * model_output) / alpha_prod_t ** 0.5
        next_sample_direction = (1 - alpha_prod_t_next) ** 0.5 * model_output
        next_sample = alpha_prod_t_next ** 0.5 * next_original_sample + next_sample_direction
        return next_sample
    
    def get_noise_pred_single(self, latents, t, context):
        noise_pred = self.model.unet(latents, t, context)["sample"]
        return noise_pred

    def get_noise_pred(self, latents, t, is_forward=True, context=None):
        if context is None:
            context = self.context
        guidance_scale = GUIDANCE_SCALE
        uncond_embeddings, cond_embeddings = context.chunk(2)
        noise_pred_uncond = self.model.unet(latents, t, uncond_embeddings)["sample"]
        noise_prediction_text = self.model.unet(latents, t, cond_embeddings)["sample"]
        noise_pred = noise_pred_uncond + guidance_scale * (noise_prediction_text - noise_pred_uncond)
        if is_forward:
            latents = self.next_step(noise_pred, t, latents)
        else:
            latents = self.prev_step(noise_pred, t, latents)
        return latents

    @torch.no_grad()
    def latent2image(self, latents, return_type='np'):
        latents = 1 / 0.18215 * latents.detach()
        image = self.model.vae.decode(latents)['sample']
        if return_type == 'np':
            image = (image / 2 + 0.5).clamp(0, 1)
            image = image.cpu().permute(0, 2, 3, 1).numpy()[0]
            image = (image * 255).astype(np.uint8)
        return image

    @torch.no_grad()
    def image2latent(self, image):
        with torch.no_grad():
            if type(image) is Image:
                image = np.array(image)
            if type(image) is torch.Tensor and image.dim() == 4:
                latents = image
            else:
                image = torch.from_numpy(image).float() / 127.5 - 1
                image = image.permute(2, 0, 1).unsqueeze(0).to(device)
                latents = self.model.vae.encode(image)['latent_dist'].mean
                latents = latents * 0.18215
        return latents

    @torch.no_grad()
    def init_prompt(self, prompt: str):
        uncond_input = self.model.tokenizer(
            [""], padding="max_length", max_length=self.model.tokenizer.model_max_length,
            return_tensors="pt"
        )
        uncond_embeddings = self.model.text_encoder(uncond_input.input_ids.to(self.model.device))[0]
        text_input = self.model.tokenizer(
            [prompt],
            padding="max_length",
            max_length=self.model.tokenizer.model_max_length,
            truncation=True,
            return_tensors="pt",
        )
        text_embeddings = self.model.text_encoder(text_input.input_ids.to(self.model.device))[0]
        self.context = torch.cat([uncond_embeddings, text_embeddings])
        self.prompt = prompt

    @torch.no_grad()
    def get_text_embeddings(self, prompt: str):
        text_input = self.model.tokenizer(
            [prompt],
            padding="max_length",
            max_length=self.model.tokenizer.model_max_length,
            truncation=True,
            return_tensors="pt",
        )
        text_embeddings = self.model.text_encoder(text_input.input_ids.to(self.model.device))[0]
        return text_embeddings

4、实验结果

运行ReadMe文件中的以下代码,快速运行代码进行图片加密解密。

python demo.py --image_path ./asserts/1.png --private_key "Effiel tower" --public_key "a tree" --save_path ./output --num_steps 50

成功运行界面如下:

在这里插入图片描述
打开output文件夹,查看实验过程中的三幅图像

在这里插入图片描述
待加密图像:

在这里插入图片描述
容器图像:

在这里插入图片描述
揭示图像:

在这里插入图片描述
可以发现,隐写后的图片自然且清晰度高,不易被察觉到隐藏了秘密图像,揭示图像还原度高,经过网络传输后仍然能够很好地被还原。


🍞五. 使用方式

编译器采用Pycharm,下载好项目代码后,阅读ReadMe文件以及“requirements.txt”。

首先运行ReadMe文件中的以下代码,下载好实验所需的所有库并配置好环境。

pip install -r requirements.txt

然后运行ReadMe文件中的以下代码,快速运行代码进行图片加密解密。

python demo.py --image_path ./asserts/1.png --private_key "Effiel tower" --public_key "a tree" --save_path ./output --num_steps 50

上述image_path后面的参数是要加密图像在设备上的路径,可以根据自己的图片路径进行调整;private_key后面的参数是私钥,根据不同待加密图片的内容自行调整;public_key后面的参数是公钥,根据想要生成的容器图像内容进行调整;save_path后面的参数是加密后的容器图像的保存地址,如果不修改的话每次运行程序都会覆盖前一次的运行结果;num_steps后面的参数是迭代次数,可以根据自己的需要进行调整,一般迭代次数越多效果越好,花费的时间越长。


🫓总结

综上,我们基本了解了“一项全新的技术啦” 🍭 ~~

恭喜你的内功又双叒叕得到了提高!!!

感谢你们的阅读😆

后续还会继续更新💓,欢迎持续关注📌哟~

💫如果有错误❌,欢迎指正呀💫

✨如果觉得收获满满,可以点点赞👍支持一下哟~✨

【传知科技 – 了解更多新知识】

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/642326.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis-Plus笔记

1.MP基础 1.1 MP常见注解 TableName(“指定表明”) TableName("tb_user") // 指定表名 Data NoArgsConstructor AllArgsConstructor Builder public class User {private Long id;private String userName;private String password;private String name;private I…

软件设计师备考 | 案例专题之数据流图 概念与例题

案例分析专题大纲: 数据流图基本概念 基本图形元素:外部实体、加工、数据存储、数据流 数据流:由一组固定成分的数据组成,表示数据的流向。在DFD中,数据流的流向必须经过加工。加工:描述了输入数据流到输出…

Ubuntu22.04虚拟机设置静态IP

虚拟机设置静态IP 按下电脑的 “win”键,在弹出的输入框中输入“控制面板”,选中控制面板 1.选择 “网络和Internet” 2.选择 “网络和共享中心” 3.选择 “更改适配器设置” 4.选择 “VMnet8”,双击打开 5.选择 “属性” 找到 “Internet …

【游戏引擎】Unity动画系统详解

持续更新。。。。。。。。。。。。。。。 【游戏引擎】Unity动画系统详解 Unity动画系统详解简介关键帧动画创建关键帧动画的步骤: Mecanim动画系统Mecanim的关键组件:使用Mecanim创建动画的步骤: 动画控制器动画控制器的高级功能&#xff1a…

AI预测福彩3D采取888=3策略+和值012路一缩定乾坤测试5月25日预测第1弹

上一套算法采用了88723的容差策略,关于容差策略相信大家都比较清楚:容差可以最大限度的保证初始大底中包含中奖号码,然后再通过设置一些杀号条件进行缩水。比如,我对我的各种模型算法近30期的预测结果进行了统计,如果采…

动态代理,反射,注解的复习笔记

1.动态代理的作用 动态代理最主要的用途就是在各种框架中,很方便的在运行期间生成代理类,通过代理类就可以完成AOP、过滤器、拦截器等操作 (注:代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己…

浏览器的一些功能

1.改主页面 点浏览器右上角的三个点也就是一个... 点了设置 你可以在这里改它的颜色 还有页面 一些有意思的网站: sandspiel像素风格游戏 趣味互动游戏:请画一个小人 (webhek.com)​​​​​​ 2018 - makemepulse解压游戏 Layered Water (vlucendo.com)水模…

《计算机网络微课堂》2-2 物理层下面的传输媒体

请大家注意,传输媒体不属于计算机网络体系结构的任何一层,如果非要将它添加到体系结构中,‍‍那只能将其放在物理层之下。 传输媒体可分为两类:一类是导引型传输媒体,‍‍另一类是非导引型传输媒体。 在导引型传输媒体…

测试网0撸大毛 — AI 公链ALIENX推出HAL Testnet活动(含保姆级教程)

近期,OpenAI推出了新一代的GPT-4o让AI再次获得关注。AI硬件销售商英伟达的股价也突破1000美元,市值攀升到2.6万亿美元。AI继续影响到我们生活的方方面面。 在加密货币行业,市场行情也逐渐走出低谷。以太坊现货ETF被批准,为整个市场…

小程序主体变更是通过迁移吗?是需要2个小程序吗?

小程序迁移变更主体有什么作用?好多朋友都想做小程序迁移变更主体,但是又不太清楚具体有啥用,今天我就来详细说说。首先,小程序迁移变更主体最重要的作用就是可以修改主体。比如你的小程序原来是 A 公司的,现在 A 公司…

一、Elasticsearch介绍与部署

目录 一、什么是Elasticsearch 二、安装Elasticsearch 三、配置es 四、启动es 1、下载安装elasticsearch的插件head 2、在浏览器,加载扩展程序 3、运行扩展程序 4、输入es地址就可以了 五、Elasticsearch 创建、查看、删除索引、创建、查看、修改、删除文档…

React 学习-10-ant design pro项目搭建

1.确保npm淘宝镜像为最新:npm config set registry https://registry.npmmirror.com 2.npm i ant-design/pro-cli -g 3.pro create my-app(确保git已安装,可远程拉代码) 4. 安装依赖,启动项目 npm run start

安卓玩机搞机技巧综合资源----自己手机制作证件照的几种方法 免费制作证件照

接上篇 安卓玩机搞机技巧综合资源------如何提取手机分区 小米机型代码分享等等 【一】 安卓玩机搞机技巧综合资源------开机英文提示解决dm-verity corruption your device is corrupt. 设备内部报错 AB分区等等【二】 安卓玩机搞机技巧综合资源------EROFS分区格式 小米红…

微信小程序源码-基于Java后端的会议发布与预约系统毕业设计(附源码+演示录像+LW)

大家好!我是程序员一帆,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设…

从cuda到cudnn到pytorch

一、预配版本信息 1、cuda12.1.1 2、cudnn8.9.7 3、pytorch2.2.0 二、引用 深度学习之环境配置:【CUDA 12.1.1cuDNN 8.9.1】最新安装教程记录 -- 20240429_torch 1.12.0对应torchvision-CSDN博客 补充: cuda历史版本索引: NVIDIA Dev…

【C语言深度解剖】(15):动态内存管理和柔性数组

🤡博客主页:醉竺 🥰本文专栏:《C语言深度解剖》 😻欢迎关注:感谢大家的点赞评论关注,祝您学有所成! ✨✨💜💛想要学习更多C语言深度解剖点击专栏链接查看&…

IDEA 将多个微服务Springboot项目Application启动类添加到services标签,统一启动、关闭服务

IDEA 将多个微服务Springboot项目Application启动类添加到services标签,统一启动、关闭服务 首先在Views > Tool Windows > Services 添加services窗口 点击services窗口,首次需要添加配置类型,我们选择Springboot 默认按照运行状态分…

【竞技宝】英超:足总杯踢完解雇腾帅,曼联管理层心意已决

根据知名媒体《卫报》的报道,足总杯之后曼联将会 解雇滕哈格,哪怕他率领曼联队能够击败强大的曼城夺冠,也无法改变他将下课的事实。因为曼联本赛季的联赛排名只有第8名,已经来到了近30年来的最差成绩,这种情况下滕哈格与曼联的缘分似乎将被终结。 滕哈格上赛季成为曼联的主帅,由…

2024洗地机哪个牌子好?洗地机十大品牌

洗地机在不同家庭环境中都能发挥其独特的优势,无论是大面积的地板还是狭小的角落,都能轻松应对。 对于有孩子或宠物的家庭,地面上经常会有各种杂物和污渍,洗地机强大的吸力和深度清洁功能,可以迅速清理掉这些脏东西&a…

SpringCloud的Config配置中心,为什么要分Server服务端和Client客户端?

SpringCloud的Config配置中心,为什么要分Server服务端和Client客户端? 在SpringCloud的Config配置中心中分了Server服务端和Client客户端,为什么需要这样分呢?它的思想是所有微服务的配置文件都放到git远程服务器上,让…