This commit is contained in:
Ziver Koc 2008-11-14 16:38:36 +00:00
commit 613bef2496
108 changed files with 8397 additions and 0 deletions

View file

@ -0,0 +1,210 @@
package zutil.image;
import java.awt.image.BufferedImage;
import zutil.ProgressListener;
/**
* This is a abstract class for all the effects
*
* Inspiration:
* http://www.dickbaldwin.com/tocadv.htm
*
* @author Ziver
*/
public abstract class ImageFilterProcessor {
private BufferedImage img;
private ProgressListener progress;
public ImageFilterProcessor(BufferedImage img){
this.img = img;
}
/**
* Sets the listener
* @param listener The listener, null to disable the progress
*/
public void setProgressListener(ProgressListener listener){
this.progress = listener;
}
/**
* Sets the progress in percent
*/
protected void setProgress(double percent){
if(progress != null) progress.progressUpdate(this, null, percent);
}
/**
* Applies a effect to a given image
*
* @param effect The effect to use
* @param img The image to process
* @return The processed image
*/
public static ImageFilterProcessor getProcessor(String effect, BufferedImage img) throws InstantiationException, IllegalAccessException, ClassNotFoundException, InterruptedException{
ImageFilterProcessor processor = (ImageFilterProcessor)Class.forName(effect).newInstance();
processor.img = img;
return processor;
}
/**
* Adds the chosen effect to the image
*
* @return The Image with the effect
* @throws InterruptedException
*/
public BufferedImage process() throws InterruptedException{
int cols = img.getWidth();
int rows = img.getHeight();
if(cols < 0 || rows < 0){
throw new InterruptedException("Image not Loaded!!!");
}
// converts the img to raw data
int[][][] data = convertToArray(img, cols, rows);
//processes the image
data = process(data, cols, rows);
//converts back the image
return convertToImage(data, data[0].length, data.length);
}
/**
* Creates a Integer array whit the pixel data of the image
* int[row][col][4]
* 0 -> Alpha data
* Red data
* Green data
* 4 -> Blue data
*
* @param img The image to convert
* @param cols Columns of the image
* @param rows Rows of the image
* @return A Integer array
* @throws InterruptedException
*/
public static int[][][] convertToArray(BufferedImage img, int cols, int rows) throws InterruptedException{
int[][][] data = new int[rows][cols][4];
// Reads in the image to a one dim array
int[] pixels = img.getRGB(0, 0, cols, rows, null, 0, cols);
// Read the pixel data and put it in the data array
for(int y=0; y<rows ;y++){
// reading a row
int[] aRow = new int[cols];
for(int x=0; x<cols ;x++){
int element = y * cols + x;
aRow[x] = pixels[element];
}
// Reading in the color data
for(int x=0; x<cols ;x++){
//Alpha data
data[y][x][0] = (aRow[x] >> 24) & 0xFF;
//Red data
data[y][x][1] = (aRow[x] >> 16) & 0xFF;
//Green data
data[y][x][2] = (aRow[x] >> 8) & 0xFF;
//Blue data
data[y][x][3] = (aRow[x])& 0xFF;
}
}
return data;
}
/**
* Converts a pixel data array to a java Image object
*
* @param pixels The pixel data array
* @param cols Columns of the image
* @param rows Rows of the image
* @return A Image
*/
public static BufferedImage convertToImage(int[][][] pixels, int cols, int rows){
int[] data = new int[cols * rows * 4];
//Move the data into the 1D array. Note the
// use of the bitwise OR operator and the
// bitwise left-shift operators to put the
// four 8-bit bytes into each int.
int index = 0;
for(int y=0; y<rows ;y++){
for(int x=0; x< cols ;x++){
data[index] = ((pixels[y][x][0] << 24) & 0xFF000000)
| ((pixels[y][x][1] << 16) & 0x00FF0000)
| ((pixels[y][x][2] << 8) & 0x0000FF00)
| ((pixels[y][x][3]) & 0x000000FF);
index++;
}
}
BufferedImage img = new BufferedImage(cols, rows, BufferedImage.TYPE_4BYTE_ABGR);
img.setRGB(0, 0, cols, rows, data, 0, cols);
return img;
}
/**
* Copies the given array to a new one that it returns
* @param data The data to duplicate
* @param cols The amount of columns
* @param rows The amount of rows
* @return The array copy
*/
public static int[][][] copyArray(int[][][] data,int cols,int rows){
int[][][] copy = new int[rows][cols][4];
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
copy[y][x][0] = data[y][x][0];
copy[y][x][1] = data[y][x][1];
copy[y][x][2] = data[y][x][2];
copy[y][x][3] = data[y][x][3];
}
}
return copy;
}
/**
* This method clips the values of the pixel so that they
* are in the range 0-255
* @param data The image data
* @param cols The amount of columns
* @param rows The amount of rows
*/
public static void clip(int[][][] data, int cols, int rows){
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
data[y][x][1] = clip(data[y][x][1]);
data[y][x][1] = clip(data[y][x][2]);
data[y][x][1] = clip(data[y][x][3]);
}
}
}
/**
* This method clips the values of a color so that it
* is in the range 0-255
* @param color
* @return
*/
public static int clip(int color){
if(color < 0)
return 0;
else if(color > 255)
return 255;
else
return color;
}
/**
* The underlying effect is run here
* @param data The raw image to apply the effect to
* @param cols Columns of the image
* @param rows Rows of the image
*/
public abstract int[][][] process(final int[][][] data, int cols, int rows);
}

