Last active
August 29, 2015 14:02
-
-
Save Alrecenk/c7ac3a789ca916e090b0 to your computer and use it in GitHub Desktop.
Scales down an image by an area weighted averaging of all overlapping pixels. Equivalent to infinite supersampling.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//scales an image, maintaining aspect ratio, to fit within the desired width and height | |
//averages color over squares weighted by overlap area to get "perfect" results when scaling down | |
//does not interpolate and is not designed for scaling up, only down (hence thumbnail) | |
public static BufferedImage makethumbnail(BufferedImage img, double desiredwidth, double desiredheight){ | |
//System.out.println("Original Image size: " + img.getWidth(null)+ " x "+img.getHeight(null)); | |
if(img ==null || img.getWidth(null) <1 || img.getHeight(null) <1){ | |
return null; // something wrong with image | |
}else{ | |
byte image[][][] = convertimage(img) ; // convert to byte array, first index is x, then y, then {r,g,b} | |
int width = image.length ; | |
int height = image[0].length ; | |
//scale uniformly to fit within the tiven size (will be smaller if aspect ratio is different) | |
double scale = Math.min(desiredwidth/(double)width, desiredheight/(double)height) ; | |
int nw = (int)(width*scale+.1), nh = (int)(height*scale+.1) ; | |
byte newimage[][][] = new byte[nw][nh][3]; | |
//sample the pixels into the new image | |
double pixel[] = new double[4]; | |
double xstep = width/(double)nw, ystep=height/(double)nh; | |
for(int x = 0 ; x < nw;x++){ | |
for(int y = 0 ; y < nh;y++){ | |
//get axis alignd bounding box to intersect with original image for this pixel | |
pixel[0] = x*xstep ; | |
pixel[1] = y*ystep ; | |
pixel[2] = pixel[0]+xstep; | |
pixel[3] = pixel[1]+ystep; | |
double c[] = colorsampled(pixel, image); | |
//cast back to byte, add 0.5 before truncating to get rounding | |
newimage[x][y][0] = (byte)(c[0]+.5); | |
newimage[x][y][1] = (byte)(c[1]+.5); | |
newimage[x][y][2] = (byte)(c[2]+.5); | |
} | |
} | |
BufferedImage img2 = convertimage(newimage) ; | |
return img2 ; | |
} | |
} | |
//returns the average color of an axis aligned bounding box on this image | |
//using no interpolation | |
//AABB is an axis aligned bounding box of the form{ minx,miny,maxx,maxy} | |
public static double[] colorsampled(double AABB[], byte image[][][]){ | |
int width = image.length; | |
int height = image[1].length ; | |
int minx = (int)(AABB[0]) ; | |
int maxx = (int)(AABB[2]+1) ; | |
int miny = (int)(AABB[1]) ; | |
int maxy = (int)(AABB[3]+1) ; | |
//make sure AABB doesn't try to read outside of texture | |
if(minx<0)minx = 0 ; | |
if(miny<0)miny = 0; | |
if(maxx>width)maxx = width ; | |
if(maxy>height)maxy = height ; | |
//area*each color | |
double rarea = 0 ; | |
double barea = 0 ; | |
double garea = 0 ; | |
double area =0,a; | |
for(int x=minx;x<maxx;x++){ | |
for(int y=miny;y<maxy;y++){ | |
double[] texel = new double[]{x,y,x+1,y+1}; | |
double intersect[] = AABBintersect(texel,AABB) ; | |
if(AABB[2] > AABB[0] && AABB[3] > AABB[1]){//if the AABBs intersect | |
double intersectarea = (AABB[2]-AABB[0])*(AABB[3]-AABB[1]); | |
if(intersectarea>0.000001){ | |
area += intersectarea ; | |
rarea+= (image[x][y][0]&0xff)*intersectarea ; | |
garea+= (image[x][y][1]&0xff)*intersectarea ; | |
barea+= (image[x][y][2]&0xff)*intersectarea ; | |
} | |
} | |
} | |
} | |
return new double[]{rarea/area,garea/area,barea/area}; | |
} | |
//returns an axis aligned bounding box representing the intersection of two AABBs | |
//where AABBs given as {xmin,ymin,xmax,ymax} | |
public static double[] AABBintersect(double[] a, double[] b){ | |
return new double[]{Math.max(a[0], b[0]),Math.max(a[1], b[1]), Math.min(a[2], b[2]),Math.min(a[3], b[3])}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment