【数据安全-02】AI打假利器数字水印,及java+opencv实现

这篇具有很好参考价值的文章主要介绍了【数据安全-02】AI打假利器数字水印,及java+opencv实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


AIGC 的火爆引燃了数字水印,说实话数字水印并不是一项新的技术,但是这时候某些公司拿出来宣传一下特别应景,相应股票蹭蹭地涨。数字水印是什么呢,顾名思义,和我们在pdf中打的水印作用差不多,起到明确版权、防伪验真的作用。但是不同于传统肉眼可见的水印,数字水印也叫隐藏式水印,能够在人眼几乎无法察觉的情况下将水印信息秘密嵌入到音频、图像或视频中去,除了减少对画质的影响外,有个重要的功能就是保护著作权,使得盗版者无法感知水印存在,让版权的鉴定的溯源变得更轻松。

提到数字水印,有个经典案例经常被提到,阿里巴巴的一名员工擅网页截图外传,造成很大的恶劣影响,结果利用数字水印,很快就定位到这名员工,这名员工还奇怪,发的时候我还特意留意图片上没有水印,怎么就能定位到我呢,可见数字水印的强大,数字水印于无形中发挥着强大作用。

背后的科学奥秘

那么数字水印到底是如何实现的呢,那就不得不提到傅里叶变换,任何函数都可以写成正弦函数之和,用直白的话说就是任何二维空间的波形,都可以用简单的正弦和余弦波叠加而成,傅里叶变换交互式入门这篇文章详细的可视化地介绍了这一原理,并且我们可以随意画一条线看看,是不是可以由多条正弦波叠加而成。

java 数字水印,数据安全,编码,Java,数据安全,数字水印,java,opencv
我们拓展到三维空间,同样的道理,任何凹凸不平的面都可以用正弦平面波叠加而成,如下图所示,看一下大脑的图片,是一张灰度图,每个像素都有灰度值,我们加个坐标,Z轴为灰度值的大小,这样整张图就成为凹凸不平的曲面,那么这张凹凸不平的曲面就可以用多个正弦平面波叠加而成,所以在我们也可以用这些个正弦平面波来存储这张图,简而言之,我们能将图像用频域表示,接下来我们聊聊二维频率域K-SPACE,或者叫傅里叶空间
java 数字水印,数据安全,编码,Java,数据安全,数字水印,java,opencv

对于正弦平面波,可以这样理解,在一个方向上存在一个正弦函数,在法线方向上将其拉伸。前面说过三个参数可以确定一个一维的正弦波。哪几个参数可以确定一个二维的正弦平面波呢?答案是四个,其中三个和一维的情况一样,即频率ω,幅度A,相位φ,但是具有相同这些参数的平面波却可以有不同的方向 n ⃗ \vec{n} n ,如下图所示,频率ω,幅度A,相位φ,都有一样,方向 n ⃗ \vec{n} n ,两个平面波叠加出来的效果。

java 数字水印,数据安全,编码,Java,数据安全,数字水印,java,opencv

类比一维中,幅度和相位可以用一个复数表示,它可以作为我们存储的内容。但是还有两个:一个频率一个方向。这时想到向量是有方向的,也是有长度的。所以我们用一个二维的矩阵的来保存分解之后得到的信息。这个矩阵就是K空间。就是说一个二维矩阵点 (μ ,ν) 代表这个平面波的法向量 n ⃗ \vec{n} n ,这个向量的模 μ 2 + ν 2 \sqrt{\mu^2+\nu^2} μ2+ν2 代表这个平面波的频率ω ,这个点里面保存的内容复数就是此平面波的幅度和相位。

复数(complex number):形如a+bi(a、b均为实数)的数为复数,其中,a被称为实部,b被称为虚部,i为虚数单位。

K空间(K Space):也称傅里叶空间,k空间是寻常空间在傅利叶转换下的对偶空间。“K”代表什么,字母“k”在光学、声学、力学和电磁学领域已经使用了一个多世纪,k=1/ λ \lambda λ,其中 λ \lambda λ表示波长,因此,k是每单位距离的波数或周期数。

