/** * Computes and plots correlation functions * * @param tauMax is the maximum time for correlation functions */ public void computeCorrelation(int tauMax) { plotFrame.clearData(); double energyAccumulator = 0, magnetizationAccumulator = 0; double energySquaredAccumulator = 0, magnetizationSquaredAccumulator = 0; for (int t = 0; t < numberOfPoints; t++) { energyAccumulator += energy[t]; magnetizationAccumulator += magnetization[t]; energySquaredAccumulator += energy[t] * energy[t]; magnetizationSquaredAccumulator += magnetization[t] * magnetization[t]; } double averageEnergySquared = Math.pow(energyAccumulator / numberOfPoints, 2); double averageMagnetizationSquared = Math.pow(magnetizationAccumulator / numberOfPoints, 2); // compute normalization factors double normE = (energySquaredAccumulator / numberOfPoints) - averageEnergySquared; double normM = (magnetizationSquaredAccumulator / numberOfPoints) - averageMagnetizationSquared; for (int tau = 1; tau <= tauMax; tau++) { double c_MAccumulator = 0; double c_EAccumulator = 0; int counter = 0; for (int t = 0; t < numberOfPoints - tau; t++) { c_MAccumulator += magnetization[t] * magnetization[t + tau]; c_EAccumulator += energy[t] * energy[t + tau]; counter++; } // correlation function defined so that c(0) = 1 and c(infinity) -> 0 plotFrame.append(0, tau, ((c_MAccumulator / counter) - averageMagnetizationSquared) / normM); plotFrame.append(1, tau, ((c_EAccumulator / counter) - averageEnergySquared) / normE); } plotFrame.setVisible(true); }
/** initializes site lattice with single particle clusters randomly placed on the lattice */ public void initialize() { site = new int[L][L]; for (int i = 0; i < L; i++) { for (int j = 0; j < L; j++) { site[i][j] = -1; // site not occupied } } x = new int[numberOfParticles]; y = new int[numberOfParticles]; firstParticle = new int[numberOfParticles]; nextParticle = new int[numberOfParticles]; lastParticle = new int[numberOfParticles]; mass = new int[numberOfParticles + 1]; numberOfClusters = 0; for (int i = 0; i < numberOfParticles; i++) { do { x[i] = (int) (Math.random() * L); y[i] = (int) (Math.random() * L); } while (site[x[i]][y[i]] != -1); site[x[i]][y[i]] = numberOfClusters; firstParticle[numberOfClusters] = i; mass[numberOfClusters] = 1; nextParticle[i] = -1; // no more particles in cluster lastParticle[numberOfClusters] = i; numberOfClusters++; checkNeighbors(x[i], y[i]); } }
/** * Constructs OscillatorsMode with the given mode and number of particles. * * <p>The particle separation is one in this model. * * @param mode int * @param N int */ OscillatorsMode(int mode, int N) { amplitude = Math.sqrt(2.0 / (N + 1)); omega = 2 * Math.sqrt(OMEGA_SQUARED) * Math.abs(Math.sin(mode * Math.PI / N / 2)); wavenumber = Math.PI * mode / (N + 1); functionDrawer = new FunctionDrawer(this); functionDrawer.initialize(0, N + 1, 300, false); // draws the initial displacement functionDrawer.color = Color.LIGHT_GRAY; }
/** Draws clusters */ public void draw(DrawingPanel panel, Graphics g) { if (site == null) { return; } int sizeX = Math.abs(panel.xToPix(1.0) - panel.xToPix(0)); int sizeY = Math.abs(panel.yToPix(1.0) - panel.yToPix(0)); for (int i = 0; i < numberOfParticles; i++) { int xpix = panel.xToPix(x[i]) - sizeX; int ypix = panel.yToPix(y[i]) - sizeY; g.fillRect(xpix + sizeX / 2, ypix + sizeY / 2, sizeX, sizeY); } }
/** * Overrides TPoint showCoordinates method. * * @param vidPanel the video panel */ public void showCoordinates(VideoPanel vidPanel) { // put values into pointmass x and y fields Point2D p = getWorldPosition(vidPanel); track.xField.setValue(p.getX()); track.yField.setValue(p.getY()); track.magField.setValue(p.distance(0, 0)); double theta = Math.atan2(p.getY(), p.getX()); track.angleField.setValue(theta); super.showCoordinates(vidPanel); }
/** * Gets the dimension of the lattice in pixel units. * * @param panel * @return the dimension */ public Dimension getInterior(DrawingPanel panel) { float availableWidth = panel.getWidth() - panel.getLeftGutter() - panel.getRightGutter() - 1; float availableHeight = panel.getHeight() - panel.getTopGutter() - panel.getBottomGutter() - 1; scaleFactor = Math.min(availableWidth / dimension.width, availableHeight / dimension.height); if (scaleFactor > 1) { scaleFactor = 1; return dimension; } return new Dimension((int) (scaleFactor * ncol), (int) (scaleFactor * nrow)); }
public ScientificRenderer(int sigfigs) { sigfigs = Math.min(sigfigs, 6); if (format instanceof DecimalFormat) { String pattern = "0.0"; // $NON-NLS-1$ for (int i = 0; i < sigfigs - 1; i++) { pattern += "0"; // $NON-NLS-1$ } pattern += "E0"; // $NON-NLS-1$ ((DecimalFormat) format).applyPattern(pattern); } }
/** * Calculates statistical values for a data array. * * @param data the data array * @return the max, min, mean, SD, SE and non-NaN data count */ private double[] getStatistics(double[] data) { double max = -Double.MAX_VALUE; double min = Double.MAX_VALUE; double sum = 0.0; double squareSum = 0.0; int count = 0; for (int i = 0; i < data.length; i++) { if (Double.isNaN(data[i])) { continue; } count++; max = Math.max(max, data[i]); min = Math.min(min, data[i]); sum += data[i]; squareSum += data[i] * data[i]; } double mean = sum / count; double sd = count < 2 ? Double.NaN : Math.sqrt((squareSum - count * mean * mean) / (count - 1)); if (max == -Double.MAX_VALUE) max = Double.NaN; if (min == Double.MAX_VALUE) min = Double.NaN; return new double[] {max, min, mean, sd, sd / Math.sqrt(count), count}; }
/** Moves a cluster chosen at random in a random direction */ public void step() { int cluster = (int) (Math.random() * numberOfClusters); int direction = (int) (Math.random() * 4); int dx = nnx[direction]; int dy = nny[direction]; int particle = firstParticle[cluster]; do { site[x[particle]][y[particle]] = -1; x[particle] = PBC.position(x[particle] + dx, L); y[particle] = PBC.position(y[particle] + dy, L); particle = nextParticle[particle]; } while (particle != -1); particle = firstParticle[cluster]; do { site[x[particle]][y[particle]] = cluster; // labels new sites occupied by cluster particle = nextParticle[particle]; } while (particle != -1); particle = firstParticle[cluster]; do { checkNeighbors(x[particle], y[particle]); // checks for merger particle = nextParticle[particle]; } while (particle != -1); }
/** * Evaluates the displacement for an oscillator at postion x * * @param x postion along chain * @return the displacement */ public double evaluate(double x) { return amplitude * Math.sin(x * wavenumber); }
/** * Sets the default point index. This defines the index of the points array used to get the point * initially selected when the step is created. * * @param index the index */ public void setDefaultPointIndex(int index) { index = Math.min(index, points.length - 1); defaultIndex = Math.max(0, index); }
/** * Gets a list of Point2D objects that lie within pixels in a rectangle and along a line. * * @param searchRect the rectangle * @param x0 the x-component of a point on the line * @param y0 the y-component of a point on the line * @param slope the slope of the line * @return a list of Point2D */ public ArrayList<Point2D> getSearchPoints( Rectangle searchRect, double x0, double y0, double theta) { double slope = -Math.tan(theta); // create line to search along Line2D line = new Line2D.Double(); if (slope > LARGE_NUMBER) { line.setLine(x0, y0, x0, y0 + 1); } else if (slope < 1 / LARGE_NUMBER) { line.setLine(x0, y0, x0 + 1, y0); } else { line.setLine(x0, y0, x0 + 1, y0 + slope); } // create intersection points (to set line ends) Point2D p1 = new Point2D.Double(); Point2D p2 = new Point2D.Double(Double.NaN, Double.NaN); Point2D p = p1; boolean foundBoth = false; double d = searchRect.x; Object[] data = getDistanceAndPointAtX(line, d); if (data != null) { p.setLocation((Point2D) data[1]); if (p.getY() >= searchRect.y && p.getY() <= searchRect.y + searchRect.height) { // line end is left edge p = p2; } } d += searchRect.width; data = getDistanceAndPointAtX(line, d); if (data != null) { p.setLocation((Point2D) data[1]); if (p.getY() >= searchRect.y && p.getY() <= searchRect.y + searchRect.height) { // line end is right edge if (p == p1) p = p2; else foundBoth = true; } } if (!foundBoth) { d = searchRect.y; data = getDistanceAndPointAtY(line, d); if (data != null) { p.setLocation((Point2D) data[1]); if (p.getX() >= searchRect.x && p.getX() <= searchRect.x + searchRect.width) { // line end is top edge if (p == p1) p = p2; else if (!p1.equals(p2)) foundBoth = true; } } } if (!foundBoth) { d += searchRect.height; data = getDistanceAndPointAtY(line, d); if (data != null) { p.setLocation((Point2D) data[1]); if (p.getX() >= searchRect.x && p.getX() <= searchRect.x + searchRect.width) { // line end is bottom edge if (p == p2 && !p1.equals(p2)) foundBoth = true; } } } // if both line ends have been found, use line to find pixels to search if (foundBoth) { // set line ends to intersections line.setLine(p1, p2); if (p1.getX() > p2.getX()) { line.setLine(p2, p1); } // find pixel intersections that fall along the line int xMin = (int) Math.ceil(Math.min(p1.getX(), p2.getX())); int xMax = (int) Math.floor(Math.max(p1.getX(), p2.getX())); int yMin = (int) Math.ceil(Math.min(p1.getY(), p2.getY())); int yMax = (int) Math.floor(Math.max(p1.getY(), p2.getY())); // collect intersections in TreeMap sorted by position along line TreeMap<Double, Point2D> intersections = new TreeMap<Double, Point2D>(); for (int x = xMin; x <= xMax; x++) { Object[] next = getDistanceAndPointAtX(line, x); intersections.put((Double) next[0], (Point2D) next[1]); } for (int y = yMin; y <= yMax; y++) { Object[] next = getDistanceAndPointAtY(line, y); intersections.put((Double) next[0], (Point2D) next[1]); } p = null; // create array of search points that are midway between intersections ArrayList<Point2D> searchPts = new ArrayList<Point2D>(); for (Double key : intersections.keySet()) { Point2D next = intersections.get(key); if (p != null) { double x = (p.getX() + next.getX()) / 2 - searchRect.x; double y = (p.getY() + next.getY()) / 2 - searchRect.y; p.setLocation(x, y); searchPts.add(p); } p = next; } return searchPts; } return null; }
/** * Gets the template location at which the best match occurs in a rectangle and along a line. May * return null. * * @param target the image to search * @param searchRect the rectangle to search within the target image * @param x0 the x-component of a point on the line * @param y0 the y-component of a point on the line * @param slope the slope of the line * @param spread the spread of the line (line width = 1+2*spread) * @return the optimized template location of the best match, if any */ public TPoint getMatchLocation( BufferedImage target, Rectangle searchRect, double x0, double y0, double theta, int spread) { wTarget = target.getWidth(); hTarget = target.getHeight(); // determine insets needed to accommodate template int left = wTemplate / 2, right = left; if (wTemplate % 2 > 0) right++; int top = hTemplate / 2, bottom = top; if (hTemplate % 2 > 0) bottom++; // trim search rectangle if necessary searchRect.x = Math.max(left, Math.min(wTarget - right, searchRect.x)); searchRect.y = Math.max(top, Math.min(hTarget - bottom, searchRect.y)); searchRect.width = Math.min(wTarget - searchRect.x - right, searchRect.width); searchRect.height = Math.min(hTarget - searchRect.y - bottom, searchRect.height); if (searchRect.width <= 0 || searchRect.height <= 0) { peakHeight = Double.NaN; peakWidth = Double.NaN; return null; } // set up test pixels to search (rectangle plus template) int xMin = Math.max(0, searchRect.x - left); int xMax = Math.min(wTarget, searchRect.x + searchRect.width + right); int yMin = Math.max(0, searchRect.y - top); int yMax = Math.min(hTarget, searchRect.y + searchRect.height + bottom); wTest = xMax - xMin; hTest = yMax - yMin; if (target.getType() != BufferedImage.TYPE_INT_RGB) { BufferedImage image = new BufferedImage(wTarget, hTarget, BufferedImage.TYPE_INT_RGB); image.createGraphics().drawImage(target, 0, 0, null); target = image; } targetPixels = new int[wTest * hTest]; target.getRaster().getDataElements(xMin, yMin, wTest, hTest, targetPixels); // get the points to search along the line ArrayList<Point2D> searchPts = getSearchPoints(searchRect, x0, y0, theta); if (searchPts == null) { peakHeight = Double.NaN; peakWidth = Double.NaN; return null; } // collect differences in a map as they are measured HashMap<Point2D, Double> diffs = new HashMap<Point2D, Double>(); // find the point with the minimum difference from template double matchDiff = largeNumber; // larger than typical differences int xMatch = 0, yMatch = 0; double avgDiff = 0; Point2D matchPt = null; for (Point2D pt : searchPts) { int x = (int) pt.getX(); int y = (int) pt.getY(); double diff = getDifferenceAtTestPoint(x, y); diffs.put(pt, diff); avgDiff += diff; if (diff < matchDiff) { matchDiff = diff; xMatch = x; yMatch = y; matchPt = pt; } } avgDiff /= searchPts.size(); peakHeight = avgDiff / matchDiff - 1; peakWidth = Double.NaN; double dl = 0; int matchIndex = searchPts.indexOf(matchPt); // if match is not exact, fit a Gaussian and find peak if (!Double.isInfinite(peakHeight) && matchIndex > 0 && matchIndex < searchPts.size() - 1) { // fill data arrays Point2D pt = searchPts.get(matchIndex - 1); double diff = diffs.get(pt); xValues[0] = -pt.distance(matchPt); yValues[0] = avgDiff / diff - 1; xValues[1] = 0; yValues[1] = peakHeight; pt = searchPts.get(matchIndex + 1); diff = diffs.get(pt); xValues[2] = pt.distance(matchPt); yValues[2] = avgDiff / diff - 1; // determine approximate offset (dl) and width (w) values double pull = -xValues[0] / (yValues[1] - yValues[0]); double push = xValues[2] / (yValues[1] - yValues[2]); if (Double.isNaN(pull)) pull = LARGE_NUMBER; if (Double.isNaN(push)) push = LARGE_NUMBER; dl = 0.3 * (xValues[2] - xValues[0]) * (push - pull) / (push + pull); double ratio = dl > 0 ? peakHeight / yValues[0] : peakHeight / yValues[2]; double w = dl > 0 ? dl - xValues[0] : dl - xValues[2]; w = w * w / Math.log(ratio); // set parameters and fit to x data dataset.clear(); dataset.append(xValues, yValues); double rmsDev = 1; for (int k = 0; k < 3; k++) { double c = k == 0 ? w : k == 1 ? w / 3 : w * 3; f.setParameterValue(0, peakHeight); f.setParameterValue(1, dl); f.setParameterValue(2, c); rmsDev = fitter.fit(f); if (rmsDev < 0.01) { // fitter succeeded (3-point fit should be exact) dl = f.getParameterValue(1); peakWidth = f.getParameterValue(2); break; } } } double dx = dl * Math.cos(theta); double dy = dl * Math.sin(theta); double xImage = xMatch + searchRect.x - left - trimLeft + dx; double yImage = yMatch + searchRect.y - top - trimTop + dy; return new TPoint(xImage, yImage); }
/** * Gets the template location at which the best match occurs in a rectangle. May return null. * * @param target the image to search * @param searchRect the rectangle to search within the target image * @return the optimized template location at which the best match, if any, is found */ public TPoint getMatchLocation(BufferedImage target, Rectangle searchRect) { wTarget = target.getWidth(); hTarget = target.getHeight(); // determine insets needed to accommodate template int left = wTemplate / 2, right = left; if (wTemplate % 2 > 0) right++; int top = hTemplate / 2, bottom = top; if (hTemplate % 2 > 0) bottom++; // trim search rectangle if necessary searchRect.x = Math.max(left, Math.min(wTarget - right, searchRect.x)); searchRect.y = Math.max(top, Math.min(hTarget - bottom, searchRect.y)); searchRect.width = Math.min(wTarget - searchRect.x - right, searchRect.width); searchRect.height = Math.min(hTarget - searchRect.y - bottom, searchRect.height); if (searchRect.width <= 0 || searchRect.height <= 0) { peakHeight = Double.NaN; peakWidth = Double.NaN; return null; } // set up test pixels to search (rectangle plus template) int xMin = Math.max(0, searchRect.x - left); int xMax = Math.min(wTarget, searchRect.x + searchRect.width + right); int yMin = Math.max(0, searchRect.y - top); int yMax = Math.min(hTarget, searchRect.y + searchRect.height + bottom); wTest = xMax - xMin; hTest = yMax - yMin; if (target.getType() != BufferedImage.TYPE_INT_RGB) { BufferedImage image = new BufferedImage(wTarget, hTarget, BufferedImage.TYPE_INT_RGB); image.createGraphics().drawImage(target, 0, 0, null); target = image; } targetPixels = new int[wTest * hTest]; target.getRaster().getDataElements(xMin, yMin, wTest, hTest, targetPixels); // find the rectangle point with the minimum difference double matchDiff = largeNumber; // larger than typical differences int xMatch = 0, yMatch = 0; double avgDiff = 0; for (int x = 0; x <= searchRect.width; x++) { for (int y = 0; y <= searchRect.height; y++) { double diff = getDifferenceAtTestPoint(x, y); avgDiff += diff; if (diff < matchDiff) { matchDiff = diff; xMatch = x; yMatch = y; } } } avgDiff /= (searchRect.width * searchRect.height); peakHeight = avgDiff / matchDiff - 1; peakWidth = Double.NaN; double dx = 0, dy = 0; // if match is not exact, fit a Gaussian and find peak if (!Double.isInfinite(peakHeight)) { // fill data arrays xValues[1] = yValues[1] = peakHeight; for (int i = -1; i < 2; i++) { if (i == 0) continue; double diff = getDifferenceAtTestPoint(xMatch + i, yMatch); xValues[i + 1] = avgDiff / diff - 1; diff = getDifferenceAtTestPoint(xMatch, yMatch + i); yValues[i + 1] = avgDiff / diff - 1; } // estimate peakHeight = peak of gaussian // estimate offset dx of gaussian double pull = 1 / (xValues[1] - xValues[0]); double push = 1 / (xValues[1] - xValues[2]); if (Double.isNaN(pull)) pull = LARGE_NUMBER; if (Double.isNaN(push)) push = LARGE_NUMBER; dx = 0.6 * (push - pull) / (push + pull); // estimate width wx of gaussian double ratio = dx > 0 ? peakHeight / xValues[0] : peakHeight / xValues[2]; double wx = dx > 0 ? dx + 1 : dx - 1; wx = wx * wx / Math.log(ratio); // estimate offset dy of gaussian pull = 1 / (yValues[1] - yValues[0]); push = 1 / (yValues[1] - yValues[2]); if (Double.isNaN(pull)) pull = LARGE_NUMBER; if (Double.isNaN(push)) push = LARGE_NUMBER; dy = 0.6 * (push - pull) / (push + pull); // estimate width wy of gaussian ratio = dy > 0 ? peakHeight / yValues[0] : peakHeight / yValues[2]; double wy = dy > 0 ? dy + 1 : dy - 1; wy = wy * wy / Math.log(ratio); // set x parameters and fit to x data dataset.clear(); dataset.append(pixelOffsets, xValues); double rmsDev = 1; for (int k = 0; k < 3; k++) { double c = k == 0 ? wx : k == 1 ? wx / 3 : wx * 3; f.setParameterValue(0, peakHeight); f.setParameterValue(1, dx); f.setParameterValue(2, c); rmsDev = fitter.fit(f); if (rmsDev < 0.01) { // fitter succeeded (3-point fit should be exact) dx = f.getParameterValue(1); peakWidth = f.getParameterValue(2); break; } } if (!Double.isNaN(peakWidth)) { // set y parameters and fit to y data dataset.clear(); dataset.append(pixelOffsets, yValues); for (int k = 0; k < 3; k++) { double c = k == 0 ? wy : k == 1 ? wy / 3 : wy * 3; f.setParameterValue(0, peakHeight); f.setParameterValue(1, dx); f.setParameterValue(2, c); rmsDev = fitter.fit(f); if (rmsDev < 0.01) { // fitter succeeded (3-point fit should be exact) dy = f.getParameterValue(1); peakWidth = (peakWidth + f.getParameterValue(2)) / 2; break; } } if (rmsDev > 0.01) peakWidth = Double.NaN; } } double xImage = xMatch + searchRect.x - left - trimLeft + dx; double yImage = yMatch + searchRect.y - top - trimTop + dy; return new TPoint(xImage, yImage); }
/** * Rebuilds the template from an input image. The input image dimensions must match the original. * The input and original are overlaid onto the existing template, if any. Pixels that fall * outside the mask are ignored in the final template. * * @param image the input image * @param alphaInput the opacity with which the input image is overlaid * @param alphaOriginal the opacity with which the original image is overlaid */ public void rebuildTemplate(BufferedImage image, int alphaInput, int alphaOriginal) { int w = image.getWidth(); int h = image.getHeight(); // return if image dimensions do not match original image if (original.getWidth() != w || original.getHeight() != h) return; // return if both alphas are zero if (alphaInput == 0 && alphaOriginal == 0) return; // draw image onto argb input BufferedImage input = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); input.createGraphics().drawImage(image, 0, 0, null); // create working image if needed if (working == null) { working = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); } // reset template dimensions and create new template if needed if (template == null || w != wTemplate || h != hTemplate) { wTemplate = w; hTemplate = h; int len = w * h; template = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); pixels = new int[len]; templateR = new int[len]; templateG = new int[len]; templateB = new int[len]; isPixelTransparent = new boolean[len]; } // set alpha of input and draw onto working Graphics2D gWorking = working.createGraphics(); alphaInput = Math.max(0, Math.min(255, alphaInput)); if (alphaInput > 0) { // overlay only if not transparent gWorking.setComposite(getComposite(alphaInput)); input.getRaster().getDataElements(0, 0, w, h, pixels); gWorking.drawImage(input, 0, 0, null); } // set alpha of original and draw onto working alphaOriginal = Math.max(0, Math.min(255, alphaOriginal)); if (alphaOriginal > 0) { // overlay only if not transparent gWorking.setComposite(getComposite(alphaOriginal)); original.getRaster().getDataElements(0, 0, w, h, pixels); gWorking.drawImage(original, 0, 0, null); } // read pixels from working raster working.getRaster().getDataElements(0, 0, wTemplate, hTemplate, pixels); if (mask != null) { // set pixels outside mask to transparent for (int i = 0; i < pixels.length; i++) { boolean inside = true; // pixel is inside only if all corners are inside int x = i % wTemplate, y = i / wTemplate; for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { p.setLocation(x + j, y + k); inside = inside && mask.contains(p); } } if (!inside) pixels[i] = pixels[i] & (0 << 24); // set alpha to zero (transparent) } } // write pixels to template raster template.getRaster().setDataElements(0, 0, wTemplate, hTemplate, pixels); // trim transparent edges from template int trimRight = 0, trimBottom = 0; trimLeft = trimTop = 0; // left edge boolean transparentEdge = true; while (transparentEdge && trimLeft < wTemplate) { for (int line = 0; line < hTemplate; line++) { int i = line * wTemplate + trimLeft; transparentEdge = transparentEdge && getAlpha(pixels[i]) == 0; } if (transparentEdge) trimLeft++; } // right edge transparentEdge = true; while (transparentEdge && (trimLeft + trimRight) < wTemplate) { for (int line = 0; line < hTemplate; line++) { int i = (line + 1) * wTemplate - 1 - trimRight; transparentEdge = transparentEdge && getAlpha(pixels[i]) == 0; } if (transparentEdge) trimRight++; } // top edge transparentEdge = true; while (transparentEdge && trimTop < hTemplate) { for (int col = 0; col < wTemplate; col++) { int i = trimTop * wTemplate + col; transparentEdge = transparentEdge && getAlpha(pixels[i]) == 0; } if (transparentEdge) trimTop++; } // bottom edge transparentEdge = true; while (transparentEdge && (trimTop + trimBottom) < hTemplate) { for (int col = 0; col < wTemplate; col++) { int i = (hTemplate - 1 - trimBottom) * wTemplate + col; transparentEdge = transparentEdge && getAlpha(pixels[i]) == 0; } if (transparentEdge) trimBottom++; } // reduce size of template if needed if (trimLeft + trimRight + trimTop + trimBottom > 0) { wTemplate -= (trimLeft + trimRight); hTemplate -= (trimTop + trimBottom); pixels = new int[wTemplate * hTemplate]; templateR = new int[wTemplate * hTemplate]; templateG = new int[wTemplate * hTemplate]; templateB = new int[wTemplate * hTemplate]; isPixelTransparent = new boolean[wTemplate * hTemplate]; BufferedImage bi = new BufferedImage(wTemplate, hTemplate, BufferedImage.TYPE_INT_ARGB); bi.createGraphics().drawImage(template, -trimLeft, -trimTop, null); template = bi; template.getRaster().getDataElements(0, 0, wTemplate, hTemplate, pixels); } // set up rgb and transparency arrays for faster matching for (int i = 0; i < pixels.length; i++) { int val = pixels[i]; templateR[i] = getRed(val); // red templateG[i] = getGreen(val); // green templateB[i] = getBlue(val); // blue isPixelTransparent[i] = getAlpha(val) == 0; // alpha } }