CopyMove.ImageMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of image-forensics Show documentation
Show all versions of image-forensics Show documentation
A library of image forensics algorithms for tampering localization.
The newest version!
package CopyMove;
import Utils.Util;
import java.awt.*;
import java.awt.image.BufferedImage;
/**
* Wrapper/Helper for Masked RGB BufferedImage
*
* @author Xavier Philippeau
*
*/
public class ImageMap {
// image data
private BufferedImage image;
public final int W,H;
// the maximum value returned by MaskedImage.distance()
public static final int DSCALE = 65535;
// array for converting distance to similarity
public static final double[] similarity;
static {
// build similarity curve such that similarity[0%]=0.999 and similarity[4%]=0.5
double s_zero=0.999;
double t_halfmax=0.10;
double x = (s_zero-0.5)*2;
double invtanh = 0.5*Math.log((1+x)/(1-x));
double coef = invtanh/t_halfmax;
similarity = new double[DSCALE+1];
for(int i=0;i=source.W) {distance+=ssdmax; continue;}
if (yks<0 || yks>=source.H) {distance+=ssdmax; continue;}
// corresponding pixel in the target patch
int xkt=xt+dx, ykt=yt+dy;
if (xkt<0 || xkt>=target.W) {distance+=ssdmax; continue;}
if (ykt<0 || ykt>=target.H) {distance+=ssdmax; continue;}
// SSD distance between pixels (each value is in [0,255^2])
long ssd=0;
// value distance (weight for R/G/B components = 3/6/1)
for(int band=0;band<3;band++) {
int weight = (band==0)?3:(band==1)?6:1;
double diff2 = (source.getSample(xks, yks, band) - target.getSample(xkt, ykt, band))*(source.getSample(xks, yks, band) - target.getSample(xkt, ykt, band)); // Value
ssd += weight*diff2;
}
// add pixel distance to global patch distance
distance += ssd;
}
}
return (int)(DSCALE*distance/wsum);
}
public static int distance2(ImageMap source,int xs,int ys, ImageMap target,int xt,int yt, int S) {
long distance=0, wsum=0;
double ssdmax = 1.9;
// for each pixel in the source patch
for(int dy=-S;dy<=S;dy++) {
for(int dx=-S;dx<=S;dx++) {
wsum+=ssdmax;
int xks=xs+dx, yks=ys+dy;
if (xks<0 || xks>=source.W) {distance+=ssdmax; continue;}
if (yks<0 || yks>=source.H) {distance+=ssdmax; continue;}
// corresponding pixel in the target patch
int xkt=xt+dx, ykt=yt+dy;
if (xkt<0 || xkt>=target.W) {distance+=ssdmax; continue;}
if (ykt<0 || ykt>=target.H) {distance+=ssdmax; continue;}
// SSD distance between pixels (each value is in [0,255^2])
long ssd=0;
double s_RGB=source.getSample(xks, yks, 0)+source.getSample(xks, yks, 1)+source.getSample(xks, yks, 2);
double s_r=source.getSample(xks, yks, 0)/s_RGB;
double s_g=source.getSample(xks, yks, 1)/s_RGB;
double s_b=source.getSample(xks, yks, 2)/s_RGB;
double t_RGB=source.getSample(xks, yks, 0)+source.getSample(xks, yks, 1)+source.getSample(xks, yks, 2);
double t_r=source.getSample(xks, yks, 0)/t_RGB;
double t_g=source.getSample(xks, yks, 1)/t_RGB;
double t_b=source.getSample(xks, yks, 2)/t_RGB;
double diff2 = (s_r - t_r)*(s_r - t_r) + (s_g - t_g)*(s_g - t_g) + (s_b - t_b)*(s_b - t_b); // Value
ssd += diff2;
// add pixel distance to global patch distance
distance += ssd;
}
}
return (int)(DSCALE*distance/wsum);
}
// Helper for BufferedImage resize
public static BufferedImage resize(BufferedImage input, int newwidth, int newheight) {
BufferedImage out = new BufferedImage(newwidth, newheight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = out.createGraphics();
java.awt.Image scaled = input.getScaledInstance(newwidth, newheight, java.awt.Image.SCALE_SMOOTH);
g.drawImage(scaled, 0, 0, out.getWidth(), out.getHeight(), null);
g.dispose();
return out;
}
// return a copy of the image
public ImageMap copy() {
boolean[][] newmask= new boolean[W][H];
BufferedImage newimage = new BufferedImage(W,H, BufferedImage.TYPE_INT_RGB);
newimage.createGraphics().drawImage(image, 0, 0, null);
return new ImageMap(newimage);
}
// return a downsampled image (factor 1/2)
public ImageMap downsample() {
int newW=W/2, newH=H/2;
// Binomial coefficient kernels
int[] kernelEven = new int[] {1,5,10,10,5,1};
int[] kernelOdd = new int[] {1,4,6,4,1};
int[] kernelx = (W%2==0)?kernelEven:kernelOdd;
int[] kernely = (H%2==0)?kernelEven:kernelOdd;
ImageMap newimage = new ImageMap(newW, newH);
for(int y=0,ny=0;y=H) continue;
for(int dx=0;dx=W) continue;
total++;
int k = kernelx[dx]*kernely[dy];
r+= k*this.getSample(xk, yk, 0);
g+= k*this.getSample(xk, yk, 1);
b+= k*this.getSample(xk, yk, 2);
ksum+=k;
}
}
if (ksum>0) {
newimage.setSample(nx, ny, 0, (int)((double)r/ksum+0.5));
newimage.setSample(nx, ny, 1, (int)((double)g/ksum+0.5));
newimage.setSample(nx, ny, 2, (int)((double)b/ksum+0.5));
}
}
}
return newimage;
}
// return an upscaled image
public ImageMap upscale(int newW,int newH) {
ImageMap newimage = new ImageMap(newW, newH);
newimage.image = resize(this.image, newW, newH);
return newimage;
}
//return a local variance map
public double[][] LocalVariance(int blockSize){
double[][] GrayscaleIm = new double[W][H];
double[][] OutputVariance = new double[W][H];
int R,G,B;
for (int ii = 0; ii < W; ii++) {
for (int jj = 0; jj < H; jj++) {
R = this.getSample(ii, jj, 0);
G = this.getSample(ii, jj, 1);
B = this.getSample(ii, jj, 2);
GrayscaleIm[ii][jj] = 0.2989 * R + 0.5870 * G + 0.1140 * B;
}
}
double[][] BlockVar=Util.BlockVar(GrayscaleIm, blockSize);
//System.out.println();
//System.out.println(W+ " " + H + " " + BlockNoiseVar.length + " " + BlockNoiseVar[0].length);
for (int ii=0; ii<(int)Math.floor(((float)W)/blockSize)*blockSize;ii++){
for (int jj=0; jj<(int)Math.floor(((float)H)/blockSize)*blockSize;jj++){
OutputVariance[ii][jj] = BlockVar[(int)Math.floor(((float)ii)/blockSize)][(int)Math.floor(((float)jj)/blockSize)];
}
}
return OutputVariance;
}
}