/* * Copyright 2005, 2009 Cosmin Basca. * e-mail: cosmin.basca@gmail.com * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * Please see COPYING for the complete licence. */ package robo.vision; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.text.DateFormat; import java.util.Calendar; import java.util.Vector; import javax.media.jai.ImageLayout; import javax.media.jai.UntiledOpImage; /** Find lines in an image with a Hough transform. */ @SuppressWarnings("unchecked") public class HoughLinesOpImage extends UntiledOpImage { @SuppressWarnings("unused") private int houghThreshold = 5, magnitudeThreshold = 5, greyOut = 255; private int accumulator[][]; private Vector<LineDescriptor> lines; public HoughLinesOpImage(RenderedImage source, ImageLayout layout, Integer edgeThreshold, Integer maximaThreshold, Integer outputIntensity) { super(source, null, layout); this.magnitudeThreshold = edgeThreshold.intValue(); this.houghThreshold = maximaThreshold.intValue(); this.greyOut = outputIntensity.intValue(); } protected void computeImage(Raster[] srcarr, WritableRaster dst, Rectangle destRect) { @SuppressWarnings("unused") int IDLE_STOP_SEARCH = 2000; //************************************* Raster src = srcarr[0]; System.out.println(DateFormat.getDateInstance().format(Calendar.getInstance().getTime())); // get edge points double edge[][]; Vector<Point> _edge = new Vector<Point>(); int width = src.getWidth(); int heigth = src.getHeight(); for(int i=0;i<width;i++) { for(int j=0;j<heigth;j++) { int sample = src.getSample(i,j,0); if(sample==RoboRaster.WHITE) //if(sample>=100) _edge.addElement(new Point(i,j)); } } int edgePoints = _edge.size(); edge = new double[_edge.size()][3]; for(int i=0;i<_edge.size();i++) { edge[i][0] = ((Point)_edge.elementAt(i)).x; edge[i][1] = ((Point)_edge.elementAt(i)).y; edge[i][2] = 1; // punct activ } // RHT - Randomized Hough Transform // max nr of pairs about 50 % of img int maxPairs = (int)((double)edgePoints * 0.5) - (int)((double)edgePoints * 0.15); if(edgePoints > 3000) maxPairs = 1300; @SuppressWarnings("unused") int currentPair = 0; // cuantizare spatiu hough int houghWidth = 500; int houghHeigth = (int)(Math.sqrt(2)*(double)Math.max(width,heigth))*2 ; int thetaStep = (int)(Math.PI / (double)houghWidth); accumulator = new int[houghWidth][houghHeigth]; clear(accumulator); System.out.println("Pairs : "+maxPairs); System.out.println("Searching : "+edgePoints); System.out.println("Acc len : ["+houghWidth+","+houghHeigth+"]"); @SuppressWarnings("unused") int idleStopCounter = 0; int p1 = 0; @SuppressWarnings("unused") int p2 = 0; int r = 0; int minR = 40; int maxR = 200; @SuppressWarnings("unused") double dP1P2 = 0.0; int validLineThreshold = 100; // detect lines for(p1 = 0; p1<edgePoints ;p1++) { for(int th = 0; th<houghWidth ;th++) { r = (int)Math.round(edge[p1][0] * Math.cos(thetaStep * th) + edge[p1][1] * Math.sin(thetaStep * th)); if( r > maxR || r < minR ) continue; accumulator[th][r] ++; } } // treshold lines for(int th = 0; th<houghWidth ;th++) { for(r = 0; r<houghHeigth ;r++) { if(accumulator[th][r] >= validLineThreshold) { // salvez info despre linie LineDescriptor ld = new LineDescriptor(th,r); lines.addElement(ld); } } } // find intersection point of all lines // and draw lines to int points } private void clear(int acc[][]) { for(int i=0;i<acc.length;i++) for(int j=0;j<acc[i].length;j++) acc[i][j] = 0; } } /* // old implementation Raster src = srcarr[0]; RoboRaster source = new RoboRaster(src); WritableRoboRaster dest = new WritableRoboRaster(dst); int width = source.getWidth(), height = source.getHeight(); int length = width * height; int gradient; double direction; double maxR = 1.5 * width, minR = -1.5 * width; double maxTheta = Math.PI / 2., minTheta = -1.*Math.PI / 2.; int quant = 360; double rangeTheta = maxTheta - minTheta, rangeR = maxR - minR; double incTheta = rangeTheta / quant, incR = rangeR / quant; int accum[] = new int[quant * quant]; int thresh[] = new int[quant * quant]; dest.setRect(getSourceImage(0).getData()); for (int v = 1; v < height - 1; v++) { for (int u = 1; u < width - 1; u++) { double sy = (source.grey(u - 1, v) * -2 + source.grey(u + 1, v) * 2 + source.grey(u - 1, v - 1) * -1 + source.grey(u + 1, v - 1) + source.grey(u - 1, v + 1) * -1 + source.grey(u + 1, v - 1)) / 8.0; double sx = (source.grey(u - 1, v - 1) + source.grey(u, v - 1) * 2 + source.grey(u + 1, v - 1) + source.grey(u - 1, v + 1) * -1 + source.grey(u, v + 1) * -2 + source.grey(u + 1, v - 1) * -1) / 8.0; gradient = (int) Math.sqrt(sx * sx + sy * sy); if (sy == 0) { if (sx == 0) direction = 0.; else direction = (sx > 0) ? 0.5 * Math.PI : -0.5 * Math.PI; } else if (sx == 0) { direction = 0.0; } else { direction = Math.atan(sy / sx); } direction += Math.PI / 2.0; //force direction to go from PI/2 to -PI/2 if (direction > Math.PI / 2.0) direction -= Math.PI; if (direction < Math.PI / -2.0) direction += Math.PI; //if the mag is bigger than threshold, increment accumulator array if (gradient > magnitudeThreshold) { double theta = direction; double r = u * Math.cos(theta) + v * Math.sin(theta); try { accum[(int)(quant * (int)((r + maxR) / incR) + //rounding is good! (theta + maxTheta) / incTheta)]++; } catch (ArrayIndexOutOfBoundsException e) { //System.out.println("r= " + r + ", theta= " + theta); } } } } //threshold the hough space; find the local maxima for (int x = 0; x < quant * quant; x++) { if (x % quant > 1 && x % quant < quant - 1 && x > quant && x < quant * quant - quant && accum[x] >= houghThreshold && accum[x] > accum[x + 1] && accum[x] > accum[x - 1] && accum[x] > accum[x + quant] && accum[x] > accum[x - quant] && accum[x] > accum[x + quant + 1] && accum[x] > accum[x - quant + 1] && accum[x] > accum[x + quant - 1] && accum[x] > accum[x - quant - 1]) { thresh[x] = 255; } } for (int x = 0; x < quant * quant; x++) { if (thresh[x] != 0) { for (int x0 = 0; x0 < width; x0++) { double r = minR + incR * (int)(x / quant); double theta = minTheta + incTheta * (x % quant); int y0 = -1 * (int)((x0 * Math.cos(theta) - r) / Math.sin(theta)); if (y0 * width + x0 >= 0 && y0 * width + x0 < length) { dest.setGrey(x0, y0, greyOut); } } } } */