View file

@ -0,0 +1,170 @@
package zutil.image;
/**
* Some util methods for image processing
* @author Ziver
*
*/
public class ImageUtil {
/**
* Returns the peek value in the image
*
* @param data The image data
* @param cols The number of columns
* @param rows The number of rows
* @return The peak value of the image
*/
public static int peakValue(int[][][] data, int cols, int rows) {
int peak = 0;
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
if(data[y][x][1] > peak) peak = data[y][x][1];
if(data[y][x][2] > peak) peak = data[y][x][2];
if(data[y][x][3] > peak) peak = data[y][x][3];
}
}
return peak;
}
/**
* Normalizes the image data by the given scale
*
* @param data The image data
* @param cols The number of columns
* @param rows The number of rows
* @param scale The scale to normalize the image by
*/
public static void normalize(int[][][] data, int cols, int rows, double scale) {
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
data[y][x][1] = (int)(data[y][x][1] * scale);
data[y][x][2] = (int)(data[y][x][2] * scale);
data[y][x][3] = (int)(data[y][x][3] * scale);
}
}
}
/**
* Returns the rms value of the image
* (The RMS value is a measure of the width of the color distribution.)
*
* @param data The image data
* @param cols The number of columns
* @param rows The number of rows
* @return The rms value for the image
*/
public static int rms(int[][][] data, int cols, int rows){
int pixelCount = 0;
long accum = 0;
for(int y=0; y <rows ;y++){
for(int x=0; x<cols ;x++){
accum += data[y][x][1] * data[y][x][1];
accum += data[y][x][2] * data[y][x][2];
accum += data[y][x][3] * data[y][x][3];
pixelCount += 3;
}
}
int meanSquare = (int)(accum/pixelCount);
int rms = (int)(Math.sqrt(meanSquare));
return rms;
}
/**
* Multiplies the given image data by the given value
*
* @param data The image data
* @param cols The number of columns
* @param rows The number of rows
* @param scale The number to scale the image by
*/
public static void scale(int[][][] data, int cols, int rows, double scale){
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
data[y][x][1] *= scale;
data[y][x][2] *= scale;
data[y][x][3] *= scale;
}
}
}
/**
* Returns the mean value of the given image data
*
* @param data The image data
* @param cols The column count
* @param rows The row count
* @return The mean value of the image
*/
public static int meanValue(int[][][] data,int cols, int rows){
int pixelCount = 0;
long accum = 0;
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
accum += data[y][x][1];
accum += data[y][x][2];
accum += data[y][x][3];
pixelCount += 3;
}
}
// calculate the mean value
return (int)(accum/pixelCount);
}
/**
* Adds the mean value to the image data
*
* @param data The image data
* @param cols The number of columns
* @param rows The number of rows
* @param mean The mean value
*/
public static void addMeanValue(int[][][] data,int cols, int rows, int mean){
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
data[y][x][1] += mean;
data[y][x][2] += mean;
data[y][x][3] += mean;
}
}
}
/**
* Copies all the pixel data from the image to the new array
*
* @param data The data to copy
* @param xStart X start position on the source
* @param yStart Y start position on the source
* @param width The amount of pixels to copy
* @param hight The amount of pixels to copy
* @return A copy of the data array
*/
public static int[][][] crop(int[][][] data, int xStart, int yStart, int width, int hight){
return crop(data, xStart, yStart, null, 0, 0, width, hight);
}
/**
* Copies all the pixel data from the image to the new array
*
* @param data The data to copy
* @param xData X start position in the source
* @param yData Y start position in the source
* @param crop The destination
* @param xCrop X start position in the destination
* @param yCrop Y start position in the destination
* @param width The amount of pixels to copy
* @param hight The amount of pixels to copy
* @return A copy of the data array
*/
public static int[][][] crop(int[][][] data, int xData, int yData, int[][][] crop, int xCrop, int yCrop, int width, int hight){
if(crop==null) crop = new int[width][hight][4];
for(int y=0; y<width ;y++){
for(int x=0; x<hight ;x++){
crop[y+yData][x+xData][0] = data[y+yCrop][x+xCrop][0];
crop[y+yData][x+xData][1] = data[y+yCrop][x+xCrop][1];
crop[y+yData][x+xData][2] = data[y+yCrop][x+xCrop][2];
crop[y+yData][x+xData][3] = data[y+yCrop][x+xCrop][3];
}
}
return crop;
}
}

