Java实现可移除图像可见加密水印

算法说明

实验选取一种典型的Logistic 混沌序列,如下:

x n + 1 = λ x n ( 1 − x n ) , x n ∈ [ 0 , 1 ] x_{n+1}= \lambda x_{n}\left ( 1-x_{n} \right ),x_{n}\in [0,1] xn+1=λxn(1xn),xn[0,1]
其中 3.569946 … ≤ λ ≤ 4 , 0 < x n < 1 3.569946… \leq \lambda \leq 4 , 0 < x_{n} < 1 3.569946λ40<xn<1

可见水印嵌入过程:

  • 步骤1:打开原图像I、二值可见水印图像W
  • 步骤2:输入密钥key,利用logistic映射由密钥key生成二值混沌序列P。
  • 步骤3:在图像I中嵌入可见水印W,
  • 步骤4:将P与W进行异或生成加密水印序列W1。
  • 步骤5:将加密水印信号W1按比特位依次嵌入到数字图像I 的LSB中去,得到含水印图像 。

可见水印去除过程:

基本是水印嵌入逆过程。

  • 步骤1:打开含水印图像 。
  • 步骤2:输入密钥key,利用logistic映射由密钥key生成二值混沌序列P。
  • 步骤3:含水印图像 的LSB中提取加密水印信号W1。
  • 步骤4:将P与W1进行异或得到序列W。
  • 步骤5:根据以下策略去除水印,恢复原图像。

效果图

原图
原图
水印图
水印图
加了水印的图
加了水印的图
密码正确移除水印的图
密码正确移除水印的图

密码不正确移除水印的图
密码不正确的图

代码

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        File I=new File("C:\\Users\\Coyamo\\Desktop\\raw.bmp");
        File W=new File("C:\\Users\\Coyamo\\Desktop\\mark1.bmp");
        File IW=new File("C:\\Users\\Coyamo\\Desktop\\out.bmp");
        File NI=new File("C:\\Users\\Coyamo\\Desktop\\lena_new.bmp");
        int pwd=1234;
        encode(I,W,pwd,IW);
        decode(IW,pwd,NI);
    }

	//加密
    public static void encode(File I,File W,int pwd,File IW){
        float x0;
        float u = 4f;
        x0 = (pwd % 10000) * 0.0001f;
        try {
            BufferedImage imageI = ImageIO.read(I);
            BufferedImage imageW = ImageIO.read(W);
            int widthI = imageI.getWidth(),
                    heightI = imageI.getHeight();
            int sizeI=widthI*heightI;
            //
            float[] x = new float[sizeI];
            x[0] = x0;
            for (int i = 0; i < 500; i++)
                x[0] = u * x[0] * (1 - x[0]);
            for (int i = 0; i < sizeI - 1; i++)
                x[i + 1] = u * x[i] * (1 - x[i]);

            //gray w
            int grayW[]=new int[sizeI];
            int avg=0;
            for(int i=0;i<widthI;i++){
                for(int j=0;j<heightI;j++){
                    int color=imageW.getRGB(i, j);
                    int r = (color >> 16) & 0xff;
                    int g = (color >> 8) & 0xff;
                    int b = color & 0xff;
                    grayW[j*heightI+i]= (r*30+g*60+b*10)/100;
                    avg+=grayW[j*heightI+i];
                }
            }
            avg=avg/sizeI;
			//水印转化二值图像插入
            int rgb[]=new int[sizeI];
            for(int i=0;i<widthI;i++){
                for(int j=0;j<heightI;j++){
                    int gray= grayW[j*heightI+i]>avg?0:1;
                    int color=imageI.getRGB(i, j);
                    int r = (color >> 16) & 0xff;
                    int g = (color >> 8) & 0xff;
                    int b = color & 0xff;
                    if(gray==1){
                        rgb[j*heightI+i]=(255-r)<<16|(255-g)<<8|(255-b);
                    }else{
                        rgb[j*heightI+i]=color;
                    }

                    rgb[j*heightI+i]=rgb[j*heightI+i]&0xfffffffe|(gray^(int)(x[j*heightI+i]+0.5f));

                }
            }

            BufferedImage image = new BufferedImage(widthI, heightI, imageI.getType());
            image.setRGB(0, 0, widthI, heightI, rgb, 0, widthI);
            String suffix = I.getName().substring(I.getName().lastIndexOf('.') + 1);
            ImageIO.write(image, suffix, IW);
            image.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void decode(File IW,int pwd,File I){
        float x0;
        float u = 4f;
        x0 = (pwd % 10000) * 0.0001f;

        try {
            BufferedImage imageIW = ImageIO.read(IW);
            int widthIW = imageIW.getWidth(),
                    heightIW = imageIW.getHeight();
            int sizeIW=widthIW*heightIW;
            
            float[] x = new float[sizeIW];
            x[0] = x0;
            for (int i = 0; i < 500; i++)
                x[0] = u * x[0] * (1 - x[0]);
            for (int i = 0; i < sizeIW - 1; i++)
                x[i + 1] = u * x[i] * (1 - x[i]);

            int W[]=new int[sizeIW];
            for(int i=0;i<widthIW;i++){
                for(int j=0;j<heightIW;j++){
                    int color=imageIW.getRGB(i, j);
                    W[j*heightIW+i]=(color&1)^(int)(0.5+x[j*heightIW+i]);
                }
            }
            int rgb[]=new int[sizeIW];
            for(int i=0;i<widthIW;i++){
                for(int j=0;j<heightIW;j++){
                    int gray= W[j*heightIW+i];
                    int color=imageIW.getRGB(i, j);
                    int r = (color >> 16) & 0xff;
                    int g = (color >> 8) & 0xff;
                    int b = color & 0xff;
                    if(gray==1){
                        rgb[j*heightIW+i]=(255-r)<<16|(255-g)<<8|(255-b);
                    }else{
                        rgb[j*heightIW+i]=color;
                    }
                }
            }

            BufferedImage image = new BufferedImage(widthIW, heightIW, imageIW.getType());
            image.setRGB(0, 0, widthIW, heightIW, rgb, 0, widthIW);
            String suffix = I.getName().substring(I.getName().lastIndexOf('.') + 1);
            ImageIO.write(image, suffix, I);
            image.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

总结

算法主要是为图像打上加密的水印,水印信息就保存在图像像素的最低位。要完全移除则需要知道密码。代码实现的要求水印和图像一样大小。算法安全性并不高,可能出现密码不正确,却移除大部分水印的情况。理想情况下密码错误是不能移除水印的。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值