package model; /** *

Title:ImageProcess.java

*

Description: Takes a raw image and processed through * a modeled cell. convolves and divides by cell size so * cell size does not effect values.

*

Copyright: Copyright (c) 2007

*

Company: Hanover College

* @author John H. Krantz, Ph.D. * @version 0.1 */ //import java.awt.*; //import javax.swing.*; // Gabor imports import util.Defaults; import model.color.*; public class ImageProcess { // image, x, y, Color Opponent Channel private double [][][] image; private int channel = ColorConst.BL_WH; // channel to read, default is the non-opponent channel // cell private double [][] cell; // for foveal modeling get cell objects private SimpleCell gabor; private DOG_Cell dog; // output private double [][] output; private int step = Defaults.STEP; // steps between centers of cells private double correction = 1; // Fovea Modeling Objects private double foveaRad = Defaults.FOVEA_RADIUS; // radius of the fovea in pixels private double acuitySlope = Defaults.ACUITY_SLOPE; // rate for acuity getting worse in periphery. private int xFov = -1; private int yFov = -1; // the position in the image in the fovea, units are pixels // Eye movement options private boolean eyeJitter = false; // flag to indicate // whether or not to jitter the eye private int jitMax = step; // the maximum offset (x and y are same) private int numJit = Defaults.NUM_JITTER; // number of relative movements to sample // this is the temporal summation if you will public ImageProcess() { } // process methods public double [][] processImage(){ correction = cell.length*cell[0].length/2; // output is scaled to cell size. // the /2 is just to match how it worked in // Mathematica. it gives a convenient range of numbers // it has no other purpose. // setup to do the eye jittering int nJ = numJit; double jitLim = jitMax; if (!eyeJitter){ jitLim = 0; nJ = 1; } double jit = nJ; // correction for averages int xStep = (int)((double)image.length - ((double)cell.length)-2.0*jitLim)/step; int yStep = (int)((double)image[0].length - ((double)cell[0].length)-2.0*jitLim)/step; output = new double[xStep][yStep]; // jitter loop // do the jitter loop as the outer loop because // eye always moves together. for (int jt = 0; jt < nJ; jt ++){ // compute the output int xOff = 0, yOff = 0; // jitter offsets if (eyeJitter){ // computer the x and y offsets separately for // each run through the image xOff = (int)((double)jitMax*2.0*(Math.random()-0.5))+jitMax; yOff = (int)((double)jitMax*2.0*(Math.random()-0.5))+jitMax; } for (int x = 0; x < xStep; x ++){ for (int y = 0; y < yStep; y ++){ // these outer two loops move across the image // get the cells activation output[x][y] = processPoint(x,y,xOff,yOff); }//end for y }// end for x } // end jitter loop // scale correction for (int x = 0; x < output.length; x ++){ for (int y = 0; y < output[0].length; y ++){ output[x][y] = output[x][y]/(correction*jit); } } return output; } public double [][] processImage(double [][]cll){ setCell(cll); return processImage(); } public double [][] processImage(double [][][] img, double [][] cll){ setCell(cll); setImage(img); return processImage(); } /** * Process an image through simple cells modeling a * central high acuity fovea * @param SimpleCell sc the basic simple cell * @return double [][] the cell activations across this cell */ public double [][] processFoveaImage(SimpleCell sc, int orient){ gabor = sc; double sd = gabor.getCellWidth(); // standard deviation // of the gabor cell. testFoveaLoc(image); // is the fovea in the image // if not put it int he center // setup to do the eye jittering int nJ = numJit; double jitLim = jitMax; if (!eyeJitter){ jitLim = 0; nJ = 1; } double jit = nJ; // correction for averages int xStep = (int)((double)image.length - ((double)cell.length)-2.0*jitLim)/step; int yStep = (int)((double)image[0].length - ((double)cell[0].length)-2.0*jitLim)/step; output = new double[xStep][yStep]; // jitter loop // do the jitter loop as the outer loop because // eye always moves together. for (int jt = 0; jt < nJ; jt ++){ // compute the output int xOff = 0, yOff = 0; // jitter offsets if (eyeJitter){ // computer the x and y offsets separately for // each run through the image xOff = (int)((double)jitMax*2.0*(Math.random()-0.5))+jitMax; yOff = (int)((double)jitMax*2.0*(Math.random()-0.5))+jitMax; } for (int x = 0; x < xStep; x ++){ for (int y = 0; y < yStep; y ++){ // these outer two loops move across the image // adjust the cell diameter double sdC = adjustSD(x,y,step,sd); gabor.setBarWidth(sdC); gabor.setupCell(); setCell(gabor.getCell(orient)); correction = cell.length*cell[0].length/2.0; // output is scaled to cell size. // the /2 is just to match how it worked in // Mathematica. it gives a convenient range of numbers // it has no other purpose. // get the cells activation output[x][y] = processPoint(x,y,xOff,yOff); // scale correction output[x][y] = output[x][y]/(correction*jit); }//end for y }// end for x } // end jitter loop return output; } /** * Process an image through simple cells modeling a * central high acuity fovea * @param SimpleCell sc the basic simple cell * @return double [][] the cell activations across this cell */ public double [][] processFoveaImage(DOG_Cell dc){ dog = dc; setCell(dog.getCell()); double sdE = dog.getExcitWidth(); double sdI = dog.getInhibWidth(); // standard deviations // of the DOG cell. testFoveaLoc(image); // is the fovea in the image // if not put it int he center // setup to do the eye jittering int nJ = numJit; double jitLim = jitMax; if (!eyeJitter){ jitLim = 0; nJ = 1; } double jit = nJ; // correction for averages int xStep = (int)((double)image.length - ((double)cell.length)-2.0*jitLim)/step; int yStep = (int)((double)image[0].length - ((double)cell[0].length)-2.0*jitLim)/step; output = new double[xStep][yStep]; // jitter loop // do the jitter loop as the outer loop because // eye always moves together. for (int jt = 0; jt < nJ; jt ++){ // compute the output int xOff = 0, yOff = 0; // jitter offsets if (eyeJitter){ // computer the x and y offsets separately for // each run through the image xOff = (int)((double)jitMax*2.0*(Math.random()-0.5))+jitMax; yOff = (int)((double)jitMax*2.0*(Math.random()-0.5))+jitMax; } for (int x = 0; x < xStep; x ++){ for (int y = 0; y < yStep; y ++){ // these outer two loops move across the image // adjust the cell diameter double sdE_C = adjustSD(x,y,step,sdE); double sdI_C = adjustSD(x,y,step,sdI); dog.setCellParameters(sdE_C, sdI_C); dog.setupCell(); setCell(dog.getCell()); // get the cells activation correction = cell.length*cell[0].length/2; // output is scaled to cell size. // the /2 is just to match how it worked in // Mathematica. it gives a convenient range of numbers // it has no other purpose. output[x][y] = processPoint(x,y,xOff,yOff); // scale correction output[x][y] = output[x][y]/(correction*jit); }//end for y }// end for x } // end jitter loop return output; } /** * Process one point on an image * @param int x the x step in the image * @param int y the y step in the image * @param int xOff the jitter offset in the x axis * @param int yOff the jitter offset in the y axis * @return double the cell activation */ public double processPoint(int x, int y, int xOff, int yOff){ double temp = 0; // the activation of this cell boolean inbounds = true; // flag that cell is completely // within image. needed for foveal modeling where // cells get larger as they move out from fovea for (int i = 0; i < cell.length; i ++){ for (int j = 0; j < cell[0].length; j ++){ int xPos = x*step+i+xOff; int yPos = y*step+j+yOff; if (xPos >=0 & xPos < image.length & yPos >= 0 & yPos < image[0].length){ temp += cell[i][j]* image[xPos][yPos][channel]; } else { inbounds = false; } }// end for j }// end for i if (!inbounds) temp = 0; // clear out values // if not all of receptive field within image return temp; } /** * determine if the fovea is in the image. If * not put the fovea in the center of the image * @param img */ private void testFoveaLoc(double [][][] img){ if (xFov >=0 & xFov < img.length & yFov >= 0 & yFov < img[0].length){ // do nothing // just easier to think through the boolean here } else { // put fovea in center of image xFov = image.length/2; yFov = image[0].length/2; } } /** * adjust the standard deviation of the cell * for how far the point in the image is from * the fovea. * @param int x x step position in the image * @param int y y step position in the image * @param int xStep the size of the x step through the * image. needed to get back to pixels. * @param int yStep the size of the y step through the * image. needed to get back to pixels. * @return double the new standard deviation */ private double adjustSD(double x, double y, double step, double sd){ double newSD = 1; // get back pixels images double xPxl = x*step; double yPxl = y*step; // how far in each dimension is the cell center // from the voea double xDst = Math.abs(xPxl-xFov)-foveaRad; double yDst = Math.abs(yPxl-yFov)-foveaRad; // do the good old pythagorean theory double distPxl = Math.sqrt(xDst*xDst+yDst*yDst); // convert to adjusted slope using a linear equation newSD = acuitySlope*distPxl+sd; return newSD; } // set methods public void setCell(double [][] cll){ cell = cll; } public void setImage(double [][][] img){ image = img; } public void setStep(int stp){ step = (stp > 0 ? stp : step); } public void setJitter(boolean b, int maxOffset, int numJitter){ eyeJitter = b; jitMax = (maxOffset > 0 ? maxOffset : jitMax); numJit = (numJitter > 0 ? numJitter : numJit); } public void setJitter(boolean b){ eyeJitter = b; } /** * Set the color opponent channel to process * @param int c the number of the color opponent channel */ public void setChannel(int c){ channel = (c == ColorConst.BL_WH | c == ColorConst.R_G | c == ColorConst.B_Y ? c : channel); } /** * set the location of the fovea in the image in pixels * @param int xLoc x position of the fovea * @param int yLoc y position of the fovea */ public void setFoveaLoc(int xLoc, int yLoc){ xFov = xLoc; yFov = yLoc; } /** * Set the parameters about the modeled fovea * @param double radius the size of fovea in pixels * @param double slope the rate at which acuity falls off * from the fovea in SD/pixels */ public void setFoveaParam(double radius, double slope){ foveaRad = (radius > 0? radius : foveaRad); acuitySlope = (slope > 0 ? slope: acuitySlope); } // get methods public double [][] getCell() { return cell; } public double [][] getOutput() { return output; } public double getFovRadius() { return foveaRad; } public double getAcuitySlope() { return acuitySlope; } public boolean getEyeJitter() { return eyeJitter; } public int getMaxJitterOffset() { return jitMax; } public int getNumJitter() { return numJit; } public int getChannel() { return channel; } }