View file

@ -0,0 +1,88 @@
package zutil.image.filters;
import java.awt.image.BufferedImage;
import zutil.image.ImageFilterProcessor;
import zutil.image.ImageUtil;
import zutil.math.ZMath;
public class BlurFilter extends ImageFilterProcessor{
private int blurValue;
/**
* Creates a blur effect on the image
* @param img The image to blur
*/
public BlurFilter(BufferedImage img){
this(img, 10);
}
/**
* Creates a blur effect on the image
* @param img The image to blur
* @param blur The amount to blur
*/
public BlurFilter(BufferedImage img, int blur){
super(img);
blurValue = blur;
}
@Override
public int[][][] process(final int[][][] data, int cols, int rows) {
int inputPeak = ImageUtil.peakValue(data, cols, rows);
int[][][] output = new int[rows][cols][4];
//Perform the convolution one or more times
// in succession
for(int i=0; i<blurValue ;i++){
//Iterate on each pixel as a registration
// point.
for(int y=1; y<rows-2 ;y++){
setProgress(ZMath.percent(0, (blurValue-1)*(rows-3), i*(rows-3)+y));
for(int x=0+1; x<cols-2 ;x++){
int redSum =
data[y - 1][x - 1][1] +
data[y - 1][x - 0][1] +
data[y - 1][x + 1][1] +
data[y - 0][x - 1][1] +
data[y - 0][x - 0][1] +
data[y - 0][x + 1][1] +
data[y + 1][x - 1][1] +
data[y + 1][x - 0][1] +
data[y + 1][x + 1][1];
int greenSum =
data[y - 1][x - 1][2] +
data[y - 1][x - 0][2] +
data[y - 1][x + 1][2] +
data[y - 0][x - 1][2] +
data[y - 0][x - 0][2] +
data[y - 0][x + 1][2] +
data[y + 1][x - 1][2] +
data[y + 1][x - 0][2] +
data[y + 1][x + 1][2];
int blueSum =
data[y - 1][x - 1][3] +
data[y - 1][x - 0][3] +
data[y - 1][x + 1][3] +
data[y - 0][x - 1][3] +
data[y - 0][x - 0][3] +
data[y - 0][x + 1][3] +
data[y + 1][x - 1][3] +
data[y + 1][x - 0][3] +
data[y + 1][x + 1][3];
output[y][x][0] = data[y][x][0];
output[y][x][1] = redSum;
output[y][x][2] = greenSum;
output[y][x][3] = blueSum;
}
}
// getting the new peak value and normalizing the image
int outputPeak = ImageUtil.peakValue(output, cols, rows);
ImageUtil.normalize(output, cols, rows, ((double)inputPeak)/outputPeak );
}
return output;
}
}

