您的位置:首页 > 编程语言 > Java开发

Java实现【快速离散余弦变换FDCT】参考:《图像数字水印的JAVA实现 刘剑鸣 著》

2012-02-20 21:55 357 查看
原始图片:



水印图片:



嵌入水印后的图片:



提取出来的水印图片:



工具类:ImageUtil.java    MathTool.java

package com.zeph.watermark.util;

public class MathTool {
public static double[][] intToDoubleMatrix(int[][] input) {
int height = input.length;
int width = input[0].length;
double[][] output = new double[height][width];
for (int i = 0; i < height; i++) {
// 列
for (int j = 0; j < width; j++) {
// 行
output[i][j] = Double.valueOf(String.valueOf(input[i][j]));
System.out.print(output[i][j]);
}
System.out.println();
}
return output;
}

public static double[] intToDoubleArray(int[] input) {
int length = input.length;
double[] output = new double[length];
for (int i = 0; i < length; i++)
output[i] = Double.valueOf(String.valueOf(input[i]));
return output;
}

public static void main(String[] args) {
int[][] test = { { 4, 5, 6 }, { 1, 2, 3 } };
MathTool.intToDoubleMatrix(test);
}
}

package com.zeph.watermark.util;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class ImageUtil {
/**
* 获取图片
*
* @param filepath
* @return
*/
public static BufferedImage getImage(String filepath) {
BufferedImage image = null;
File file = new File(filepath);
try {
image = ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
return image;
}

/**
* 获取图像文件的像素(图片转换为像素)
*
* @param filepath
* @param format
*/
public int[] getImagePixels(String filepath) {
BufferedImage image = null;
File file = new File(filepath);
try {
image = ImageIO.read(file);
} catch (IOException e) {
e.printStackTrace();
}
WritableRaster raster = image.getRaster();
// 得到图像的宽度
int width = raster.getWidth();
// 得到图像的高度
int height = raster.getHeight();
// RGB格式图像文件每一个点的颜色由红、绿、兰三种颜色构成,即实际图像可为3层,
// 分别为R,G,B层,因此分解后的文件象素是实际坐标高度和宽度的三倍。
int[] pixels = new int[3 * width * height];
// 读取坐标的范围是从(0,0)坐标开始宽width,高height
raster.getPixels(0, 0, width, height, pixels);
return pixels;
}

/**
* 像素转换成图像文件
*
* @param result
* @param width
* @param height
* @param filepath
* @param format
*/
public static void setImage(double[] result, int width, int height,
String filepath, String format, int type) {
BufferedImage outImage = new BufferedImage(width, height, type);
WritableRaster outRaster = outImage.getRaster();
outRaster.setPixels(0, 0, width, height, result);
// 图像文件的写入
File outFile = new File(filepath);
try {
ImageIO.write(outImage, format, outFile);
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 一维数组转为二维数组
*
* @param m
* @param width
* @param height
* @return
*/
public static int[][] arrayToMatrix(int[] m, int width, int height) {
int[][] result = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int p = j * height + i;
result[i][j] = m[p];
}
}
return result;
}

/**
* 一维数组转换为三维数组
*
* @param pixels
* @param width
* @param height
* @return
*/
public static int[][][] getRGBArrayToMatrix(int[] pixels, int width,
int height) {
// 已知有3个二维数组组成分别代表RGB
int[][][] result = new int[3][height][width];
int[][] temp = new int[3][width * height];
for (int i = 0; i < pixels.length; i++) {
int m = i / 3;
int n = i % 3;
temp
[m] = pixels[i];
}
result[0] = arrayToMatrix(temp[0], width, height);
result[1] = arrayToMatrix(temp[1], width, height);
result[2] = arrayToMatrix(temp[2], width, height);
return result;
}

/**
* 二维数组转为一维数组
*
* @param m
* @return
*/
public static double[] matrixToArray(double[][] m) {
int p = m.length * m[0].length;
double[] result = new double[p];
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[i].length; j++) {
int q = j * m.length + i;
result[q] = m[i][j];
}
}
return result;
}

