精华内容
下载资源
问答
  • 不可见数字水印
    2021-03-13 02:34:48

    如何使用JAVA实现数字水印

    数字水印有可见不可见之分,可见的比如课件上印有学校校徽,微博发图片会水印上上传者的信息及微博logo等。

    用java实现可见的数字水印,草人主要是用到了java.awt包中的AlphaComposite类,当然在实现之前先介绍一下AlphaComposite类:

    AlphaComposite类是关于两个目标重叠的混合处理类,此类实现的特定规则是 T. Porter 和 T. Duff 合著的 “Compositing Digital Images”, SIGGRAPH 84, 253-259 中描述的 12 条基本规则集。该类提供的一个getInstance的方法,其中的两个参数为rule和alpha,第二个参数将由调用者设置一个alpha值,即是透明度的设置,而第一个参数则是混合方式。此类扩展了 Porter 和 Duff 定义的方程,包含一个额外的因子。AlphaComposite 类的实例可以包含一个 alpha 值,在将该值用于混合方程之前,可以用它来修改不透明度和每个源像素的覆盖率。

    Porter和 Duff 的论文在混合方程的描述中使用了以下因子:

    以规则SRC_OVER为例,使用这些因子,Porter 和 Duff 定义了 12 种选择混合因子 Fs 和 Fd 的方法,从而产生了 12 种令人满意的可视效果。在对 12 个指定可视效果的静态字段的描述中,给出了具有确定 Fs 和 Fd 值的方程。SRC_OVER在目标色之上合成源色(Porter-Duff Source Over Destination 规则)。指定Fs = 1 和 Fd = (1-As),因此:

    Ar = As + Ad*(1-As)

    Cr = Cs + Cd*(1-As)

    该类扩展后一共有24中规则,定义了9个方法,由于草人的程序中用到了方法getInstance()就对之说明一下——

    •详细定义:public static AlphaComposite getInstance(int rule, float alpha)

    •功能:创建一个 AlphaComposite 对象,它具有指定的规则和用来乘源色 alpha 值的常量 alpha 值。在将源色与目标色合成前,要将源色乘以指定的 alpha 值。

    •参数:rule——合成规则,24种;alpha——将乘源色的 alpha 值的常量 alpha 值。alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字。

    •抛出:IllegalArgumentException - 如果 alpha 小于 0.0 或大于 1.0,或者 rule 是以下规则之一:CLEAR、SRC、DST、SRC_OVER、DST_OVER、SRC_IN、DST_IN、SRC_OUT、DST_OUT、 SRC_ATOP、DST_ATOP 或 XOR。

    既然是图像处理,就先创建一个java2d对象

    Graphics2D g2d=image.createGraphics();

    //用源图像填充背景

    g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null, null);

    然后为 Graphics2D 上下文设置 Composite后就可以将想要写入的文字或者图片写入源图片上

    AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);

    //为 Graphics2D 上下文设置 Composite。 Composite 用于所有绘制方法中,如 drawImage、

    //drawString、draw 和 fill。 它指定新的像素如何在呈现过程中与图形设备上的现有像素组合。

    g2d.setComposite(ac);

    完整代码(代码中注释足够了,就不多啰嗦)

    package cumt.zry.two;

    import java.awt.*;

    import java.awt.image.BufferedImage;

    import java.io.*;

    import javax.imageio.*;

    public class Watermark2{

    public Watermark2(){super();};

    /**

    * 在源图片上设置水印文字

    */

    public void WordsToImage(String srcImagePath,float alpha,

    String font,int fontStyle,int fontSize,Color color,

    String inputWords,int x,int y,String imageFormat,String toPath) throws IOException{

    FileOutputStream fos=null;

    try {

    //读取图片

    BufferedImage image = ImageIO.read(new File(srcImagePath));

    //创建java2D对象

    Graphics2D g2d=image.createGraphics();

    //用源图像填充背景

    g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null, null);

    //!!!!

    AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);

    //为 Graphics2D 上下文设置 Composite。 Composite 用于所有绘制方法中,如 drawImage、

    //drawString、draw 和 fill。 它指定新的像素如何在呈现过程中与图形设备上的现有像素组合。

    g2d.setComposite(ac);

    //设置文字字体名称、样式、大小

    g2d.setFont(new Font(font, fontStyle, fontSize));

    g2d.setColor(color);//设置字体颜色

    g2d.drawString(inputWords, x, y); //输入水印文字及其起始x、y坐标

    g2d.dispose();

    //将水印后的图片写入toPath路径中

    fos=new FileOutputStream(toPath);

    ImageIO.write(image, imageFormat, fos);

    }

    //文件操作错误抛出

    catch (Exception e) {

    e.printStackTrace();

    }finally{

    if(fos!=null){

    fos.close();

    }

    }

    }

    /**

    * 在源图像上设置图片水印

    */

    public void ImageToImage(String srcImagePath,String appendImagePath,

    float alpha,int x,int y,int width,int height,

    String imageFormat,String toPath) throws IOException{

    FileOutputStream fos = null;

    try {

    //读图

    BufferedImage image = ImageIO.read(new File(srcImagePath));

    //创建java2D对象

    Graphics2D g2d=image.createGraphics();

    //用源图像填充背景

    g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null, null);

    //关键地方

    AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);

    g2d.setComposite(ac);

    BufferedImage appendImage = ImageIO.read(new File(appendImagePath));

    g2d.drawImage(appendImage, x, y, width, height, null, null);

    g2d.dispose();

    fos=new FileOutputStream(toPath);

    ImageIO.write(image, imageFormat, fos);

    } catch (Exception e) {

    e.printStackTrace();

    }finally{

    if(fos!=null){

    fos.close();

    }

    }

    }

    public static void main(String[] args) throws Exception

    {

    Watermark2 imageObj = new Watermark2();

    //源图片路径

    String srcImagePath = "F:/27.jpg";

    //水印图片路径

    String appendImagePath = "F:/logo.jpg";

    // ---- 宋体 普通字体 77号字 红色 透明度0.4"

    float alpha = 0.4F;

    String font = "宋体";

    int fontStyle = Font.PLAIN;

    int fontSize = 77;

    Color color = Color.RED;

    String inputWords = "图片上设置水印文字";

    int x = 1700;

    int y = 77;

    String imageFormat = "jpg";

    //水印文字后的存储路径

    String wToPath = "F:/31.png";

    //水印图片后的存储路径

    String IToPath = "F:/7.png" ;

    imageObj.WordsToImage(srcImagePath, alpha, font, fontStyle,

    fontSize, color, inputWords, x, y, imageFormat, wToPath);

    imageObj.ImageToImage(srcImagePath, appendImagePath, alpha,

    x, y, 300, 200, imageFormat, IToPath);

    }

    }

    实现预览:

    以上就是文章的全部内容,希望对大家的学习有所帮助。相关阅读:

    深入解析JavaScript中的arguments对象

    List<>中Find的用法小结

    node.js中的fs.fchmod方法使用说明

    Android中WebView的一些简单用法

    Win10系统中注销/睡眠/休眠等电源模式有什么区别?

    Win7将文件夹按时间分组排列以快速找到需要的文件

    JavaScript中for-in遍历方式示例介绍

    win8笔记本无法搜索wifi信号找不到WLAN该怎么办?

    win10th2如何升级更新?win10 TH2正式版升级教程

    sqlplus登录\连接命令、sqlplus命令的使用大全

    Win10预览体验计划2016年1月有新变化 明年1月将有多个Windows10预览版发布

    Oracle 分区索引介绍和实例演示

    升级Win10后VirtualBox无法使用怎么办

    Android组件Glide实现图片平滑滚动效果

    更多相关内容
  • 显性水印和不可见数字水印

    千次阅读 2021-03-05 11:12:31
    显性水印和不可见数字水印 显性水印(代码见最后) 获取要绘制的画布所在元素 获取浏览器的dpr(devicePixelRatio),将画布的宽度和高度乘以dpr, 否则绘制出来的画布会变得模糊 创建Image元素开始绘制原始图片 ...

    显性水印和不可见数字水印

    显性水印(代码见最后)

    1. 获取要绘制的画布所在元素

    2. 获取浏览器的dpr(devicePixelRatio),将画布的宽度和高度乘以dpr, 否则绘制出来的画布会变得模糊

    3. 创建Image元素开始绘制原始图片

    4. 绘制显性水印, 设置水印的样式, 水印位置设置在图片右下角

    不可见数字水印

    function getBitOffset(color):

    获取RGB中某一分量对应的位和偏移量

    图片编码
    function encodeImg(src):
    1. 获取画布元素的Context

    2. 画布宽高乘以dpr(devicePixelRatio)

    3. 绘制水印, 使用getImageData()方法获得水印的像素信息

    4. 绘制图片, 使用getImageData()方法获得图片的像素信息

    5. 调用mergeData()方法合并像素信息

    function mergeData(ctx, newData, color, originalData):

    ​ 1. 合并原始图片数据和数字水印的rgb数据.

    ​ 2. 对于规定的某一个RGB分量,

    ​ 采用将把没有水印信息的像素通过自增方式全改成偶数,

    ​ 把有水印信息的像素自增全改成奇数这种编码的方式编码图片

    1. 绘制合并后的图片
    图片解码
    function decodeImg(src,color):
    1. 同encodeImg()方法一样, 使用getImageData()方法获得图片的RGB信息
    2. 调用processData()方法
    function processData(ctx, originalData,color):
    1. 解码的方式与编码的方式相反
    2. 将非指定的RGB分量的所有信息置0(像素点置黑)
    3. 对于指定的RGB分量, 将偶数部分(非水印信息)的信息置0, 其他信息置为255
    4. 对于alpha通道的信息不处理

    结果如图

    显性水印和不可见数字

    代码

    未解决跨域问题, 不可从外部直接打开html, 需从IDE打开

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>watermark</title>
    
    </head>
    <style>
        html{
            margin:0;
            padding: 0;
        }
        .app{
            display: flex;
            justify-content: space-around;
            flex-wrap: wrap;
        }
        .canvas{
            height: 200px;
            width: 540px;
            margin-top: 50px;
        }
        img{
            height: 200px;
            width: 540px;
            margin-top: 50px;
        }
    
    </style>
    <body>
    <div class="app">
        <img src="../images/1.jpg">
        <canvas class="canvas" id="canvas-mark"></canvas>
        <canvas class="canvas" id="encode-mark"></canvas>
        <canvas class="canvas" id="encode-image"></canvas>
    
    </div>
    <script>
            //绘制显性水印
            var canvas_mark=document.getElementById("canvas-mark")
            var dpr = (scale = window.devicePixelRatio || 1);
            var rect = canvas_mark.getBoundingClientRect();
            canvas_mark.width = rect.width * dpr;
            canvas_mark.height = rect.height * dpr;
            canvas_mark.style.width = rect.width + "px";
            canvas_mark.style.height = rect.height + "px";
            let ctx=canvas_mark.getContext('2d');
            let img = new Image();
            img.onload = function () {
                ctx.drawImage(img, 0, 0, canvas_mark.width, canvas_mark.height);
                const txt = '@ ChenYin';
                ctx.fillStyle = '#fff';
                ctx.globalAlpha = 1;
                ctx.font = `12px 微软雅黑 light`;
                ctx.textAlign = 'right';
                ctx.fillText(txt, canvas_mark.width - 10, canvas_mark.height - 10);
            }
            img.src="../images/1.jpg"
    
            //绘制数字水印和数字水印结果图
    
            //获取RGB中某一分量对应的位和偏移量
            function getBitOffset(color) {
                let bit, offset;
    
                switch (color) {
                    case 'R':
                        bit = 0;
                        offset = 3;
                        break;
                    case 'G':
                        bit = 1;
                        offset = 2;
                        break;
                    case 'B':
                        bit = 2;
                        offset = 1;
                        break;
                }
                return [bit,offset];
            }
    
            //图片编码
            //合并原始图片数据和数字水印的rgb数据, 采用将把没有信息的像素全改成偶数, 把有信息的像素全改成奇数这种编码的方式
            function mergeData(ctx, newData, color, originalData) {
                let oData = originalData.data;
    
                let [bit,offset]=getBitOffset(color);
    
                for (var i = 0; i < oData.length; i++) {
                    if (i % 4 == bit) {
    
                        // 只处理目标通道
                        //把没有信息的像素全改成偶数
                        if (newData[i + offset] === 0 && (oData[i] % 2 === 1)) {
    
                            if (oData[i] === 255) {
                                oData[i]--;
                            } else {
                                oData[i]++;
                            }
                            //把有信息的像素全改成奇数
                        } else if (newData[i + offset] !== 0 && (oData[i] % 2 === 0)) {
                            // // 有信息的像素,该通道最低位置1,可以想想上面的斑点效果是怎么实现的
                            oData[i]++;
                        }
                    }
                }
                ctx.putImageData(originalData, 0, 0);
    
    
            }
    
            function encodeImg(src) {
                var textData;
                var can=document.getElementById('encode-mark');
                var dpr = (scale = window.devicePixelRatio || 1);
                var rect = canvas_mark.getBoundingClientRect();
                can.width = rect.width * dpr;
                can.height = rect.height * dpr;
                can.style.width = rect.width + "px";
                can.style.height = rect.height + "px";
    
    
                var ctx = can.getContext('2d');
                ctx.font = '30px Microsoft Yahei';
                ctx.fillText('ChenYin', 200, 120);
                textData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height).data;
                var img = new Image();
                // img.crossOrigin = '';
                var originalData;
                img.onload = function () {
                    // 获取指定区域的canvas像素信息
                    ctx.drawImage(img, 0, 0,can.width,can.height);
                    originalData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
                    mergeData(ctx, textData, 'G', originalData)
                };
                img.src = src;
            }
    
            //图片解码
            function processData(ctx, originalData,color) {
                let data = originalData.data;
                let [bit,offset]=getBitOffset(color);
                for (var i = 0; i < data.length; i++) {
                    if (i % 4 == bit) {
    
                        if (data[i] % 2 == 0) {
                            data[i] = 0;
                        } else {
                            data[i] = 255;
                        }
                    } else if (i % 4 == 3) {
                        continue;//alpha通道不处理
                    } else {
                        data[i] = 0;
                    }
                }
                // 将结果绘制到画布
                ctx.putImageData(originalData, 0, 0);
            }
    
            function decodeImg(src,color) {
                var encode_image = document.getElementById('encode-image')
                var dpr = (scale = window.devicePixelRatio || 1);
                var rect = canvas_mark.getBoundingClientRect();
                encode_image.width = rect.width * dpr;
                encode_image.height = rect.height * dpr;
                encode_image.style.width = rect.width + "px";
                encode_image.style.height = rect.height + "px";
                var ctx=encode_image.getContext('2d');
                var img = new Image();
                var originalData;
                img.onload = function () {
                    // 获取指定区域的canvas像素信息
                    ctx.drawImage(img, 0, 0);
                    originalData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
                    console.log(originalData)
                    processData(ctx, originalData,color)
                };
                img.src = src;
            }
            encodeImg('../images/1.jpg');
            decodeImg('../images/1-encode.png','G');
    
    
    </script>
    </body>
    
    </html>
    
    展开全文
  • 刘剑鸣 著; ISBN:9787807179764
  • 本文介绍了如何使用JAVA实现数字水印,主要用到了java.awt包中的AlphaComposite类,需要学习制作水印的朋友可以参考下
  • 利用DCT原理,实现添加不可见水印的python程序,包括源程序,且可见系数可调节,包含压缩攻击检测程序
  • 随着网络技术和多媒体技术的飞速发展,如何保护多媒体信息的安全已成为国际上研究的热门话题,数字水印技术应运而生。作为保护数字作品版权的一种重要...该水印算法不可见性较好,对JPEG压缩,噪声,有较好的鲁棒性。
  • 利用五种攻击测试(剪切、滤波、缩放、椒盐噪音、裁剪)对嵌入水印后的图像进行攻击测试,以PSNR(峰值信噪比)、归一化的互相关系数来评价图像的抗攻击能力、不可见性和鲁棒性。(matlab代码,python 代码可私聊)
  • 介绍了标准粒子群优化(SPSO)算法,在两种粒子群改进算法Gaussian Swarm和Fuzzy PSO的基础上提出了Cauchy粒子群优化(CPSO)算法,并将遗传算法中的变异操作引入粒子群优化,形成了动态概率变异Cauchy粒子群优化...
  • 为了提高数字水印抗击各种图像攻击的性能和保持图像的稳健性和不可见性,提出了一种基于离散小波变换(DWT),SVD(singular value decomposition)奇异值分解水印图像和原始载体图像的离散余弦变换(DCT)的自适应...
  • 数字水印(Digital Watermarking)技术是将一些标识信息(即水印)直接嵌入数字载体当中(包括多媒体、文档、软件等)或是间接表示(修改特定区域的结构),且影响原载体的使用价值,也容易被探知和再次修改,但可以被...
  • 利用DCT原理,实现添加可见水印的python程序,包括源程序和界面程序,且可见系数可调节
  • Python不可见水印,隐形水印
  • 一种基于WEB图像版权的可见&不可见水印算法,陈莹,王晓宁,本论文通过对网络上数字图像安全的分析,针对数字图像易于被拷贝和被篡改的现象,提出了网络上数字图像的水印方案。该数字水印
  • 早期大约是10年前从一本数字图像处理上看到过数字水印的概念,觉得确实一种很有意思的东西,那个时候主要就是基于LSB的图像信息的隐藏,这种在空域里的方法有较大的缺陷,鲁棒性是比较差的。随便一个后期的都会造成...

    早期大约是10年前从一本数字图像处理上看到过数字水印的概念,觉得确实一种很有意思的东西,那个时候主要就是基于LSB的图像信息的隐藏,这种在空域里的方法有较大的缺陷,鲁棒性是比较差的。随便一个后期的都会造成水印的丢失,因此,虽然是一种盲水印,但是不具有很好的推广性。

    前段时间一个朋友给了我一段使用Opencv的盲水印代码,是基于FFT变换的, 抽空看了下,对其中部分的实现过程进行了替换和分解,也实现了一个最简单的基于频域的盲水印效果。

    我在寻找相关资料的时候在网络上看到有几个这方面的文章和工具,现在分享如下:

    好像还有一个写的比较详细,而且有工具,在github上也有分享代码。

    但是似乎这些工具大部分只支持文字水印,而不支持图像水印,文字我不熟悉,因此我还是用图像做水印模板,核心的代码如下所示:

    fb8d4fe9ceebb2cdcc87f56e9c3f6ad4.gifint IM_AddBlindWaterMark(unsigned char *Src, unsigned char *WaterMark, unsigned char *Dest, int Width, int Height, int Stride, int WidthW, int HeightW, intStrideW)

    {int Channel = Stride / Width, ChannelW = StrideW /WidthW;if ((Src == NULL) || (Dest == NULL))                        returnIM_STATUS_NULLREFRENCE;if ((Width <= 0) || (Height <= 0))                            returnIM_STATUS_INVALIDPARAMETER;if ((Channel != 1) && (Channel != 3) && (Channel != 4))        returnIM_STATUS_INVALIDPARAMETER;if ((ChannelW != 1) && (ChannelW != 3) && (ChannelW != 4))    returnIM_STATUS_INVALIDPARAMETER;if ((WidthW >= Width / 4) || (HeightW >= Height / 4))        return IM_STATUS_INVALIDPARAMETER;        //水印图不能大于原图尺寸的一半

    int Status =IM_STATUS_OK;int OptimalW = IM_GetOptimalDftSize(Width),    OptimalH =IM_GetOptimalDftSize(Height);int OffsetX = (OptimalW - Width) / 2,        OffsetY = (OptimalH - Height) / 2;int HalfW = OptimalW / 2,                    HalfH = OptimalH / 2;if (Channel == 1)

    {

    Complex*Data = (Complex *)malloc(OptimalW * OptimalH * sizeof(Complex));if ((Data == NULL))    returnIM_STATUS_OUTOFMEMORY;for (int Y = 0; Y < Height; Y++)                                //我们把数据居中布置,边缘用重复像素的方式{

    unsignedchar *LinePS = Src + Y *Stride;

    Complex*LinePD = Data + (Y + OffsetY) *OptimalW;for (int X = 0; X < OffsetX; X++)

    {

    LinePD[X].Real= LinePS[0];

    LinePD[X].Imag= 0;

    }for (int X = OffsetX; X < OffsetX + Width; X++)

    {

    LinePD[X].Real= LinePS[X -OffsetX];

    LinePD[X].Imag= 0;

    }for (int X = OffsetX + Width; X < OptimalW; X++)

    {

    LinePD[X].Real= LinePS[Width - 1];

    LinePD[X].Imag= 0;

    }

    }for (int Y = 0; Y < OffsetY; Y++)

    {

    memcpy(Data+ Y * OptimalW, Data + OffsetY * OptimalW, OptimalW * sizeof(Complex));

    }for (int Y = OffsetY + Height; Y < OptimalH; Y++)

    {

    memcpy(Data+ Y * OptimalW, Data + (OffsetY + Height - 1) * OptimalW, OptimalW * sizeof(Complex));

    }

    IM_FFT2D(Data, Data, OptimalW, OptimalH,false, 0, 0);

    IM_FFTShift(Data, Data, OptimalW, OptimalH);//数据偏移到中心

    for (int Y = 0; Y < HeightW; Y++)

    {

    Complex*LineLT = Data + (Y + OffsetY + Height / 16) * OptimalW + OffsetX + Width / 16;            //确保在可见的范围内添加,左上角和右下角都镜像添加

    Complex *LineRB = Data + (OffsetY + Height - 1 - Height / 16 - Y) * OptimalW + OffsetX + Width - 1 - Width / 16;    //再稍微往内部移动一点,可以适当增强抵抗变形的能力,但是越往中心其对最终结果的影响越大。

    unsigned char *LinePS = WaterMark + Y *StrideW;if (ChannelW == 1)

    {for (int X = 0; X < WidthW; X++)

    {float Cof = ((LinePS[X] * 4) >> 8) + 1;

    LineLT[X].Real*= Cof;    LineLT[X].Imag *=Cof;

    LineRB[-X].Real *= Cof;    LineRB[-X].Imag *=Cof;

    }

    }else if (ChannelW == 3)

    {for (int X = 0; X < WidthW; X++)

    {float Cof = ((((LinePS[0] + LinePS[1] + LinePS[1] + LinePS[2]) >> 2) * 4) >> 8) + 1;

    LineLT[X].Real*= Cof;    LineLT[X].Imag *=Cof;

    LineRB[-X].Real *= Cof;    LineRB[-X].Imag *=Cof;

    LinePS+= 3;

    }

    }else if (ChannelW == 4)

    {for (int X = 0; X < WidthW; X++)

    {float Cof = ((IM_Div255(((LinePS[0] + LinePS[1] + LinePS[1] + LinePS[2]) >> 2) * LinePS[3]) * 4) >> 8) + 1;

    LineLT[X].Real*= Cof;    LineLT[X].Imag *=Cof;

    LineRB[-X].Real *= Cof;    LineRB[-X].Imag *=Cof;

    LinePS+= 4;

    }

    }

    }

    IM_IFFTShift(Data, Data, OptimalW, OptimalH);

    IM_FFT2D(Data, Data, OptimalW, OptimalH,true, 0, 0);for (int Y = 0; Y < Height; Y++)

    {

    Complex*LinePS = Data + (Y + OffsetY) * OptimalW +OffsetX;

    unsignedchar *LinePD = Dest + Y *Stride;for (int X = 0; X < Width; X++)

    {

    LinePD[X]=IM_ClampToByte(LinePS[X].Real);

    }

    }if (Data != NULL)        free(Data);returnIM_STATUS_OK;

    }else{

    }

    }

    fb8d4fe9ceebb2cdcc87f56e9c3f6ad4.gif

    首先,把图像变换到频域,这里采用了opencv的有关FFT计算的过程,使用IM_GetOptimalDftSize计算最佳的DFT算法的大小,然后将图像数据居中分布,周边的空白像素采用镜像填充方式填充,虚部数据填0。

    FFT变换完成后,对FFT数据进行移位,把高频数据放置到图像的中心,低频的数据放置到图像的边缘。为了将水印的图像嵌入到目标图像,我们在适当位置根据水印图像的强度或内容来修改这些频域值,为了不影响最终的目标图像的视觉效果,嵌入的数据放置到边缘的低频数据中(靠近边缘的部位),我这里也没有放置在最边缘,而是边缘靠中的部位。

    常用的水印图像可能是8位灰度、24位彩色或32位透明图,因此,我在程序里对不同位数的水印图都做了处理,如果是32位图,则把Alpha也考虑进去了,使用的嵌入方式就是最简单的更具水印图的颜色强度值将目标图像的频域系数放大。这里的放大程度我做了固定的设计,测试效果还比较好,如果过度放大,则最后处理的结果将会严重的失真,这就失去了算法本身的意义了。当然还有一种方式就是缩小系数,也可以去尝试下。

    之后,我们需要将平移后的数据再次进行移位,然后就是进行IFFT计算了,并将计算结果返回到图像域。

    本例只给出了针对灰度目标图像的代码,那么彩色图像其实是一样的过程,将他们分解成三个通道单独处理就OK了。

    同时,为了保证水印对结果图不会造成太大的影响,我们程序对水印图大小做了限制,长和宽都不得大于目标图像的1/4。

    另外,从嵌入的代码可以看到,我们希望水印图像尽量是黑色的背景(8位或24位)或纯背景部位是透明的(32位),这样对目标图像的影响也比较小。

    我们来做一些测试,以下是一张原图(原图缩小显示了)及两个水印图进行测试:

    d97297b12da51b33ec9355dff1036844.png 

    50bceca64cb5023e48dd8ba8a7f1f130.png  

    b1406b1a2dc340a804f37e8d4df6324e.png

    分别查看其结果图和频谱图:

    b9492ba7dc351834dd7cab9dfd1fcc5c.png 

    7390c4c5513c1ab259606bb58a928e77.png

    f5b8963b063a9e9f07fa667a0ec6a52c.png 

    bc017e2d527edc938ffce704611c6457.png

    可见,添加水印后基本未对原始图像造成视觉上的损失,在处理后的图像的频谱上可以明显看到添加后的水印的样式。

    如果对添加水印后的图像进行一些处理,看看水印是否还能有效保存。

    一、乱七八糟的增强

    910a9a8da4f6723d89aa6101218673c9.png 

    3fcf570c08f26c9f5ca78fafa375af47.png

    2、有局部裁切的旋转

    3d76703a1e58cde6f76048f2e680a451.png  

    8274b75c9f26b164ce4e2613bbe1e32c.png

    3、含有模糊性质的算法

    2ce9f21655b2feaf7f927bc8ca14e1b3.png 

    0691b73b602efd1db7ee5d315395550f.png

    可见,这个时候水印信息就基本丢失了,这主要是因为我们的水印信息是加在图像的低频的,而模糊会对低频进行处理,所以就看不到水印了,但是如果是锐化算法就不成问题的。

    因此,这个盲水印的功能还是比较初级的,但是如果在自己的比较重要的图里隐藏个水印有的时候还是值得的,假如某个坏人是直接使用你的图而没有做任何更改呢。

    另外,还有一种基于FFT比较常见的水印技术,需要嵌入水印的图片以及未嵌入水印的原始图这样才可以获得水印,理论上讲这种应该不叫做盲水印了,但是他有个好处就是可以对水印进行加密,这样别人就比较难以知道你对图像是否嵌入了水印了。需要做的额外工具就是一定需要保留原始的未加水印的图像了。

    我将这个 小工具也集成到了我的SSE做的DEMO里了,有需要的朋友可以试下:

    a0fa9d59da0ec7541260a0cf21d240a7.png

    展开全文
  • 随着数字水印技术的发展,数字水印的应用领域也得到了扩展,数字水印的基本应用领域是版权保护、隐藏标识、认证和安全不可见通信。 当数字水印应用于版权保护时,潜在的应用市场在于电子商务、在线或离线地分发...
  • 提出了一种新的加密计算全息技术,原始水印图像经过双随机相位编码,所得复数图像经过共轭对称延拓和傅里叶变换后得到全息图,所得全息图解密图像上没有视觉可见噪声污染。...所提的数字水印技术有很好的实用价值。
  • 本文依据视频特点,指出作为视频的数字水印应满足的要求,对视频数字水印算法进行分析和探讨。最后针对数字电视版权管理的具体问题,提出利用数字水印技术巧妙解决问题的方案。
  • 数字水印处理.doc

    2020-02-15 19:17:11
    为保护数字图像作品的知识产权,采用数字水印技术嵌入水印图像于作品中,同时尽可能影响作品的可用性,在作品版权发生争执时,通过提取水印信息确认作品版权。 通常情况下,水印图像大小要远小于载体图像,嵌入...
  • 基于小波分解的图像数字水印算法,全文包括数字水印的嵌入和提取。
  • 水印的强度决定其鲁棒性,多数水印算法都是人为地调整水印的嵌入强度,其缺点是只对少数图像适用。针对这一问题,该文提出一种具有自适应性的根据图像本身纹理特性预测出水印强度的算法,适合于多数图像,实验结果...
  • 提出了一种基于SVD分解与小波分解的小波隐形水印...通过奇异值分解实现盲提取,把水印图像嵌入小波分解的中频子带,最后运用归一化互相关函数(NC)和峰值信噪比(PSNR)进行定量分析,证明该算法有很好的不可见性与鲁棒性。
  • 随着数字水印技术的发展,数字水印的应用领域也得到了扩展,数字水印的基本应用领域是版权保护、隐藏标识、和安全不可见通信。当数字水印应用于版权保护时,潜在的应用市场在于电子商务、在线或离线地分发多媒体内容...
  • 为了提高水印的鲁棒性和不可见性,在颜色模型、全息和小波理论的基础上,提出一种基于Lab空间的图像全息数字水印算法。首先将水印信息进行双随机相位调制并生成水印全息图,然后将载体图像从RGB颜色空间转换到CIELab...
  • 数字水印技术可以保护来自入侵者的多媒体数据,例如文本,图像,音频和视频。 它将版权信息嵌入到多媒体内容中。 所有权标识和身份验证可保护内容免受攻击者的侵害。 二进制水印图像被加扰并嵌入到原始封面图像中。 ...
  • 数字水印是一种嵌入到图像、视频或者音频数据中的不可见标志,通过对水印信息的检测可以达到保护多媒体数据版权的目的。先前众多的水印算法大部分是基于二维操作的(如静止图像、视频)。基于虚拟光学信息隐藏理论提出...
  • 目录1设计目的 12设计要求 23相关知识 33.1 数字水印的相关知识数字水印的相关知识 33.2 数字水印技术的基本原理 43.3数字水印的分类 54设计内容 64.1 LSB算法介绍 64.1.1 LSB算法的基本原理 64.1.2 LSB算法基本步骤...

    目录

    1设计目的 1

    2设计要求 2

    3相关知识 3

    3.1 数字水印的相关知识数字水印的相关知识 3

    3.2 数字水印技术的基本原理 4

    3.3数字水印的分类 5

    4设计内容 6

    4.1 LSB算法介绍 6

    4.1.1 LSB算法的基本原理 6

    4.1.2 LSB算法基本步骤 6

    4.2 LSB算法的实现 6

    4.3设计流程图 7

    4.3.1水印嵌入的流程图 7

    4.3.2水印提取的流程图 8

    5程序源代码 9

    6仿真结果与分析 12

    6.1 嵌入水印后的运行结果 12

    6.2 提取水印后的运行结果 13

    6.3 结果分析 14

    7结论语 15

    8参考文献 16



    1设计目的

    (1)了解数字水印的基本概念,深入理解基于LSB算法的数字水印嵌入与提取方法。

    (2)运用MATLAB语言编程实现图像水印的嵌入和提取。

    (3)能够显示水印嵌入前后的载体图像,能够显示嵌入与提取的水印。

    (4)熟练掌握 MATLAB软件的基本操作。

    (5)学会掌握 MATLAB软件的程序编程。

    (6)培养独立分析和解决问题的能力,学会撰写课程设计的总结报告。


    2设计要求

    本设计利用MATLAB进行编程及仿真,仿真内容为基于Matlab的数字水印设计,基于空域的水印实现。拟利用所学数字图象处理技术知识,在MATLAB软件系统上来实现对图像水印的嵌入和提取。

    (1)掌握课程设计的相关知识、概念、思路及目的。

    (2)程序设计合理、能够正确运行且操作简单,可实施性强。

    (3)掌握数字水印技术的基本原理。

    (4)掌握基于空域的LSB算法并明确程序操作步骤的先后顺序。


    3相关知识

    3.1 数字水印的相关知识数字水印的相关知识

    数字水印(Digital Watermark)技术是指用信号处理的方法在数字化的多媒体数据中嵌入隐蔽的标记,这种标记通常是不可见的,只有通过专用的检测器或阅读器才能提取。数字水印是信息隐藏技术的一个重要研究方向。

    在数字水印技术中,水印的数据量和鲁棒性构成了一对基本矛盾。从主观上讲,理想的水印算法应该既能隐藏大量数据,又可以抗各种信道噪声和信号变形。然而在实际中,这两个指标往往不能同时实现,不过这并不会影响数字水印技术的应用,因为实际应用一般只偏重其中的一个方面。如果是为了隐蔽通信,数据量显然是最重要的,由于通信方式极为隐蔽,遭遇敌方篡改攻击的可能性很小,因而对鲁棒性要求不高。但对保证数据安全来说,情况恰恰相反,各种保密的数据随时面临着被盗取和篡改的危险,所以鲁棒性是十分重要的,此时,隐藏数据量的要求居于次要地位。数字水印技术是通过一定的算法将一些标志性信息直接嵌到多媒体内容当中,但不影响原内容的价值和使用,并且不能被人的知觉系统觉察或注意到。水印信息可以是作者的序列号、公司标志、有特殊意义的文本等,可用来识别文件、图像或音乐制品的来源、版本、原作者、拥有者、发行人、合法使用人对数字产品的拥有权。与加密技术不同,数字水印技术并不能阻止盗版活动的发生,但它可以判别对象是否受到保护,监视被保护数据的传播、真伪鉴别和非法拷贝、解决版权纠纷并为法庭提供证据。为了给攻击者增加去除水印的难度,目前大多数水印制作方案都采用密码学中的加密(包括公开密钥、私有密钥)体系来加强,在水印的嵌入、提取时采用一种密钥,甚至几种密钥联合使用。

    随着计算机应用逐渐广泛、网络技术的迅速发展,使音频、视频等多媒体信息都能以数字形式传输和播放,从而使大规模非授权拷贝成为了可能,而这样会损害音乐、电影、书籍和软件等出版业的发展,为了保护知识产权引发了一个很有意义的研究方向:信息隐藏。本文首先介绍了了数字水印技术的原理和分类,接着对LSB算法原理及LSB算法实现进行了介绍,最后使用MATLAB 对其加密过程进行了仿真。

    3.2 数字水印技术的基本原理

    数字水印的主要目的是将特定的信息加入到需要保护的媒体信息中,加入的信息一般是能够代表媒体信息版权的内容,如公司标志、媒体作者、特定代码等,而且要保证数字水印能够抵抗一定的攻击,而不被轻易的破坏和修改,同时数字水印要能够被提取或者能够被检测到。数字水印的具体内容、算法、提取或检测过程根据实际应用有不同的要求。数字水印的嵌入和提取过程如图3.1,图3.2所示。

    图3.1 数字水印的嵌入过程

    图3.2 数字水印的提取过程

    图3.1是数字水印的嵌入过程,加入密钥可以提高数字水印的隐蔽性、抗攻击性,而并非是必须的。根据用途不同,嵌入的水印有些是需要还原的,而有些则只需验证水印的存在性,前者需要数字水印的提取算法,而图3.2需要数字水印的检测算法,根据具体的水印算法,嵌入或提取的过程可能有所不同。

    3.3数字水印的分类

    数字水印算法一般可分为两种空域法和频域法,频域法有以下优点:

    (1)嵌入的水印信号能量可以分布到空域的所有像素上,有利于保证水印的不可见 性;

    (2)视觉系统(HVS)的某些特性(如频率的掩蔽特性)可以更方便地结合到水印编码过程中;

    (3)频域法可与国际数据压缩标准兼容,从而实现在压缩域(compressed domain)内的水印编码。所以我们也以频域法为主介绍MATLAB在数字水印技术中的使用。

    按数字水印的特性可分为鲁捧数字水印和脆弱数字水印。鲁棒数字水印主要用于标识数字媒体信息的版权信息,它要求嵌入的水印能够抵抗对媒体的常规编辑和恶意攻击,在对媒体进行如:裁剪、旋转、缩放、压缩的变换后水印信息不受到较大损害。而脆弱水印相反,它对攻击敏感,可以根据脆弱水印的状态判断原始信息是否被修改过。

    按数字水印所附载的媒体可分为图像水印、音频水印、视频水印和文本水印等。每一种数字化的媒体都有相应的水印算法,这也造成了数字水印算法的复杂性。

    按数字水印隐藏的位置划分可以分为空 (时)域数字水印、频域数字水印、时/频域数字水印和时间/度数字水印。原始信息通常在空域或者时域上表示,根据信号处理理论有多种变换将信号变化到另外的域上,每一种域上都可以嵌入数字水 印,也就产生了相应的数字水印算法。

    按数字水印的可见性可以分为可见数字水印和非可见数字水印。可见数字水印通常是将公司表示叠加到原始图像上,算法比较简单,也有相应的应用软件,如Undreamt Marking Technologies公司的Photo Watermark。而不可见数字水印要求嵌入的水印是不能被人的视觉系统感知的,其算法相对复杂。

    关于数字水印算法的分类还有很多不同的分类方法,比如按用途划分,按检测过程划分等,限于篇幅,本文仅介绍了较为常见的基于空域的LSB算法。

    4设计内容

    4.1 LSB算法介绍

    LSB是一种简单传统的信息隐藏算法,属于数字水印技术中的一种。本文首先介绍了LSB技术的原理和特点,然后讨论了基于LSB的数字水印算法。最后利用MATLAB 2009 b对这一算法的加密过程进行了仿真。

    4.1.1 LSB算法的基本原理

    对空域的LSB做替换,用来替换LSB的序列就是需要加入的水印信息、水印的数字摘要或者由水印生成的伪随机序列。由于水印信息嵌入的位置是LSB,为了满足水印的不可见性,允许嵌入的水印强度不可能太高。然而针对空域的各种处理,如游程编码前的预处理,会对不显著分量进行一定的压缩,所以LSB算法对这些操作很敏感。因此LSB算法最初是用于脆弱性水印的。

    4.1.2 LSB算法基本步骤

    (1) 将得到的隐藏有秘密信息的十进制像素值转换为二进制数据.

    (2) 用二进制秘密信息中的每一比特信息替换与之相对应的载体数据的最低有效位.

    (3)将得到的含秘密信息的二进制数据转换为十进制像素值,从而获得含秘密信息的图像.

    4.2 LSB算法的实现

    LSB算法实现较为简单,首先,需要考虑嵌入的数字水印的数据量,如果嵌入最低的1位,则可以嵌入的信息量是原始图像信息量的1/8,如果适用最低两位则可以嵌入的信息量是1/4。但是嵌入的数字水印的信息量越大,同时对图像的视觉效果影响也越大。在这里要嵌入一个二值的图像。然后,适当调整数字水印图像的大小和比特位数,以适应数字水印图像数据量的要求。最后,对原始图像中要使用的最低位置0,再将数字水印数据放人原始图像的最低位即可。下面通过MATLAB 2009 b2实现这一算法。

    这里选用一幅3264*2448像素,256灰度的图像,数字水印用“万泉公园”的字样的二值图像。

    置0的方法是调用模2函数mod(a,2),将得到的数值与原水印相减,从而得到最低位为0的图片。(使用两位最低有效位的话则用模4函数mod(a,4)然后相减)。LSB算法简单,实现容易,同时可以保证数字水印的不可见性,由于可以在最低位的每个像素上都插人数字水印信息,因此有较大的信息嵌入量。LSB算法一般嵌入图像的最低一位或者两位,如果嵌入的位数太多,则会被人眼察觉到。但是由于数字水印位于图像的不重要像素位上,因此很容易被图像过滤、量化和几何型变等操作破坏,以致无法恢复数字水印。针对基本的LSB算法的缺点,一些研究者也提出了一些改进的算法,如奇偶标识位隐藏算法、索引数据链隐藏算法等,这些算法能增强数字水印的隐蔽性。

    4.3设计流程图

    4.3.1水印嵌入的流程图


    图4.1 水印嵌入的流程图

    4.3.2水印提取的流程图

    读取带有水印的图像和水印图像

    得到嵌入的水印

    图4.2水印提取的流程图


    5程序源代码

    1. 嵌入水印代码

    clear all;

    % 保存开始时间

    start_time=cputime;

    % 读入原图像

    file_name='E:\1.BMP;

    [cover_object,map]=imread(file_name);

    % 读入水印图像

    file_name='E:\2.BMP';

    [message,map1]=imread(file_name);

    message1=message;

    message=double(message); %%转换为double数

    message=fix(message./2); %%转换为0,1组成的矩阵

    message=uint8(message); %%转换为uint8数

    % 原图的行数与列数

    Mc=size(cover_object,1); %原图的行数

    Nc=size(cover_object,2); %原图的列数

    % 水印的行数与列数

    Mm=size(message,1); %水印的行数

    Nm=size(message,2); %水印的列数

    % 将水印扩展为原图像大小,并写入watermark

    for ii = 1:Mc

    for jj = 1:Nc

    watermark(ii,jj)=message(mod(ii,Mm)+1,mod(jj,Nm)+1);

    % 用mod函数进行求余处理

    end

    end

    % 将原图的最低有效位值换为水印的值

    watermarked_image=cover_object;

    for ii = 1:Mc

    for jj = 1:Nc

    watermarked_image(ii,jj)=bitset(watermarked_image(ii,jj),1,watermark(ii,jj));

    % 用bitset函数将原图的最低有效位值换为水印的值

    end

    end

    % 将嵌入水印图像写入lsb_watermarked.bmp

    imwrite(watermarked_image,'lsb_watermarked.bmp','bmp');

    % 显示运行时间

    elapsed_time=cputime-start_time,

    % 显示嵌入水印图像

    figure(1);

    subplot(1,2,1);

    imshow(watermarked_image,[]);

    title('嵌入水印图像');

    subplot(1,2,2);

    imshow(cover_object,[]);

    title('原图像');


    %%扩展后水印

    for ii = 1:Mc

    for jj = 1:Nc

    watermark1(ii,jj)=message1(mod(ii,Mm)+1,mod(jj,Nm)+1);

    %用mod函数对水印进行扩展

    end

    end

    %显示结果

    figure(2);subplot(1,2,1);

    imshow(watermark1,[]);

    title('扩展后的水印');

    figure(2);subplot(1,2,2);

    imshow(message1,[]);

    title('原水印');


    (2) 水印的提取过程


    clear all;

    % 保存开始时间

    start_time=cputime;

    % 读入嵌入水印图像

    file_name='lsb_watermarked.bmp';

    watermarked_image=imread(file_name);

    % 嵌入水印图像的行数与列数

    Mw=size(watermarked_image,1);%嵌入水印图像行数

    Nw=size(watermarked_image,2);%嵌入水印图像列数

    %读入原始水印

    file_name='E:\2.BMP';

    orig_watermark=imread(file_name);

    %%原始水印的行数与列数

    Mm=size(orig_watermark,1); %水印的行数

    Nm=size(orig_watermark,2); %水印的列数

    % 用嵌入水印图像的最低有效位重建水印

    for ii = 1:Mw

    for jj = 1:Nw

    watermark(ii,jj)=bitget(watermarked_image(ii,jj),1);

    % 用bitget函数重建水印

    end

    end

    % 将提取水印变为原始水印大小

    watermark=2*double(watermark);

    for ii = 1:Mm-1

    for jj = 1:Nm-1

    watermark1(ii+1,jj+1)=watermark(ii,jj);

    end

    end

    watermark1(1,1)=watermark(Mm,Nm);

    % 显示运行时间

    elapsed_time=cputime-start_time,

    % 显示嵌入水印图像,提取水印以及原始水印

    figure(1);

    subplot(1,2,1);

    imshow(watermarked_image,[]);

    title('嵌入水印图像');

    figure(2);

    subplot(1,2,1);

    imshow(watermark1,[]);

    title('提取水印');

    figure(2);

    subplot(1,2,2);

    imshow(orig_watermark,[]);

    title('原始水印');

    6仿真结果与分析

    6.1 嵌入水印后的运行结果

    (1) 根据水印嵌入算法及显示函数,得出原图像和嵌入水印后的图像,如图6.1



    v2-4cbacf2b34a3ba592e9c03a3b32d723c_b.jpg

    图6.1 原图像和嵌入水印后的图像











    (2) 将要嵌入到图像中的水印显示出来,如图6.2



    v2-7fbfbff15e8364caea2dee76d6639285_b.jpg

    图6.2 原水印的图像

    6.2 提取水印后的运行结果

    (1) 将水印通过嵌入算法嵌入到图像中,并将嵌入水印的图像写入到temp.jpg中,嵌入水印的图像如图6.3



    v2-a426b4e172054f238e0a8fd7b7dd96e2_b.jpg

    图6.3 嵌入水印的图像


    (2)通过提取水印的过程算法将水印从原图像中提取出来,如图6.4


    v2-ad63f7f9efadee8ef0b6bc1bb12443ee_b.jpg

    图6.4 原水印与提取的水印图像

    6.3 结果分析

    (1)嵌入水印后的运行结果

    结果图如上图6.1和图6.2,图6.1表示的是原图像和嵌入水印后的结果图像,图 6.2表示的是原水印和扩展后的水印的结果图像。通过图示显示,可知LSB算法的实现简单和保证水印的不可见性.

    (2)提取水印后的运行结果

    结果图如上图6.3和图6.4,图6.3表示的是嵌入水印的原图像,图6.4 表示的是原水印与提取的水印的图像。通过图示显示,正确的提取中水印,但是水印有一定的模糊性.

    7结论语

    通过本次的设计,理解到了水印的嵌入和提取的过程,了解到水印的用处和价值,在以后的实际生活中也可以采用LSB算法实现水印的嵌入.可以起到图像版权或者防止篡改的保护性.

    本设计采用的是基于空域的水印实现,通过LSB算法实现起来比较简单,同时可以保证数字水印的不可见性.

    但是在实践的课程中,发现如果嵌入的位数太多,则会被人眼察觉到。但是由于数字水印位于图像的不重要像素位上,因此很容易被图像过滤、量化和几何型变等操作破坏,以致无法恢复数字水印.所以通常可采用一些增强数字水印的隐蔽性的算法.如奇偶标识位隐藏算法、索引数据链隐藏算法等,从而使水印的隐蔽性更高.


    8参考文献

    [1] 林福宗.多媒体技术基础(第2版)课程设计与学习指导[M]. 北京:清华大学出版社, 2006

    [2] 姚敏.数字图像处理[M]. 北京:机械工业出版社,2006

    [3] 容观澳.计算机图像处理. 北京:清华大学出版社,2000

    [4] 周新伦.数字图像处理. 北京:国防工业出版社,2006

    [5] 吴健康.数字图像处理. 北京:邮电大学出版社,1989

    [6] 王积分.计算机图像识别. 北京:中国铁道出版社,1988

    [7] 贾永红.计算机图像处理与分析. 武汉:武汉大学出版社,2001

    [8] 陈桂明.应用MATLAB语言处理数信号与图像处理.北京:科学出版社,2000

    [9] 徐建华.图像处理与分析. 上海:上海交通大学出版社,1990

    [10] 王润生.图像理解. 北京:国防科技大学出版社,1995

    [11] 姚敏.数字图像处理. 北京:机械工业出版社,2006

    展开全文
  • 将全息数字水印技术应用于防伪印刷无需添加任何新的材料,对设备和工艺也没有特殊的要求,同时还可提高水印的不可见性,其操作性较强。综述了空间域和变换域2类全息数字水印算法的研究现状,提出了现有全息数字水印方案...
  • 分析了一维和二维DCT变换的原理,分析了DCT变换域的数字水印技术中DCT变换系数的选择依据,重点研究了DCT变换域的数字水印嵌入与提取方法,并且利 用VC++进行编程验证,实验测试表明,基于DCT变换域的数字水印技术...
  • 用于重要电子文件保护的数字水印和数字指纹算法研究.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,030
精华内容 1,212
关键字:

不可见数字水印