易损水印的实现 java

数字水印的易损水印的java实现,网上找了好久都没找着。
易损水印: *
原理就是,将图片像素分割成8x8的子模块。每个子模块进行一次dct变换,
变换之后,根据信号,对比第62与63位。如果信号为1则 使得63>62,如果信号为0则使得62>63.
最后再进行一次反DCT变换,就完成了一个子模块的操作,将子模块的像素值与原原子模块交换。
一个信号就需要一个子模块,将所有信号操作完成后,信号就完全嵌入到了图片中了。
预先处理:
将需要嵌入图片的信息进行处理:
message------md5(数字摘要)-----sign(RSA)—(转换成二进制)------二进制签名信息
将图片进行处理:
图片-----提取像素----->BufferedImage bimage=ImageIO.read(file);
因为图片是分RGB三层,因此要选择一层来作为你的操作像素:

		//path,图片的地址
		public static int[][] getPixels(String path){ 
			File file =new File(path);
			int[] rgb=new int[3];
			try {
				BufferedImage bimage=ImageIO.read(file);
				int[][] RPixels=new int[bimage.getWidth()][bimage.getHeight()];
				int minX=bimage.getMinX();
				int minY=bimage.getMinY();
				for(int i=minX;i<bimage.getWidth();i++){
					for(int j=minY;j<bimage.getHeight();j++){
						int p=bimage.getRGB(i, j);
						rgb[0] = (p & 0xff0000) >> 16;
						rgb[1] = (p & 0xff00) >> 8;
						rgb[2] = (p & 0xff);
						RPixels[i][j]=rgb[0];
					}
				}
				return RPixels;
			} catch (IOException e) {
				e.printStackTrace();
				return null;
			} 
		}

下面是易损水印的实现。

		/**@param imagePath:需要处理的图片地址
		 * @param sign:转为二进制信号后的签名信息
		 * */
		public void createWaterMark(String imagePath,int[][] sign){
			int[][]data=getPixels(imagePath);
			int tag=0;
			int h=0;
			double[][] data2=MathTool.intToDoubleMatrix(data);
			double[][]result2=data2;
			for(int i=0;i<sign.length;i++){
				for(int j=0;j<sign[i].length;j++){
		    		double[][] blk=new double[8][8];
		    		if(tag*8+8>data[h].length){
		    			tag=0;
		    			h++;
		    		}
		    		for(int n=0;n<8;n++){    //将像素分割成8*8的子块
	    				for(int m=0;m<8;m++){	
	    					blk[n][m]=data[8*h+n][8*tag+m];
	    				}
		    		}	
		    	
		    		double[][] fblk=FDct.fDctTransform(blk); //DCT变换
		    	  
		    	 if(sign[i][j]==1&&fblk[7][5]<fblk[7][6]){
		    		 double temp=fblk[7][6];
		    			fblk[7][6]=fblk[7][5];
		    			fblk[7][5]=temp;
		    		}else if(sign[i][j]==1&&fblk[7][5]==fblk[7][6]){
		    			fblk[7][6]-=3;
		    		}else if(sign[i][j]==0&&fblk[7][5]>fblk[7][6]){
		    			 double temp=fblk[7][6];
		    			fblk[7][6]=fblk[7][5];
		    			fblk[7][5]=temp;
		    		}else if(sign[i][j]==0&&fblk[7][5]==fblk[7][6]){
		    			fblk[7][6]+=3;
		    		} 
					blk=IFDct.iFDctTransform(fblk);;	 //反 DCT变换	
					for(int n=0;n<8;n++){    //将嵌入信息后的子块放进原图
						for(int m=0;m<8;m++){
							result2[8*h+n][8*tag+m]=blk[n][m];
						}
					}
					tag++;
			}
		}
		File file =new File(imagePath);
		int[] rgb=new int[3];
		try {
			BufferedImage bimage=ImageIO.read(file);
			BufferedImage newImage=new BufferedImage(bimage.getWidth(),bimage.getHeight(),bimage.getType());
			int minX=bimage.getMinX();
			int minY=bimage.getMinY();
			for(int i=minX;i<bimage.getWidth();i++){
				for(int j=minY;j<bimage.getHeight();j++){
					int p=bimage.getRGB(i, j);
					rgb[0] = (p & 0xff0000) >> 16;
					rgb[1] = (p & 0xff00) >> 8;
					rgb[2] = (p & 0xff);
					Color myColor=new Color((int)result2[i][j],rgb[1],rgb[2] );
					int newRGB=myColor.getRGB();	  
					newImage.setRGB(i, j, newRGB);	
				}
			}
			File file2=new File("D://sign.png");
			ImageIO.write(newImage, "png", file2); 
		}catch (IOException e) {
			e.printStackTrace();
		} 	 
		}

最后:
经过DCT变换后可能会出现越界问题。因为像素取值在[0-255],dct变换会使得有些数超越255这个值或低于0.
因此可以使用归一法对数据进行归一到[0-255]这个区间 这是不可以的,归一法会有误差。
最后,我自己的解决是 在提取图片像素的时候,将处于[255-253] /[0-3]这个区间的数进行缩小和放大。这样一般不会出现越界。
像素越界一般出现在黑白图片里。因为黑色和白色就是0/255.

如果有人有更好解决这个问题,请告知,谢谢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值