/**
* 三维数组转为一维数组
*
* @param m
* @return
*/
public static double[] getRGBMatrixToArray(double[][][] m) {
int width = m[0].length;
int height = m[0][0].length;
int len = width * height;
double[] result = new double[3 * len];
double[][] temp = new double[3][len];
temp[0] = matrixToArray(m[0]);
temp[1] = matrixToArray(m[1]);
temp[2] = matrixToArray(m[2]);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < temp[i].length; j++)
result[3 * j + i] = temp[i][j];
}
return result;
}
}

实现类:Dct.java    FDct.java    IFDct.java    AddWatermark.java    ExtractWatermark.java

package com.zeph.watermark.fdct;

public interface Dct {
static double C1 = 0.98078528, C2 = 0.923879532, C3 = 0.831469612,
C4 = 0.707106781, C5 = 0.555570233, C6 = 0.382683432,
C7 = 0.195090322;
}

package com.zeph.watermark.fdct;

public class FDct implements Dct {
public static double[][] fDctTransform(double[][] ablk) {
double[][] blk = new double[8][8];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
blk[i][j] = ablk[i][j];
}
}
// 对行变换
for (int i = 0; i <= 7; i++) {
double S07, S16, S25, S34, S0734, S1625;
double D07, D16, D25, D34, D0734, D1625;
S07 = blk[i][0] + blk[i][7];
S16 = blk[i][1] + blk[i][6];
S25 = blk[i][2] + blk[i][5];
S34 = blk[i][3] + blk[i][4];
S0734 = S07 + S34;
S1625 = S16 + S25;
D07 = blk[i][0] - blk[i][7];
D16 = blk[i][1] - blk[i][6];
D25 = blk[i][2] - blk[i][5];
D34 = blk[i][3] - blk[i][4];
D0734 = S07 - S34;
D1625 = S16 - S25;
blk[i][0] = 0.5 * (C4 * (S0734 + S1625));
blk[i][1] = 0.5 * (C1 * D07 + C3 * D16 + C5 * D25 + C7 * D34);
blk[i][2] = 0.5 * (C2 * D0734 + C6 * D1625);
blk[i][3] = 0.5 * (C3 * D07 - C7 * D16 - C1 * D25 - C5 * D34);
blk[i][4] = 0.5 * (C4 * (S0734 - S1625));
blk[i][5] = 0.5 * (C5 * D07 - C1 * D16 + C7 * D25 + C3 * D34);
blk[i][6] = 0.5 * (C6 * D0734 - C2 * D1625);
blk[i][7] = 0.5 * (C7 * D07 - C5 * D16 + C3 * D25 - C1 * D34);
}
// 对列变换
for (int j = 0; j <= 7; j++) {
double S07, S16, S25, S34, S0734, S1625;
double D07, D16, D25, D34, D0734, D1625;
S07 = blk[0][j] + blk[7][j];
S16 = blk[1][j] + blk[6][j];
S25 = blk[2][j] + blk[5][j];
S34 = blk[3][j] + blk[4][j];
S0734 = S07 + S34;
S1625 = S16 + S25;
D07 = blk[0][j] - blk[7][j];
D16 = blk[1][j] - blk[6][j];
D25 = blk[2][j] - blk[5][j];
D34 = blk[3][j] - blk[4][j];
D0734 = S07 - S34;
D1625 = S16 - S25;
blk[0][j] = 0.5 * (C4 * (S0734 + S1625));
blk[1][j] = 0.5 * (C1 * D07 + C3 * D16 + C5 * D25 + C7 * D34);
blk[2][j] = 0.5 * (C2 * D0734 + C6 * D1625);
blk[3][j] = 0.5 * (C3 * D07 - C7 * D16 - C1 * D25 - C5 * D34);
blk[4][j] = 0.5 * (C4 * (S0734 - S1625));
blk[5][j] = 0.5 * (C5 * D07 - C1 * D16 + C7 * D25 + C3 * D34);
blk[6][j] = 0.5 * (C6 * D0734 - C2 * D1625);
blk[7][j] = 0.5 * (C7 * D07 - C5 * D16 + C3 * D25 - C1 * D34);
}
return blk;
}
}