View file

@ -0,0 +1,90 @@
package zutil.image.filters;
import java.awt.image.BufferedImage;
import zutil.image.ImageFilterProcessor;
import zutil.math.ZMath;
public class ColorIntensityFilter extends ImageFilterProcessor{
private boolean invert;
private int redScale;
private int greenScale;
private int blueScale;
public ColorIntensityFilter(BufferedImage img){
this(img, 50, 50, 50, false);
}
/**
* Creates a ColorIntensityEffect object with the given values
* @param img The image data
* @param inv If the image color should be inverted
*/
public ColorIntensityFilter(BufferedImage img, boolean inv){
this(img, 100, 100, 100, inv);
}
/**
* Creates a ColorIntensityEffect object with the given values
* @param img The image data
* @param red The scale of red (0-100)
* @param green The scale of green (0-100)
* @param blue The scale of blue (0-100)
*/
public ColorIntensityFilter(BufferedImage img, int red, int green, int blue){
this(img, red, green, blue, false);
}
/**
* Creates a ColorIntensityEffect object with the given values
* @param img The image data
* @param red The scale of red (0-100)
* @param green The scale of green (0-100)
* @param blue The scale of blue (0-100)
* @param inv If the image color should be inverted
*/
public ColorIntensityFilter(BufferedImage img, int red, int green, int blue, boolean inv){
super(img);
invert = false;
redScale = red;
greenScale = green;
blueScale = blue;
}
@Override
public int[][][] process(final int[][][] data, int cols, int rows) {
// making sure the scales are right
if(redScale > 100) redScale = 100;
else if(redScale < 0) redScale = 0;
if(greenScale > 100) greenScale = 100;
else if(greenScale < 0) greenScale = 0;
if(blueScale > 100) blueScale = 100;
else if(blueScale < 0) blueScale = 0;
int[][][] output = new int[rows][cols][4];
// Applying the color intensity to the image
for(int y=0; y<rows ;y++){
setProgress(ZMath.percent(0, rows-1, y));
for(int x=0; x<cols ;x++){
if(!invert){
// inversion
output[y][x][0] = data[y][x][0];
output[y][x][1] = 255 - data[y][x][1] * redScale/100;
output[y][x][2] = 255 - data[y][x][2] * greenScale/100;
output[y][x][3] = 255 - data[y][x][3] * blueScale/100;
}
else{
output[y][x][0] = data[y][x][0];
output[y][x][1] = data[y][x][1] * redScale/100;
output[y][x][2] = data[y][x][2] * greenScale/100;
output[y][x][3] = data[y][x][3] * blueScale/100;
}
}
}
return output;
}
}

View file

@ -0,0 +1,47 @@
package zutil.image.filters;
import java.awt.image.BufferedImage;
import zutil.image.ImageFilterProcessor;
import zutil.image.ImageUtil;
public class ContrastBrightnessFilter extends ImageFilterProcessor{
private double contrast;
private double brightness;
/**
* Creates a ContrastBrightnessEffect object with the given values
* @param img The image to apply the effect to
*/
public ContrastBrightnessFilter(BufferedImage img){
this(img, 3, 1.2);
}
/**
* Creates a ContrastBrightnessEffect object with the given values
* @param img The image to apply the effect to
* @param con The contrast to apply
* @param brig The brightness to apply
*/
public ContrastBrightnessFilter(BufferedImage img, double con, double brig){
super(img);
contrast = con;
brightness = brig;
}
@Override
public int[][][] process(final int[][][] data, int cols, int rows) {
int mean = ImageUtil.meanValue(data, cols, rows);
int[][][] output = copyArray(data, cols, rows);
ImageUtil.addMeanValue(output, cols, rows, mean*(-1));
ImageUtil.scale(output, cols, rows, contrast);
ImageUtil.addMeanValue(output, cols, rows, (int)(brightness*mean));
clip(output , cols, rows);
return output;
}
}

