public static Image houghLineDetector(Image original, double epsilon, double threshold) { // Apply border detector Image borderImage = MaskUtils.applyMasks(original, MaskFactory.buildSobelMasks(), SynthetizationType.ABS); borderImage = ThresholdUtils.global(borderImage, Image.MAX_VAL / 2, 1); double D = Math.max(borderImage.getWidth(), borderImage.getHeight()); Range roRange = new Range(-Math.sqrt(2) * D, Math.sqrt(2) * D); Range thetaRange = new Range(-90, 90); int roSize = (int) (Math.abs(roRange.getLength())); int thetaSize = (int) (Math.abs(thetaRange.getLength())); int[][] A = new int[roSize][thetaSize]; // Step 3 for (int x = 0; x < borderImage.getWidth(); x++) { for (int y = 0; y < borderImage.getHeight(); y++) { if (isWhite(borderImage, x, y)) { // Iterates theta (j) from 1 to m for (int theta = 0; theta < thetaSize; theta++) { double thetaValue = thetaRange.getLowerBound() + theta; double thetaTerm = x * Math.cos(thetaValue * Math.PI / 180) - y * Math.sin(thetaValue * Math.PI / 180); // Iterates ro (i) from 1 to n for (int ro = 0; ro < roSize; ro++) { double roValue = roRange.getLowerBound() + ro; double total = roValue - thetaTerm; // If verifies the normal equation of the line, add // 1 to the acumulator // Step 4 if (Math.abs(total) < epsilon) { // The maximum values from this vector, gives // the most voted positions. A[ro][theta] += 1; } } } } } } // Step 5 Set<BucketForLines> allBuckets = new HashSet<BucketForLines>(); for (int ro = 0; ro < roSize; ro++) { for (int theta = 0; theta < thetaSize; theta++) { BucketForLines newBucket = new BucketForLines(ro, theta, A[ro][theta]); allBuckets.add(newBucket); } } // Generates a descending sorted list. List<BucketForLines> allBucketsAsList = new ArrayList<BucketForLines>(allBuckets); Collections.sort(allBucketsAsList); Image houghed = original.clone(); // Gets the max vote number int maxVotes = allBucketsAsList.get(0).votes; if (maxVotes > 1) { for (BucketForLines b : allBucketsAsList) { // Only for those with max votes if (b.votes < maxVotes * threshold) { break; } double roValue = roRange.getLowerBound() + b.ro; double thetaValue = thetaRange.getLowerBound() + b.theta; for (int x = 0; x < borderImage.getWidth(); x++) { for (int y = 0; y < borderImage.getHeight(); y++) { double thetaTerm = x * Math.cos(thetaValue * Math.PI / 180) - y * Math.sin(thetaValue * Math.PI / 180); double total = roValue - thetaTerm; // Step 6 if (Math.abs(total) < epsilon) { paintRed(houghed, x, y); } } } } } return houghed; }
public static Image houghCircleDetector( Image original, double epsilon, double threshold, int rMin, int rMax) { // Apply border detector Image borderImage = MaskUtils.applyMasks(original, MaskFactory.buildSobelMasks(), SynthetizationType.ABS); borderImage = ThresholdUtils.global(borderImage, Image.MAX_VAL / 2, 1); Range aRange = new Range(rMin, borderImage.getWidth() - rMin); Range bRange = new Range(rMin, borderImage.getHeight() - rMin); Range rRange = new Range(rMin, rMax); int aSize = (int) (Math.abs(aRange.getLength())); int bSize = (int) (Math.abs(bRange.getLength())); int rSize = (int) (Math.abs(rRange.getLength())); int[][][] A = new int[aSize][bSize][rSize]; for (int r = 0; r < rSize; r += 2) { double rValue = rRange.getLowerBound() + r; double rTerm = Math.pow(rValue, 2); for (int a = 0; a < aSize; a += 2) { double aValue = aRange.getLowerBound() + a; for (int b = 0; b < bSize; b += 2) { double bValue = bRange.getLowerBound() + b; for (int x = 0; x < borderImage.getWidth(); x += 2) { double aTerm = Math.pow(x - aValue, 2); for (int y = 0; y < borderImage.getHeight(); y += 2) { if (isWhite(borderImage, x, y)) { double bTerm = Math.pow(y - bValue, 2); double total = rTerm - aTerm - bTerm; if (Math.abs(total) < epsilon) { A[a][b][r] += 1; } } } } } } } System.out.println("Voted"); Set<BucketForCircles> allBuckets = new HashSet<BucketForCircles>(); for (int a = 0; a < aSize; a += 2) { for (int b = 0; b < bSize; b += 2) { for (int r = 0; r < rSize; r += 2) { if (A[a][b][r] > 0) { BucketForCircles newBucket = new BucketForCircles(a, b, r, A[a][b][r]); allBuckets.add(newBucket); } } } } Image houghed = original.clone(); if (allBuckets.isEmpty()) { System.out.println("Empty Buckets"); return houghed; } List<BucketForCircles> allBucketsAsList = new ArrayList<BucketForCircles>(allBuckets); Collections.sort(allBucketsAsList); int maxHits = allBucketsAsList.get(0).votes; System.out.println("maxHits:" + maxHits); if (maxHits > 2) for (BucketForCircles b : allBucketsAsList) { if (b.votes < maxHits * threshold) { break; } int aValue = rMin + b.a; int bValue = (int) bRange.getLowerBound() + b.b; int rValue = (int) rRange.getLowerBound() + b.r; System.out.println("Circle: (" + aValue + "," + bValue + "," + rValue + ")"); drawCircle(houghed, aValue, bValue, rValue); } return houghed; }