package com.zeph.watermark.fdct;

public class IFDct implements Dct {
public static double[][] iFDctTransform(double[][] ablk) {
double[][] blk = new double[8][8];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
blk[i][j] = ablk[i][j];
}
}
// 对列做IDCT
for (int j = 0; j <= 7; j++) {
double[] tmp = new double[16];
// first step
tmp[0] = blk[0][j] * C4 + blk[2][j] * C2;
tmp[1] = blk[4][j] * C4 + blk[6][j] * C6;
tmp[2] = blk[0][j] * C4 + blk[2][j] * C6;
tmp[3] = -blk[4][j] * C4 - blk[6][j] * C2;
tmp[4] = blk[0][j] * C4 - blk[2][j] * C6;
tmp[5] = -blk[4][j] * C4 + blk[6][j] * C2;
tmp[6] = blk[0][j] * C4 - blk[2][j] * C2;
tmp[7] = blk[4][j] * C4 - blk[6][j] * C6;
tmp[8] = blk[1][j] * C7 - blk[3][j] * C5;
tmp[9] = blk[5][j] * C3 - blk[7][j] * C1;
tmp[10] = blk[1][j] * C5 - blk[3][j] * C1;
tmp[11] = blk[5][j] * C7 + blk[7][j] * C3;
tmp[12] = blk[1][j] * C3 - blk[3][j] * C7;
tmp[13] = -blk[5][j] * C1 - blk[7][j] * C5;
tmp[14] = blk[1][j] * C1 + blk[3][j] * C3;
tmp[15] = blk[5][j] * C5 + blk[7][j] * C7;
// second step
tmp[0] = 0.5 * (tmp[0] + tmp[1]);
tmp[1] = 0.5 * (tmp[2] + tmp[3]);
tmp[2] = 0.5 * (tmp[4] + tmp[5]);
tmp[3] = 0.5 * (tmp[6] + tmp[7]);
tmp[4] = 0.5 * (tmp[8] + tmp[9]);
tmp[5] = 0.5 * (tmp[10] + tmp[11]);
tmp[6] = 0.5 * (tmp[12] + tmp[13]);
tmp[7] = 0.5 * (tmp[14] + tmp[15]);
// third step
blk[0][j] = tmp[0] + tmp[7];
blk[1][j] = tmp[1] + tmp[6];
blk[2][j] = tmp[2] + tmp[5];
blk[3][j] = tmp[3] + tmp[4];
blk[4][j] = tmp[3] - tmp[4];
blk[5][j] = tmp[2] - tmp[5];
blk[6][j] = tmp[1] - tmp[6];
blk[7][j] = tmp[0] - tmp[7];
}
// 对行做IDCT
for (int i = 0; i <= 7; i++) {
double[] tmp = new double[16];
// first step
tmp[0] = blk[i][0] * C4 + blk[i][2] * C2;
tmp[1] = blk[i][4] * C4 + blk[i][6] * C6;
tmp[2] = blk[i][0] * C4 + blk[i][2] * C6;
tmp[3] = -blk[i][4] * C4 - blk[i][6] * C2;
tmp[4] = blk[i][0] * C4 - blk[i][2] * C6;
tmp[5] = -blk[i][4] * C4 + blk[i][6] * C2;
tmp[6] = blk[i][0] * C4 - blk[i][2] * C2;
tmp[7] = blk[i][4] * C4 - blk[i][6] * C6;
tmp[8] = blk[i][1] * C7 - blk[i][3] * C5;
tmp[9] = blk[i][5] * C3 - blk[i][7] * C1;
tmp[10] = blk[i][1] * C5 - blk[i][3] * C1;
tmp[11] = blk[i][5] * C7 + blk[i][7] * C3;
tmp[12] = blk[i][1] * C3 - blk[i][3] * C7;
tmp[13] = -blk[i][5] * C1 - blk[i][7] * C5;
tmp[14] = blk[i][1] * C1 + blk[i][3] * C3;
tmp[15] = blk[i][5] * C5 + blk[i][7] * C7;
// second step
tmp[0] = 0.5 * (tmp[0] + tmp[1]);
tmp[1] = 0.5 * (tmp[2] + tmp[3]);
tmp[2] = 0.5 * (tmp[4] + tmp[5]);
tmp[3] = 0.5 * (tmp[6] + tmp[7]);
tmp[4] = 0.5 * (tmp[8] + tmp[9]);
tmp[5] = 0.5 * (tmp[10] + tmp[11]);
tmp[6] = 0.5 * (tmp[12] + tmp[13]);
tmp[7] = 0.5 * (tmp[14] + tmp[15]);
// third step
blk[i][0] = tmp[0] + tmp[7];
blk[i][1] = tmp[1] + tmp[6];
blk[i][2] = tmp[2] + tmp[5];
blk[i][3] = tmp[3] + tmp[4];
blk[i][4] = tmp[3] - tmp[4];
blk[i][5] = tmp[2] - tmp[5];
blk[i][6] = tmp[1] - tmp[6];
blk[i][7] = tmp[0] - tmp[7];
}
return blk;
}

}