View file

@ -0,0 +1,87 @@
package zutil.image.filters;
import java.awt.image.BufferedImage;
import zutil.image.ImageFilterProcessor;
import zutil.math.ZMath;
public class DitheringFilter extends ImageFilterProcessor{
// default palette is black and white
private int[][] palette = {
{255,0,0,0},
{255,255,255,255}
};
/**
* Sets up a default DitheringEffect
*/
public DitheringFilter(BufferedImage img){
super(img);
}
/**
* Creates a Dithering Effect object
* @param img The image to apply the effect on
* @param palette The palette to use on the image
* int[colorCount][4]
* 0 -> Alpha data
* Red data
* Green data
* 4 -> Blue data
*/
public DitheringFilter(BufferedImage img, int[][] palette){
super(img);
this.palette = palette;
}
@Override
public int[][][] process(final int[][][] data, int cols, int rows) {
int error, index;
int[] currentPixel;
int[][][] output = copyArray(data, cols, rows);
for(int y=0; y<rows ;y++){
setProgress(ZMath.percent(0, rows-1, y));
for(int x=0; x<cols ;x++){
currentPixel = output[y][x];
index = findNearestColor(currentPixel, palette);
output[y][x] = palette[index];
for (int i = 1; i < 4; i++) {
error = currentPixel[i] - palette[index][i];
if (x + 1 < cols) {
output[y+0][x+1][i] = clip( output[y+0][x+1][i] + (error*7)/16 );
}
if (y + 1 < rows) {
if (x - 1 > 0)
output[y+1][x-1][i] = clip( output[y+1][x-1][i] + (error*3)/16 );
output[y+1][x+0][i] = clip( output[y+1][x+0][i] + (error*5)/16 );
if (x + 1 < cols)
output[y+1][x+1][i] = clip( output[y+1][x+1][i] + (error*1)/16 );
}
}
}
}
return output;
}
private static int findNearestColor(int[] color, int[][] palette) {
int minDistanceSquared = 255*255 + 255*255 + 255*255 + 1;
int bestIndex = 0;
for (byte i = 0; i < palette.length; i++) {
int Rdiff = color[1] - palette[i][0];
int Gdiff = color[2] - palette[i][1];
int Bdiff = color[3] - palette[i][2];
int distanceSquared = Rdiff*Rdiff + Gdiff*Gdiff + Bdiff*Bdiff;
if (distanceSquared < minDistanceSquared) {
minDistanceSquared = distanceSquared;
bestIndex = i;
}
}
return bestIndex;
}
}

View file