java 数字水印,数据安全,编码,Java,数据安全,数字水印,java,opencv

好了讲到这里,我们回归正题,数字水印到底怎么实现,以下就是基本流程,简单步骤如下:

  • 原始图像A经过傅里叶变换得到K空间图像B。
  • 将水印内容写到K空间图像B,得到叠加图像C。
  • 对图像C进行傅里叶逆变换等到添加了数字水印的图像D,该图像D在视觉上和A没什么区别。
    java 数字水印,数据安全,编码,Java,数据安全,数字水印,java,opencv

那么解密流程就很简单了,对D进行一次傅里叶变换就能得到图像C,视觉上就能看到水印了。

java+OpenCV实现

可以参考这篇文章opencv的java-maven-idea开发环境配置进行配置OpenCV的开发环境。我用的opencv的4.6.0版本,下面是数据盲水印的java代码实现,仅供学习参考:

package tools;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import java.util.ArrayList;
import java.util.List;

public class ImgWatermarkUtil {
    private static List<Mat> planes = new ArrayList<Mat>();
    private static List<Mat> allPlanes = new ArrayList<Mat>();
    public static Mat addImageWatermarkWithText(Mat image, String watermarkText){
        Mat complexImage = new Mat();
        Mat padded = splitSrc(image);
        padded.convertTo(padded, CvType.CV_32F);
        planes.add(padded);
        planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
        Core.merge(planes, complexImage);
        Core.dft(complexImage, complexImage);
        Scalar scalar = new Scalar(0, 0, 0);
        Point point = new Point(40, 40);
        Imgproc.putText(complexImage, watermarkText, point, Imgproc.FONT_HERSHEY_DUPLEX, 1D, scalar);
        Core.flip(complexImage, complexImage, -1);
        Imgproc.putText(complexImage, watermarkText, point, Imgproc.FONT_HERSHEY_DUPLEX, 1D, scalar);
        Core.flip(complexImage, complexImage, -1);
        return antitransformImage(complexImage, allPlanes);
    }
    public static Mat getImageKSpace(Mat image){
        Mat complexImage = new Mat();
        Mat padded = splitSrc(image);
        padded.convertTo(padded, CvType.CV_32F);
        planes.add(padded);
        planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
        Core.merge(planes, complexImage);
        Core.dft(complexImage, complexImage);
        Scalar scalar = new Scalar(0, 0, 0);
        Point point = new Point(40, 40);
        Mat magnitude = createOptimizedMagnitude(complexImage);
        planes.clear();
        return magnitude;
    }
    
    public static Mat getImageWatermarkWithText(Mat image){
        List<Mat> planes = new ArrayList<Mat>();
        Mat complexImage = new Mat();
        Mat padded = splitSrc(image);
        padded.convertTo(padded, CvType.CV_32F);
        planes.add(padded);
        planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
        Core.merge(planes, complexImage);
        Core.dft(complexImage, complexImage);
        Mat magnitude = createOptimizedMagnitude(complexImage);
        planes.clear();
        return magnitude;
    }

    private static Mat splitSrc(Mat mat) {
        mat = optimizeImageDim(mat);
        Core.split(mat, allPlanes);
        Mat padded = new Mat();
        if (allPlanes.size() > 1) {
            for (int i = 0; i < allPlanes.size(); i++) {
                if (i == 0) {
                    padded = allPlanes.get(i);
                    break;
                }
            }
        } else {
            padded = mat;
        }
        return padded;
    }
    private static Mat antitransformImage(Mat complexImage, List<Mat> allPlanes) {
        Mat invDFT = new Mat();
        Core.idft(complexImage, invDFT, Core.DFT_SCALE | Core.DFT_REAL_OUTPUT, 0);
        Mat restoredImage = new Mat();
        invDFT.convertTo(restoredImage, CvType.CV_8U);
        if (allPlanes.size() == 0) {
            allPlanes.add(restoredImage);
        } else {
            allPlanes.set(0, restoredImage);
        }
        Mat lastImage = new Mat();
        Core.merge(allPlanes, lastImage);
        return lastImage;
    }