package com.zeph.watermark.fdct;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;

import com.zeph.watermark.util.ImageUtil;
import com.zeph.watermark.util.MathTool;

public class AddWatermark {
private static final int d = 5;

public static void main(String[] args) {
AddWatermark embed = new AddWatermark();
embed.start();
}

public void start() {
BufferedImage oImage = ImageUtil.getImage("D://lena.jpg");
BufferedImage wImage = ImageUtil.getImage("D://zhong.bmp");
int type = oImage.getType();
WritableRaster oRaster = oImage.getRaster();
WritableRaster wRaster = wImage.getRaster();
int oWidth = oRaster.getWidth();
int oHeight = oRaster.getHeight();
int wWidth = wRaster.getWidth();
int wHeight = wRaster.getHeight();
int[] oPixels = new int[3 * oWidth * oHeight];
int[] wPixels = new int[wWidth * wHeight];
oRaster.getPixels(0, 0, oWidth, oHeight, oPixels);
wRaster.getPixels(0, 0, wWidth, wHeight, wPixels);
int[][][] RGBPixels = ImageUtil.getRGBArrayToMatrix(oPixels, oWidth,
oHeight);
// 得到RGB图像的三层矩阵表示
double[][] rPixels = MathTool.intToDoubleMatrix(RGBPixels[2]);
int[][] wDMatrix = ImageUtil.arrayToMatrix(wPixels, wWidth, wHeight);
double[][] result = rPixels;
// 嵌入算法
for (int i = 0; i < wWidth; i++) {
for (int j = 0; j < wHeight; j++) {
double[][] blk = new double[8][8];
// 对原始图像8 * 8 分块
for (int m = 0; m < 8; m++) {
for (int n = 0; n < 8; n++) {
blk[m]
= rPixels[8 * i + m][8 * j + n];
}
}
double[][] dBlk = FDct.fDctTransform(blk);
if (wDMatrix[i][j] == 0) {
dBlk[3][3] = dBlk[3][3] - d;
dBlk[3][4] = dBlk[3][4] - d;
dBlk[3][5] = dBlk[3][5] - d;
dBlk[4][3] = dBlk[4][3] - d;
dBlk[5][3] = dBlk[5][3] - d;
} else {
dBlk[3][3] = dBlk[3][3] + d;
dBlk[3][4] = dBlk[3][4] + d;
dBlk[3][5] = dBlk[3][5] + d;
dBlk[4][3] = dBlk[4][3] + d;
dBlk[5][3] = dBlk[5][3] + d;
}
blk = IFDct.iFDctTransform(dBlk);
for (int m = 0; m < 8; m++) {
for (int n = 0; n < 8; n++) {
result[8 * i + m][8 * j + n] = blk[m]
;
}
}
}
}
double[][][] temp = new double[3][oWidth][oHeight];
temp[0] = MathTool.intToDoubleMatrix(RGBPixels[0]);
temp[1] = MathTool.intToDoubleMatrix(RGBPixels[1]);
temp[2] = result;
double[] rgbResult = ImageUtil.getRGBMatrixToArray(temp);
// 将BufferedImage对象写入磁盘
ImageUtil.setImage(rgbResult, oWidth, oHeight, "D://result.bmp",
"bmp", type);
}

}