@ -0,0 +1,171 @@
package zutil.image.filters;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import zutil.image.ImageFilterProcessor;
import zutil.math.ZMath;
public class FaceDetectionFilter extends ImageFilterProcessor{
public FaceDetectionFilter(BufferedImage img) {
super(img);
}
@Override
public int[][][] process(int[][][] data, int cols, int rows) {
int[][][] IRgBy = convertARGBToIRgBy(data, cols, rows);
MedianFilter median = new MedianFilter(null, 4*getSCALE(cols,rows), new boolean[]{false,false,true,true});
IRgBy = median.process(IRgBy, cols, rows);
setProgress(ZMath.percent(0, 4, 1));
//********* Texture Map ********
median = new MedianFilter(null, 8*getSCALE(cols,rows), new boolean[]{false,true,false,false});
int[][][] textureMap = median.process(IRgBy, cols, rows);
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
textureMap[y][x][1] = Math.abs(IRgBy[y][x][1]-textureMap[y][x][1]);
}
}
median = new MedianFilter(null, 12*getSCALE(cols,rows), new boolean[]{false,true,false,false});
textureMap = median.process(textureMap, cols, rows);
setProgress(ZMath.percent(0, 4, 2));
//*********** Hue & Saturation *********
int[][] skinMap = new int[rows][cols];
int[][] hueMap = new int[rows][cols];
int[][] saturationMap = new int[rows][cols];
int hue, saturation;
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
// hue = (atan^2(Rg,By))
hue = (int)( Math.atan2(IRgBy[y][x][2], IRgBy[y][x][3]) * 360/2*Math.PI);
// saturation = sqrt(Rg^2+By^2)
saturation = (int) Math.sqrt(IRgBy[y][x][2]*IRgBy[y][x][2] + IRgBy[y][x][3]*IRgBy[y][x][3]);
hueMap[y][x] = hue;
saturationMap[y][x] = saturation;
// (1) texture<4.5, 120<160, 10<60
// (2) texture<4.5, 150<180, 20<80
if((textureMap[y][x][1] < 4.5 && (hue >= 120 && hue <= 160) && (saturation >= 10 && saturation <= 60)) ||
(textureMap[y][x][1] < 4.5 && (hue >= 150 && hue <= 180) && (saturation >= 20 && saturation <= 80)) ){
skinMap[y][x] = 1;
}
}
}
setProgress(ZMath.percent(0, 4, 3));
//************** SkinMap dilation ********************
skinMap = dilation(skinMap , cols, rows);
//*****************************************************
setProgress(100);
//return convertArrayToARGBchannel(hueMap, cols, rows, -150, 150, 1);
//return convertArrayToARGBchannel(saturationMap, cols, rows, 0, 70, 1);
return convertArrayToARGBchannel(skinMap, cols, rows, 0, 1, 2);
}
private int[][] dilation(int[][] data, int cols, int rows){
int[][] output = new int[rows][cols];
int radX = 8;
int radY = 8;
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
if(data[y][x] == 1){
for(int dy=y-radY; dy<y+radY ;dy++){
for(int dx=x-radX; dx<x+radX ;dx++){
if(dy >= 0 && dy < rows && dx >= 0 && dx < cols)
output[dy][dx] = 1;
}
}
}
}
}
return output;
}
/**
* Converts the given data array to a color image
*
* @param data The 2d data
* @param cols The size of the image data
* @param rows The size of the image data
* @param min The minimum value in the data
* @param max The maximum value in the data
* @param channel The color channel to apply the data to
* @return A ARGB array
*/
public int[][][] convertArrayToARGBchannel(int[][] data, int cols, int rows,int min, int max, int channel){
int[][][] output = new int[rows][cols][4];
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
output[y][x][0] = 255;
output[y][x][channel] = (int) ZMath.percent(min, max, data[y][x]);
}
}
return output;
}
/**
* Converts RGB color to log-opponent (IRgBy) with the formula:
* I= [L(R)+L(B)+L(G)]/3
* Rg = L(R)-L(G)
* By = L(B)-[L(G)+L(R)]/2
*
* @param data The RGB data
* @param cols The number of columns
* @param rows The number of rows
* @return IRgBy data
*/
public int[][][] convertARGBToIRgBy(int[][][] data, int cols, int rows){
int[][][] output = new int[rows][cols][4];
for(int y=0; y<rows ;y++){
for(int x=0; x<cols ;x++){
output[y][x][0] = data[y][x][0];
// I= [L(R)+L(B)+L(G)]/3
output[y][x][1] = (
IRgByFunction(data[y][x][1]) +
IRgByFunction(data[y][x][2]) +
IRgByFunction(data[y][x][3])
) / 3;
// Rg = L(R)-L(G)
output[y][x][2] = IRgByFunction(output[y][x][1]) - IRgByFunction(data[y][x][2]);
// By = L(B)-[L(G)+L(R)]/2
output[y][x][3] = IRgByFunction(output[y][x][3]) -
(IRgByFunction(output[y][x][2]) - IRgByFunction(output[y][x][1])) / 2;
}
}
return output;
}
// Helper function to convertToIRgBy()
private int IRgByFunction(int value){
return (int)(105*Math.log10(value+1));
}
private int getSCALE(int cols, int rows){
return (cols+rows)/320;
}
public Rectangle getFaceRectangle(){
return null;
}
}

View file

