Skip to content

Commit

Permalink
Fix lines identification + refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
nfeybesse committed May 15, 2018
1 parent 5d2011c commit 3a3df94
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 372 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.genericsystem.cv.application;

public class HoughTrajectStep implements Comparable<HoughTrajectStep> {
final int y;
final double derivative;
final double magnitude;

public HoughTrajectStep(int y, double derivative, double magnitude) {
this.y = y;
this.derivative = derivative;
this.magnitude = magnitude;
}

@Override
public int compareTo(HoughTrajectStep step) {
return Double.compare(step.magnitude, magnitude);
}

public double getTheta() {
return Math.atan(derivative) / Math.PI * 180 + 45;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
package org.genericsystem.cv.application;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.apache.commons.math3.analysis.interpolation.LinearInterpolator;
import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction;
import org.genericsystem.cv.Img;
Expand All @@ -19,17 +30,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class RadonTransform {

static {
Expand Down Expand Up @@ -259,23 +259,38 @@ public static TrajectStep[] bestTrajectRadon(Mat projectionMap, double anglePena
return thetas;
}

public static TrajectStep[] bestTrajectFHT(Mat projectionMap, double anglePenality) {
List<Double> penality = IntStream.range(0, projectionMap.cols()).mapToObj(theta -> anglePenality * Math.abs(Math.atan((double) (theta - 45) / 45) - Math.atan((double) (theta + 1 - 45) / (45))) * 180 / Math.PI).collect(Collectors.toList());
double[][] score = new double[projectionMap.rows()][projectionMap.cols()];
int[][] thetaPrev = new int[projectionMap.rows()][projectionMap.cols()];
for (int theta = 0; theta < projectionMap.cols(); theta++)
score[0][theta] = projectionMap.get(0, theta)[0];
for (int k = 1; k < projectionMap.rows(); k++) {
for (int theta = 0; theta < projectionMap.cols(); theta++) {
double magnitude = projectionMap.get(k, theta)[0];
static Mat adaptivHough(Mat houghTransform, int blurSize) {
Mat adaptivHough = new Mat();
Mat blur = new Mat();
Imgproc.blur(houghTransform, blur, new Size(1, blurSize), new Point(-1, -1), Core.BORDER_ISOLATED);
Core.absdiff(houghTransform, blur, adaptivHough);
blur.release();
// adaptivHough.row(0).setTo(new Scalar(0));
// adaptivHough.row(houghTransform.rows() - 1).setTo(new Scalar(0));
// Core.pow(adaptivHough, 2, adaptivHough);
return adaptivHough;
}

public static List<HoughTrajectStep> bestTrajectFHT(Mat houghTransform, int blurSize, double anglePenality) {
int stripWidth = (houghTransform.cols() + 1) / 2;
Mat adaptivHough = adaptivHough(houghTransform, blurSize);
List<Double> penality = IntStream.range(0, adaptivHough.cols())
.mapToObj(theta -> anglePenality * Math.abs(Math.atan((double) (theta - stripWidth + 1) / (stripWidth - 1)) - Math.atan((double) (theta - stripWidth + 2) / (stripWidth - 1))) * 180 / Math.PI).collect(Collectors.toList());
double[][] score = new double[adaptivHough.rows()][adaptivHough.cols()];
int[][] thetaPrev = new int[adaptivHough.rows()][adaptivHough.cols()];
for (int theta = 0; theta < adaptivHough.cols(); theta++)
score[0][theta] = adaptivHough.get(0, theta)[0];
for (int k = 1; k < adaptivHough.rows(); k++) {
for (int theta = 0; theta < adaptivHough.cols(); theta++) {
double magnitude = adaptivHough.get(k, theta)[0];

double scoreFromPrevTheta = theta != 0 ? score[k - 1][theta - 1] : Double.NEGATIVE_INFINITY;
double scoreFromSameTheta = score[k - 1][theta];
double scoreFromNextTheta = theta < projectionMap.cols() - 1 ? score[k - 1][theta + 1] : Double.NEGATIVE_INFINITY;
double scoreFromNextTheta = theta < adaptivHough.cols() - 1 ? score[k - 1][theta + 1] : Double.NEGATIVE_INFINITY;

double bestScore4Pos = -1;
double prevPenality = theta == 0 ? Double.NEGATIVE_INFINITY : penality.get(theta - 1);
double nextPenality = theta <= projectionMap.cols() ? penality.get(theta) : Double.NEGATIVE_INFINITY;
double nextPenality = theta <= adaptivHough.cols() ? penality.get(theta) : Double.NEGATIVE_INFINITY;

if (scoreFromSameTheta >= (scoreFromPrevTheta + prevPenality) && scoreFromSameTheta >= (scoreFromNextTheta + nextPenality)) {
bestScore4Pos = scoreFromSameTheta;
Expand All @@ -291,23 +306,26 @@ public static TrajectStep[] bestTrajectFHT(Mat projectionMap, double anglePenali
}
}

adaptivHough.release();

double maxScore = Double.NEGATIVE_INFINITY;
int prevTheta = -1;
for (int theta = 0; theta < projectionMap.cols(); theta++) {
double lastScore = score[projectionMap.rows() - 1][theta];
for (int theta = 0; theta < houghTransform.cols(); theta++) {
double lastScore = score[houghTransform.rows() - 1][theta];
if (lastScore > maxScore) {
maxScore = lastScore;
prevTheta = theta;
}
}

assert prevTheta != -1;
TrajectStep[] thetas = new TrajectStep[projectionMap.rows()];
for (int k = projectionMap.rows() - 1; k >= 0; k--) {
thetas[k] = new TrajectStep(k, prevTheta, projectionMap.get(k, prevTheta)[0]);
prevTheta = thetaPrev[k][prevTheta];
HoughTrajectStep[] result = new HoughTrajectStep[houghTransform.rows()];
for (int y = houghTransform.rows() - 1; y >= 0; y--) {
double derivative = ((double) prevTheta - (stripWidth - 1)) / (stripWidth - 1);
result[y] = new HoughTrajectStep(y, derivative, houghTransform.get(y, prevTheta)[0]);
prevTheta = thetaPrev[y][prevTheta];
}

return thetas;
return Arrays.asList(result);
}

public static List<Mat> extractStrips(Mat src, int stripNumber, double stripWidth, double step) {
Expand Down Expand Up @@ -406,20 +424,20 @@ public static List<OrientedPoint> toVerticalOrientedPoints(Function<Double, Doub
return orientedPoints;
}

public static List<OrientedPoint> toHorizontalOrientedPoints(TrajectStep[] trajectSteps, double x) {
public static List<OrientedPoint> toHorizontalOrientedPoints(List<HoughTrajectStep> trajectSteps, double x) {
List<OrientedPoint> orientedPoints = new ArrayList<>();
Arrays.stream(trajectSteps).filter(ts -> ts.magnitude >= 0.1).sorted().limit(100).forEach(trajectStep -> {
double angle = ((double) trajectStep.theta - 45) / 180 * Math.PI;
orientedPoints.add(new OrientedPoint(new Point(x, trajectStep.k), angle, trajectStep.magnitude));
trajectSteps.stream().filter(ts -> ts.magnitude >= 0.1).sorted().limit(30).forEach(trajectStep -> {
double angle = (trajectStep.getTheta() - 45) / 180 * Math.PI;
orientedPoints.add(new OrientedPoint(new Point(x, trajectStep.y), angle, trajectStep.magnitude));
});
return orientedPoints;
}

public static List<OrientedPoint> toVerticalOrientedPoints(TrajectStep[] trajectSteps, double y) {
public static List<OrientedPoint> toVerticalOrientedPoints(List<HoughTrajectStep> trajectSteps, double y) {
List<OrientedPoint> orientedPoints = new ArrayList<>();
Arrays.stream(trajectSteps).filter(ts -> ts.magnitude >= 0.1).sorted().limit(100).forEach(trajectStep -> {
double angle = -((double) trajectStep.theta - 45) / 180 * Math.PI;
orientedPoints.add(new OrientedPoint(new Point(trajectStep.k, y), angle, trajectStep.magnitude));
trajectSteps.stream().filter(ts -> ts.magnitude >= 0.1).sorted().limit(30).forEach(trajectStep -> {
double angle = -(trajectStep.getTheta() - 45) / 180 * Math.PI;
orientedPoints.add(new OrientedPoint(new Point(trajectStep.y, y), angle, trajectStep.magnitude));
});
return orientedPoints;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package org.genericsystem.cv.application;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction;
import org.genericsystem.cv.AbstractApp;
import org.genericsystem.cv.Img;
Expand All @@ -11,15 +20,6 @@
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import javafx.application.Platform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
Expand Down Expand Up @@ -149,29 +149,22 @@ private Image[] doWork() {

List<TrajectStep[]> vTrajs = vProjectionMaps.stream().map(projectionMap -> RadonTransform.bestTrajectRadon(projectionMap, -1000)).collect(Collectors.toList());
List<TrajectStep[]> hTrajs = hProjectionMaps.stream().map(projectionMap -> RadonTransform.bestTrajectRadon(projectionMap, -1000)).collect(Collectors.toList());
List<TrajectStep[]> vHoughTrajs = vHoughs.stream().map(projectionMap -> RadonTransform.bestTrajectFHT(projectionMap, -1000)).collect(Collectors.toList());
List<TrajectStep[]> hHoughTrajs = hHoughs.stream().map(projectionMap -> RadonTransform.bestTrajectFHT(projectionMap, -1000)).collect(Collectors.toList());
List<List<HoughTrajectStep>> vHoughTrajs = vHoughs.stream().map(projectionMap -> RadonTransform.bestTrajectFHT(projectionMap, 11, -50)).collect(Collectors.toList());
List<List<HoughTrajectStep>> hHoughTrajs = hHoughs.stream().map(projectionMap -> RadonTransform.bestTrajectFHT(projectionMap, 11, -50)).collect(Collectors.toList());
ref = trace("Compute trajects", ref);
for (TrajectStep[] houghVtraj : vHoughTrajs)
for (int y = 0; y < houghVtraj.length; y++)
houghVtraj[y].theta = (int) Math.round(Math.atan((double) (houghVtraj[y].theta - 45) / 45) / Math.PI * 180 + 45);

for (TrajectStep[] houghHtraj : hHoughTrajs)
for (int y = 0; y < houghHtraj.length; y++)
houghHtraj[y].theta = (int) Math.round(Math.atan((double) (houghHtraj[y].theta - 45) / 45) / Math.PI * 180 + 45);

ref = trace("Transform trajects", ref);
List<Function<Double, Double>> approxVFunctions = vTrajs.stream().map(traj -> RadonTransform.approxTraject(traj)).collect(Collectors.toList());
List<Function<Double, Double>> approxHFunctions = hTrajs.stream().map(traj -> RadonTransform.approxTraject(traj)).collect(Collectors.toList());
List<Function<Double, Double>> approxVFHTFunctions = vHoughTrajs.stream().map(traj -> RadonTransform.approxTraject(traj)).collect(Collectors.toList());
List<Function<Double, Double>> approxHFHTFunctions = hHoughTrajs.stream().map(traj -> RadonTransform.approxTraject(traj)).collect(Collectors.toList());
// List<Function<Double, Double>> approxVFHTFunctions = vHoughTrajs.stream().map(traj -> RadonTransform.approxTraject(traj)).collect(Collectors.toList());
// List<Function<Double, Double>> approxHFHTFunctions = hHoughTrajs.stream().map(traj -> RadonTransform.approxTraject(traj)).collect(Collectors.toList());

ref = trace("Compute approxs", ref);

List<PolynomialSplineFunction> vRadonSplinesFunctions = RadonTransform.toPolynomialSplineFunction(approxVFunctions, binarized.getSrc().size(), 20, minAngle, vStrips.size(), 0.5f);
List<PolynomialSplineFunction> hRadonSplinesFunctions = RadonTransform.toPolynomialSplineFunction(approxHFunctions, transposedBinarized.getSrc().size(), 20, minAngle, hStrips.size(), 0.5f);
List<PolynomialSplineFunction> vFHTSplinesFunctions = RadonTransform.toPolynomialSplineFunction(approxVFHTFunctions, binarized.getSrc().size(), 20, minAngle, vStrips.size(), 0.5f);
List<PolynomialSplineFunction> hFHTSplinesFunctions = RadonTransform.toPolynomialSplineFunction(approxHFHTFunctions, transposedBinarized.getSrc().size(), 20, minAngle, hStrips.size(), 0.5f);
// List<PolynomialSplineFunction> vFHTSplinesFunctions = RadonTransform.toPolynomialSplineFunction(approxVFHTFunctions, binarized.getSrc().size(), 20, minAngle, vStrips.size(), 0.5f);
// List<PolynomialSplineFunction> hFHTSplinesFunctions = RadonTransform.toPolynomialSplineFunction(approxHFHTFunctions, transposedBinarized.getSrc().size(), 20, minAngle, hStrips.size(), 0.5f);

Mat image = superFrame.getFrame().getSrc().clone();
RadonTransform.displayHSplines(vRadonSplinesFunctions, image);
Expand All @@ -192,8 +185,8 @@ private Image[] doWork() {
images[10] = new Img(image, false).toJfxImage();

Mat image2 = superFrame.getFrame().getSrc().clone();
RadonTransform.displayHSplines(vFHTSplinesFunctions, image2);
RadonTransform.displayVSplines(hFHTSplinesFunctions, image2);
// RadonTransform.displayHSplines(vFHTSplinesFunctions, image2);
// RadonTransform.displayVSplines(hFHTSplinesFunctions, image2);
images[11] = new Img(image2, false).toJfxImage();

ref = trace("Compute cubic spline lines", ref);
Expand All @@ -212,12 +205,12 @@ private Image[] doWork() {

vStrip = 0;
List<OrientedPoint> fhtHorizontals = new ArrayList<>();
for (Function<Double, Double> f : approxVFHTFunctions)
fhtHorizontals.addAll(RadonTransform.toHorizontalOrientedPoints(f, (vStrip++ + 1) * hStep, binarized.height(), (int) hStep));
// for (Function<Double, Double> f : approxVFHTFunctions)
// fhtHorizontals.addAll(RadonTransform.toHorizontalOrientedPoints(f, (vStrip++ + 1) * hStep, binarized.height(), (int) hStep));
hStrip = 0;
List<OrientedPoint> fhtVerticals = new ArrayList<>();
for (Function<Double, Double> f : approxHFHTFunctions)
fhtVerticals.addAll(RadonTransform.toVerticalOrientedPoints(f, (hStrip++ + 1) * vStep, binarized.width(), (int) vStep));
// for (Function<Double, Double> f : approxHFHTFunctions)
// fhtVerticals.addAll(RadonTransform.toVerticalOrientedPoints(f, (hStrip++ + 1) * vStep, binarized.width(), (int) vStep));

GeneralInterpolator interpolatorFHT = new GeneralInterpolator(fhtHorizontals, fhtVerticals, 3, 10);

Expand Down Expand Up @@ -253,33 +246,33 @@ private Image[] doWork() {

images[1] = frameDisplay.toJfxImage();

Img frameDisplayFHT = new Img(superFrame.getFrame().getSrc().clone(), false);
vStrip = 0;
for (Function<Double, Double> f : approxVFHTFunctions) {
for (int k = (int) hStep; k + hStep <= binarized.height(); k += hStep) {
double angle = (f.apply((double) k) - minAngle) / 180 * Math.PI;
Imgproc.line(frameDisplayFHT.getSrc(), new Point((vStrip + 1) * stripWidth / 2 - Math.cos(angle) * stripWidth / 6, k - Math.sin(angle) * stripWidth / 6),
new Point((vStrip + 1) * stripWidth / 2 + Math.cos(angle) * stripWidth / 6, k + Math.sin(angle) * stripWidth / 6), new Scalar(0, 255, 0), 2);
angle = interpolatorFHT.interpolateVerticals((vStrip + 1) * stripWidth / 2, k);
Imgproc.line(frameDisplayFHT.getSrc(), new Point((vStrip + 1) * stripWidth / 2 - Math.cos(angle) * stripWidth / 6, k - Math.sin(angle) * stripWidth / 6),
new Point((vStrip + 1) * stripWidth / 2 + Math.cos(angle) * stripWidth / 6, k + Math.sin(angle) * stripWidth / 6), new Scalar(255, 0, 0), 2);
}
vStrip++;
}
hStrip = 0;
for (Function<Double, Double> f : approxHFHTFunctions) {
for (int k = (int) vStep; k + vStep <= binarized.width(); k += vStep) {
double angle = (90 + minAngle - (f.apply((double) k))) / 180 * Math.PI;
Imgproc.line(frameDisplayFHT.getSrc(), new Point(k - Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 - Math.sin(angle) * stripHeight / 6),
new Point(k + Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 + Math.sin(angle) * stripHeight / 6), new Scalar(0, 0, 255), 2);
angle = interpolatorFHT.interpolateHorizontals(k, (hStrip + 1) * stripHeight / 2);
Imgproc.line(frameDisplayFHT.getSrc(), new Point(k - Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 - Math.sin(angle) * stripHeight / 6),
new Point(k + Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 + Math.sin(angle) * stripHeight / 6), new Scalar(255, 0, 0), 2);

}
hStrip++;
}
images[2] = frameDisplayFHT.toJfxImage();
// Img frameDisplayFHT = new Img(superFrame.getFrame().getSrc().clone(), false);
// vStrip = 0;
// for (Function<Double, Double> f : approxVFHTFunctions) {
// for (int k = (int) hStep; k + hStep <= binarized.height(); k += hStep) {
// double angle = (f.apply((double) k) - minAngle) / 180 * Math.PI;
// Imgproc.line(frameDisplayFHT.getSrc(), new Point((vStrip + 1) * stripWidth / 2 - Math.cos(angle) * stripWidth / 6, k - Math.sin(angle) * stripWidth / 6),
// new Point((vStrip + 1) * stripWidth / 2 + Math.cos(angle) * stripWidth / 6, k + Math.sin(angle) * stripWidth / 6), new Scalar(0, 255, 0), 2);
// angle = interpolatorFHT.interpolateVerticals((vStrip + 1) * stripWidth / 2, k);
// Imgproc.line(frameDisplayFHT.getSrc(), new Point((vStrip + 1) * stripWidth / 2 - Math.cos(angle) * stripWidth / 6, k - Math.sin(angle) * stripWidth / 6),
// new Point((vStrip + 1) * stripWidth / 2 + Math.cos(angle) * stripWidth / 6, k + Math.sin(angle) * stripWidth / 6), new Scalar(255, 0, 0), 2);
// }
// vStrip++;
// }
// hStrip = 0;
// for (Function<Double, Double> f : approxHFHTFunctions) {
// for (int k = (int) vStep; k + vStep <= binarized.width(); k += vStep) {
// double angle = (90 + minAngle - (f.apply((double) k))) / 180 * Math.PI;
// Imgproc.line(frameDisplayFHT.getSrc(), new Point(k - Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 - Math.sin(angle) * stripHeight / 6),
// new Point(k + Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 + Math.sin(angle) * stripHeight / 6), new Scalar(0, 0, 255), 2);
// angle = interpolatorFHT.interpolateHorizontals(k, (hStrip + 1) * stripHeight / 2);
// Imgproc.line(frameDisplayFHT.getSrc(), new Point(k - Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 - Math.sin(angle) * stripHeight / 6),
// new Point(k + Math.cos(angle) * stripHeight / 6, (hStrip + 1) * stripHeight / 2 + Math.sin(angle) * stripHeight / 6), new Scalar(255, 0, 0), 2);
//
// }
// hStrip++;
// }
// images[2] = frameDisplayFHT.toJfxImage();

ref = trace("Display lines", ref);

Expand Down
Loading

0 comments on commit 3a3df94

Please sign in to comment.