package com.zeph.watermark.fdct;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;

import com.zeph.watermark.util.ImageUtil;
import com.zeph.watermark.util.MathTool;

public class ExtractWatermark {
public static void main(String[] args) {
ExtractWatermark distill = new ExtractWatermark();
distill.start(32, 32);
}

public void start(int wWidth, int wHeight) {
// mImage是嵌入水印后的图像
BufferedImage mImage = ImageUtil.getImage("D://result.bmp");
// 原始图像
BufferedImage oImage = ImageUtil.getImage("D://lena.jpg");
WritableRaster oRaster = oImage.getRaster();
WritableRaster mRaster = mImage.getRaster();
int oWidth = oRaster.getWidth();
int oHeight = oRaster.getHeight();
int[] oPixels = new int[3 * oWidth * oHeight];
int[] mPixels = new int[3 * oWidth * oHeight];
oRaster.getPixels(0, 0, oWidth, oHeight, oPixels);
mRaster.getPixels(0, 0, oWidth, oHeight, mPixels);
// 得rgb图像三层矩阵,mRgbPixels[0]表示b层分量
int[][][] mRgbPixels = ImageUtil.getRGBArrayToMatrix(mPixels, oWidth,
oHeight);
int[][][] oRgbPixels = ImageUtil.getRGBArrayToMatrix(oPixels, oWidth,
oHeight);
double[][] oDPixels = MathTool.intToDoubleMatrix(mRgbPixels[2]);
double[][] mDPixels = MathTool.intToDoubleMatrix(oRgbPixels[2]);
double[][] result = new double[wWidth][wHeight];
for (int i = 0; i < wWidth; i++) {
for (int j = 0; j < wHeight; j++) {
double[][] oBlk = new double[8][8];
double[][] mBlk = new double[8][8];
int d = 0;
int f = 0;
for (int m = 0; m < 8; m++) {
for (int n = 0; n < 8; n++) {
oBlk[m]
= oDPixels[8 * i + m][8 * j + n];
mBlk[m]
= mDPixels[8 * i + m][8 * j + n];
}
}
double[][] dOBlk = FDct.fDctTransform(oBlk);
double[][] dMBlk = FDct.fDctTransform(mBlk);
if (dOBlk[3][3] > dMBlk[3][3]) {
d++;
} else {
f++;
}
if (dOBlk[3][4] > dMBlk[3][4]) {
d++;
} else {
f++;
}
if (dOBlk[3][5] > dMBlk[3][5]) {
d++;
} else {
f++;
}
if (dOBlk[4][3] > dMBlk[4][3]) {
d++;
} else {
f++;
}
if (dOBlk[5][3] > dMBlk[5][3]) {
d++;
} else {
f++;
}
if (d < f) {
result[i][j] = 0;
} else {
result[i][j] = 1;
}
}
}
double[] outResult = ImageUtil.matrixToArray(result);
// 把嵌入水印的结果写到BufferedImage对象
ImageUtil.setImage(outResult, wWidth, wHeight, "D://mark.bmp", "bmp",
BufferedImage.TYPE_BYTE_BINARY);
}

}


程序的实现参考:刘剑鸣  著 《图像数字水印的JAVA实现》

书中没有给出完整的程序示例,在这里,我将它补充和修改,将程序调试成功。
程序算法是针对指定的图片,也就是非盲性图片的水印算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java c output string image file
相关文章推荐