@ -0,0 +1,169 @@
package zutil.image.filters;
import java.awt.image.BufferedImage;
import zutil.algo.sort.sortable.SortableDataList;
import zutil.image.ImageFilterProcessor;
import zutil.math.ZMath;
/**
* The MedianFilter is used for noise reduction and things
*
* @author Ziver
*/
public class MedianFilter extends ImageFilterProcessor{
private int windowSize;
private boolean[] channels;
/**
* Setup a default MedianFilter
*
* @param img The image to process
*/
public MedianFilter(BufferedImage img) {
this(img, 10);
}
/**
* Setup a default MedianFilter
*
* @param img The image to process
* @param pixels The size of the window
*/
public MedianFilter(BufferedImage img, int pixels) {
this(img, pixels, new boolean[]{true,true,true,true});
}
/**
* Setup a default MedianFilter
*
* @param img The image to process
* @param pixels The size of the window
* @param channels Is a 4 element array for witch channels to use the filter on
*/
public MedianFilter(BufferedImage img, int pixels, boolean[] channels) {
super(img);
this.windowSize = pixels;
this.channels = channels;
}
/*
edgex := (window width / 2) rounded down
edgey := (window height / 2) rounded down
for x from edgex to image width - edgex:
for y from edgey to image height - edgey:
colorArray[window width][window height];
for fx from 0 to window width:
for fy from 0 to window height:
colorArray[fx][fy] := pixelvalue[x + fx - edgex][y + fy - edgey]
Sort colorArray[][];
pixelValue[x][y] := colorArray[window width / 2][window height / 2];
*/
@Override
public int[][][] process(int[][][] data, int cols, int rows) {
int[][][] output = new int[rows][cols][4];
int edgeX = windowSize / 2;
int edgeY = windowSize / 2;
int[][] tmpArray = new int[4][256*2];
int pixelCount = 0;
for(int y=0; y<rows ;y++){
setProgress(ZMath.percent(0, rows-1, y));
for(int x=0; x<cols ;x++){
pixelCount = 0;
for(int fy=0; fy<windowSize ;fy++){
for(int fx=0; fx<windowSize ;fx++){
if(y+fy-edgeY >= 0 && y+fy-edgeY < rows && x+fx-edgeX >= 0 && x+fx-edgeX < cols){
//colorArray[fx][fy] := pixelvalue[x + fx - edgex][y + fy - edgey]
if(channels[0]) tmpArray[0][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][0] ) ]++;
if(channels[1]) tmpArray[1][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][1] ) ]++;
if(channels[2]) tmpArray[2][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][2] ) ]++;
if(channels[3]) tmpArray[3][ getMedianIndex( data[y + fy - edgeY][x + fx - edgeX][3] ) ]++;
pixelCount++;
}
}
}
if(channels[0])output[y][x][0] = findMedian(tmpArray[0], pixelCount/2);
else output[y][x][0] = data[y][x][0];
if(channels[1])output[y][x][1] = findMedian(tmpArray[1], pixelCount/2);
else output[y][x][1] = data[y][x][1];
if(channels[2])output[y][x][2] = findMedian(tmpArray[2], pixelCount/2);
else output[y][x][2] = data[y][x][2];
if(channels[3])output[y][x][3] = findMedian(tmpArray[3], pixelCount/2);
else output[y][x][3] = data[y][x][3];
}
}
return output;
}
private int getMedianIndex(int i){
if(i < 0) return Math.abs(i);
else return i+256;
}
private int findMedian(int[] median, int medianCount){
int sum = 0;
int ret = 0;
for(int i=0; i<median.length ;i++){
sum += median[i];
median[i] = 0;
if(sum >= medianCount && ret == 0){
ret = i-256;
}
}
return ret;
}
class SortableARGB implements SortableDataList<Integer>{
private int[][][] data;
private int cols;
private int rows;
private int channel;
public SortableARGB(int[][][] data, int cols, int rows, int channel){
this.data = data;
this.cols = cols;
this.rows = rows;
this.channel = channel;
}
public int compare(int a, int b) {
return compare(a, data[ getY(b) ][ getX(b) ][ channel ]);
}
public int compare(int a, Integer b) {
return ((Integer)data[ getY(a) ][ getX(a) ][ channel ]).compareTo(b);
}
public Integer getIndex(int i) {
return data[ getY(i) ][ getX(i) ][ channel ];
}
public int size() {
return cols * rows;
}
public void swap(int a, int b) {
int tmp = data[ getY(a) ][ getX(a) ][ channel ];
data[ getY(a) ][ getX(a) ][ channel ] = data[ getY(b) ][ getX(b) ][ channel ];
data[ getY(b) ][ getX(b) ][ channel ] = tmp;
}
private int getX(int a){
return a % cols;
}
private int getY(int a){
return a / cols;
}
}
}