   private static Mat optimizeImageDim(Mat image) {
        Mat padded = new Mat();
        int addPixelRows = Core.getOptimalDFTSize(image.rows());
        int addPixelCols = Core.getOptimalDFTSize(image.cols());
        Core.copyMakeBorder(image, padded, 0, addPixelRows - image.rows(), 0, addPixelCols - image.cols(),
                Core.BORDER_CONSTANT, Scalar.all(0));


        return padded;
    }
    private static Mat createOptimizedMagnitude(Mat complexImage) {
        List<Mat> newPlanes = new ArrayList<Mat>();
        Mat mag = new Mat();
        Core.split(complexImage, newPlanes);
        Core.magnitude(newPlanes.get(0), newPlanes.get(1), mag);
        Core.add(Mat.ones(mag.size(), CvType.CV_32F), mag, mag);
        Core.log(mag, mag);
        shiftDFT(mag);
        mag.convertTo(mag, CvType.CV_8UC1);
        Core.normalize(mag, mag, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC1);
        return mag;
    }
    private static void shiftDFT(Mat image) {
        image = image.submat(new Rect(0, 0, image.cols() & -2, image.rows() & -2));
        int cx = image.cols() / 2;
        int cy = image.rows() / 2;

        Mat q0 = new Mat(image, new Rect(0, 0, cx, cy));
        Mat q1 = new Mat(image, new Rect(cx, 0, cx, cy));
        Mat q2 = new Mat(image, new Rect(0, cy, cx, cy));
        Mat q3 = new Mat(image, new Rect(cx, cy, cx, cy));
        Mat tmp = new Mat();
        q0.copyTo(tmp);
        q3.copyTo(q0);
        tmp.copyTo(q3);
        q1.copyTo(tmp);
        q2.copyTo(q1);
        tmp.copyTo(q2);
    }
}
import org.opencv.imgcodecs.Imgcodecs;

import java.net.URL;

import static org.opencv.imgcodecs.Imgcodecs.imread;
import static org.opencv.imgcodecs.Imgcodecs.imwrite;

public class Main {
    static{
        loadDll();
    }
    public static void main(String[] args){
        Mat img = imread("E:/software/opencv/Img.jpg");
        Mat kSpaceImg = ImgWatermarkUtil.getImageKSpace(img);
        Mat outImg = ImgWatermarkUtil.addImageWatermarkWithText(img,"zhulangfly");
        imwrite("E:/software/opencv/Img-kSpaceImg.jpg",kSpaceImg);
        imwrite("E:/software/opencv/Img-out.jpg",outImg);
        Mat watermarkImg = ImgWatermarkUtil.getImageWatermarkWithText(outImg);
        imwrite("E:/software/opencv/Img-watermark.jpg",watermarkImg);
    }
    public static void loadDll() {
        System.setProperty("java.awt.headless", "false");
        System.out.println(System.getProperty("java.library.path"));
        URL url = ClassLoader.getSystemResource("dlls/opencv_java460.dll");
        System.load(url.getPath());
    }
}
    <dependency>
         <groupId>org.openpnp</groupId>
         <artifactId>opencv</artifactId>
         <version>4.6.0-0</version>
   </dependency>

参考文献文章来源地址https://www.toymoban.com/news/detail-677760.html

  • 数字水印技术在前端落地的思考
  • 阿里巴巴公司根据截图查到泄露信息的具体员工的技术是什么?
  • 通俗讲解:图像傅里叶变换
  • 形象理解二维傅里叶变换
  • 傅里叶变换交互式入门
  • opencv的java-maven-idea开发环境配置
  • Java使用OpenCV:基于DCT变换 实现 图片 数字 的盲水印添加和提取

到了这里,关于【数据安全-02】AI打假利器数字水印,及java+opencv实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • IP数据云:实战网络安全的得力利器

    在当今数字化时代,企业和个人面临着日益复杂和频繁的网络安全威胁。为了应对这些挑战,IP数据云作为一项全面的网络安全解决方案,已经在多个实际案例中展现了其卓越的能力。 1、识别并隔离异常行为 挑战:一家大型金融机构发现其内部网络上有异常的数据流量,但

    2024年01月25日
    浏览(35)
  • AI技术发展:防范AI诈骗,守护数字安全

    随着AI技术的迅猛发展,人工智能赋予了计算机更多的能力,包括自然语言处理、图像生成、声音合成等。这些领域的突破为人们提供了全新的体验和便捷,但同时也催生了一些潜在的安全风险,其中最突出的就是AI诈骗。本文将探讨如何防范AI诈骗,确保数字安全。 AI技术的

    2024年02月06日
    浏览(38)
  • 第02讲:链路追踪利器,快速上手 SkyWalking

    SkyWalking 环境搭建 在本课时中,我们将安装并体验 SkyWalking 的基本使用,下面是使用到的相关软件包: apache-skywalking-apm-6.2.0.tar.gz 下载地址:https://archive.apache.org/dist/skywalking/6.2.0/ elasticsearch-6.6.1.tar.gz 下载地址:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.6.1.tar.gz ki

    2023年04月10日
    浏览(38)
  • AI数据技术02:RAG数据检索

            在人工智能的动态环境中,检索增强生成(RAG)已成为游戏规则的改变者,彻底改变了我们生成文本和与文本交互的方式。RAG 使用大型语言模型 (LLM) 等工具将信息检索的强大功能与自然语言生成无缝结合,为内容创建提供了一种变革性的方法。         在

    2024年02月03日
    浏览(42)
  • AI诈骗的防范与应对:维护数字安全的责任

    近年来,人工智能生成内容(AIGC)技术在各个领域都取得了显著的进展,为我们带来了更多的便捷和创新。然而,与此同时,这项技术也被不法分子滥用,用于实施各种形式的AI诈骗。这种威胁需要我们认真对待,并采取适当的措施来应对。本文将探讨AI诈骗的风险,以及如

    2024年01月22日
    浏览(38)
  • 开源与安全:共同构建可信赖的数字生态系统(AI)

    开源与安全:共同构建可信赖的数字生态系统 引言 开源软件的透明性与审计优势 1. 透明的源代码 2. 社区审计的力量 3. 及时修复漏洞 开源软件在安全方面的价值和贡献 1. 安全性强化数字生态 2. 防范供应链攻击 3. 提供安全的解决方案 开源软件在不同行业的安全应用案例 1

    2024年02月20日
    浏览(58)
  • Web3与AI:数字时代安全隐私交易的未来

    AI+web3=下一个热门赛道? 在数字时代的浪潮中,Web3和人工智能(AI)成为了两个备受关注的前沿技术。 Web3代表着下一代互联网,强调去中心化、透明和用户控制的特点。 而人工智能作为一种智能化的技术,正在改变着我们的生活和商业领域。本文将探讨Web3与人工智能的

    2024年02月13日
    浏览(39)
  • 代理IP与SOCKS5代理:网络安全与数据隐私保护的技术利器

    深入探讨代理IP和SOCKS5代理的技术性,并阐述它们在网络安全和数据隐私保护中的重要作用。我们将详细介绍代理IP的概念、工作原理和应用场景,以及SOCKS5代理协议的特点和优势。此外,我们还将讨论如何使用代理IP和SOCKS5代理实现匿名访问、绕过封锁和保护个人隐私。通过

    2024年02月11日
    浏览(46)
  • OpenStego-隐写术及数字水印添加教程

    OpenStego提供了两个主要功能:         Data hiding,即数据隐藏:它可以隐藏任何数据在封面文件(如图像)。         Digital watermarking,即数字水印:使用不可见签名对文件(如图像)进行水印。它可以用来检测未经授权的文件复制。 Data hiding 数据隐藏在这种模式下,你既可以隐

    2024年02月03日
    浏览(38)
  • 【Java万花筒】缓存与存储:Java应用中的数据处理利器

    在现代软件开发中,高效地处理和存储数据是至关重要的任务。本文将介绍一系列在Java应用中广泛使用的数据缓存与存储库,涵盖了Ehcache、Redisson、Apache Cassandra、Hazelcast以及Apache Ignite。这些库不仅为数据的快速访问提供了解决方案,还在分布式环境下展现出强大的能力,满

    2024年01月24日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包