View file

@ -0,0 +1,63 @@
package zutil.image.filters;
import java.awt.image.BufferedImage;
import zutil.image.ImageFilterProcessor;
import zutil.math.ZMath;
public class ResizeImage extends ImageFilterProcessor{
private int width;
private int hight;
/**
* Will create a ResizeImage object and fix the hight with the aspect
* of the width
*
* @param img The image to resize
* @param w The new width
*/
public ResizeImage(BufferedImage img, int w){
this(img, w, -1);
}
/**
* Will create a ResizeImage object
*
* @param img The image to resize
* @param w The new width if -1 then it will be scaled whit aspect of the hight
* @param h The new hight if -1 then it will be scaled whit aspect of the width
*/
public ResizeImage(BufferedImage img, int w, int h){
super(img);
width = w;
hight = h;
}
@Override
public int[][][] process(final int[][][] data, int cols, int rows) {
if(width < 1){
hight = (int)(((double)width/cols)*rows);
}
else if(hight < 1){
width = (int)(((double)hight/rows)*cols);
}
int[][][] tmp = new int[hight][width][4];
double xScale = ((double)cols/width);
double yScale = ((double)rows/hight);
for(int y=0; y<width ;y++){
setProgress(ZMath.percent(0, width-1, y));
for(int x=0; x<hight ;x++){
tmp[y][x][0] = data[(int)(y*yScale)][(int)(x*xScale)][0];
tmp[y][x][1] = data[(int)(y*yScale)][(int)(x*xScale)][1];
tmp[y][x][2] = data[(int)(y*yScale)][(int)(x*xScale)][2];
tmp[y][x][3] = data[(int)(y*yScale)][(int)(x*xScale)][3];
}
}
return tmp;
}
}

View file

@ -0,0 +1,73 @@
package zutil.image.filters;
import java.awt.image.BufferedImage;
import zutil.image.ImageFilterProcessor;
import zutil.math.ZMath;
public class SpotLightFilter extends ImageFilterProcessor{
private int radius;
private int xPos;
private int yPos;
/**
* Sets up a default spotlight effect in
* the middle of the image
*/
public SpotLightFilter(BufferedImage img){
this(img, 100, -1, -1);
}
/**
* Sets up a custom spotlight
* @param r The radius of the spotlight in pixels
*/
public SpotLightFilter(BufferedImage img, int r){
this(img, r, -1, -1);
}
/**
* Sets up a custom spotlight
* @param r The radius of the spotlight in pixels
* @param x The x position of the spotlight, if -1 then it will be centered
* @param y The y position of the spotlight, if -1 then it will be centered
*/
public SpotLightFilter(BufferedImage img, int r, int x, int y){
super(img);
radius = r;
xPos = x;
yPos = y;
}
@Override
public int[][][] process(final int[][][] data, int cols, int rows) {
if(xPos < 0) xPos = cols/2;
if(yPos < 0) yPos = rows/2;
int[][][] output = new int[rows][cols][4];
double scale, dx, dy, distance;
for(int y=0; y<rows ;y++){
setProgress(ZMath.percent(0, rows-1, y));
for(int x=0; x<cols ;x++){
dx = x-xPos;
dy = y-yPos;
distance = Math.sqrt(dx*dx+dy*dy);
if(distance > radius){
scale = 0;
}
else{
scale = 1-(distance/radius);
}
output[y][x][0] = data[y][x][0];
output[y][x][1] = clip((int)(scale * data[y][x][1]));
output[y][x][2] = clip((int)(scale * data[y][x][2]));
output[y][x][3] = clip((int)(scale * data[y][x][3]));
}
}
return output;
}
}