Skip to content

Commit

Permalink
Compare Fast Hough Transform / Radon results
Browse files Browse the repository at this point in the history
  • Loading branch information
nfeybesse committed Apr 16, 2018
1 parent e637e2c commit 05fdaf6
Show file tree
Hide file tree
Showing 6 changed files with 679 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.genericsystem.cv.application;

import org.genericsystem.cv.Lines;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DirectionalEnhancer {

public static Lines getLines(Mat frame) {
Mat mat = prepare(frame);
Mat houghLines = new Mat();
Imgproc.HoughLinesP(mat, houghLines, 1, Math.PI / 180, 10, 100, 10);
mat.release();
Lines lines = new Lines(houghLines);
houghLines.release();
return lines;
}

public static Mat prepare(Mat frame) {
Mat mat = new Mat();
Imgproc.cvtColor(frame, mat, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(mat, mat, new Size(13, 13), 0);
Imgproc.adaptiveThreshold(mat, mat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 51, 2);
Imgproc.morphologyEx(mat, mat, Imgproc.MORPH_CLOSE, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(9, 9)));
Imgproc.morphologyEx(mat, mat, Imgproc.MORPH_OPEN, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(5, 5)));
List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(mat, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
for (MatOfPoint contour : contours)
Imgproc.drawContours(mat, Arrays.asList(contour), 0, new Scalar(255, 0, 0), -1);
Imgproc.morphologyEx(mat, mat, Imgproc.MORPH_GRADIENT, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(4, 4)));
return mat;
}

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

import org.genericsystem.cv.AbstractApp;
import org.genericsystem.cv.Img;
import org.genericsystem.cv.Lines;
import org.genericsystem.cv.utils.NativeLibraryLoader;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
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.stream.Collectors;

import javafx.application.Platform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;

public class DirectionalEnhancerDemo extends AbstractApp {

public static void main(String[] args) {
launch(args);
}

static {
NativeLibraryLoader.load();
}

private final double f = 6.053 / 0.009;

private GSCapture gsCapture = new GSVideoCapture(0, f, GSVideoCapture.HD, GSVideoCapture.VGA);
private SuperFrameImg superFrame = gsCapture.read();
private ScheduledExecutorService timer = new BoundedScheduledThreadPoolExecutor();
private Config config = new Config();
private final ImageView[][] imageViews = new ImageView[][] { new ImageView[3], new ImageView[3], new ImageView[3], new ImageView[3] };

private void startTimer() {
timer.scheduleAtFixedRate(() -> {
try {
Image[] images = doWork();
if (images != null)
Platform.runLater(() -> {
Iterator<Image> it = Arrays.asList(images).iterator();
for (int row = 0; row < imageViews.length; row++)
for (int col = 0; col < imageViews[row].length; col++)
if (it.hasNext())
imageViews[row][col].setImage(it.next());
});
} catch (Throwable e) {
e.printStackTrace();
}
}, 1000, 30, TimeUnit.MILLISECONDS);
}

@Override
protected void fillGrid(GridPane mainGrid) {
double displaySizeReduction = 1.5;
for (int col = 0; col < imageViews.length; col++)
for (int row = 0; row < imageViews[col].length; row++) {
ImageView imageView = new ImageView();
imageViews[col][row] = imageView;
mainGrid.add(imageViews[col][row], col, row);
imageView.setFitWidth(superFrame.width() / displaySizeReduction);
imageView.setFitHeight(superFrame.height() / displaySizeReduction);
}
startTimer();
}

private Image[] doWork() {
System.out.println("do work");
if (!config.stabilizedMode) {
superFrame = gsCapture.read();
}
Image[] images = new Image[12];

long ref = System.currentTimeMillis();

// Mat mat = DirectionalEnhancer.prepare(superFrame.getFrame().getSrc());

Mat mat = new Mat();
Imgproc.cvtColor(superFrame.getFrame().getSrc(), mat, Imgproc.COLOR_BGR2GRAY);
Imgproc.GaussianBlur(mat, mat, new Size(13, 13), 0);
images[0] = new Img(mat, false).toJfxImage();
Imgproc.adaptiveThreshold(mat, mat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 7, 2);
images[1] = new Img(mat, false).toJfxImage();
Imgproc.morphologyEx(mat, mat, Imgproc.MORPH_CLOSE, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(9, 9)));
// images[2] = new Img(mat, false).toJfxImage();
// Imgproc.morphologyEx(mat, mat, Imgproc.MORPH_OPEN, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(5, 5)));

images[2] = new Img(mat, false).toJfxImage();

List<MatOfPoint> contours = new ArrayList<>();
Imgproc.findContours(mat, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
for (MatOfPoint contour : contours)
Imgproc.drawContours(mat, Arrays.asList(contour), 0, new Scalar(255, 0, 0), -1);
images[3] = new Img(mat, false).toJfxImage();
Mat gradient = new Mat();
Imgproc.morphologyEx(mat, gradient, Imgproc.MORPH_GRADIENT, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(4, 4)));

images[4] = new Img(gradient, false).toJfxImage();
Mat smallLines = new Mat();
Mat bigLines = new Mat();
Imgproc.HoughLinesP(gradient, bigLines, 1, Math.PI / 180, 10, 30, 10);
Imgproc.HoughLinesP(gradient, smallLines, 1, Math.PI / 180, 10, 30, 10);
Lines slines = new Lines(smallLines);
Lines blines = new Lines(bigLines);

Mat result = Mat.zeros(superFrame.getFrame().getSrc().size(), superFrame.getFrame().getSrc().type());
Lines horizontalLines = new Lines(blines.getLines().stream().filter(l -> Math.abs(l.y2 - l.y1) < Math.abs(l.x2 - l.x1)).collect(Collectors.toList()));
horizontalLines.draw(result, new Scalar(0, 255, 0), 2);

Lines verticalLines = new Lines(slines.getLines().stream().filter(l -> Math.abs(l.y2 - l.y1) > Math.abs(l.x2 - l.x1)).collect(Collectors.toList()));
verticalLines.draw(result, new Scalar(0, 0, 255), 2);

images[5] = new Img(result, false).toJfxImage();

horizontalLines.draw(mat, new Scalar(255), 2);
verticalLines.draw(mat, new Scalar(255), 2);
ref = trace("Draw lines", ref);

Imgproc.findContours(mat, contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
for (MatOfPoint contour : contours)
Imgproc.drawContours(mat, Arrays.asList(contour), 0, new Scalar(255, 0, 0), -1);

images[6] = new Img(mat, false).toJfxImage();

Imgproc.morphologyEx(mat, gradient, Imgproc.MORPH_GRADIENT, Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(3, 3)));

images[7] = new Img(gradient, false).toJfxImage();

Imgproc.HoughLinesP(gradient, bigLines, 1, Math.PI / 180, 100, 300, 50);
Imgproc.HoughLinesP(gradient, smallLines, 1, Math.PI / 180, 25, 40, 13);
slines = new Lines(smallLines);
blines = new Lines(bigLines);

result = Mat.zeros(superFrame.getFrame().getSrc().size(), superFrame.getFrame().getSrc().type());
horizontalLines = new Lines(blines.getLines().stream().filter(l -> Math.abs(l.y2 - l.y1) < Math.abs(l.x2 - l.x1)).collect(Collectors.toList()));
horizontalLines.draw(result, new Scalar(0, 255, 0), 2);

verticalLines = new Lines(slines.getLines().stream().filter(l -> Math.abs(l.y2 - l.y1) > Math.abs(l.x2 - l.x1)).collect(Collectors.toList()));
verticalLines.draw(result, new Scalar(0, 0, 255), 2);

images[8] = new Img(result, false).toJfxImage();

mat.release();
result.release();
return images;
}

private long trace(String message, long ref) {
long last = System.currentTimeMillis();
System.out.println(message + " : " + (last - ref));
return last;
}

@Override
protected void onS() {
config.stabilizedMode = !config.stabilizedMode;
}

@Override
protected void onSpace() {
if (config.isOn) {
timer.shutdown();
// gsCapture.release();
} else {
timer = new BoundedScheduledThreadPoolExecutor();
// gsCapture = new GSVideoCapture(0, f, GSVideoCapture.HD, GSVideoCapture.VGA);
startTimer();
}
config.isOn = !config.isOn;
}

@Override
protected void onT() {
config.textsEnabledMode = !config.textsEnabledMode;
}

@Override
public void stop() throws Exception {
super.stop();
timer.shutdown();
timer.awaitTermination(5000, TimeUnit.MILLISECONDS);
gsCapture.release();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import org.opencv.core.Point;
import org.opencv.core.Range;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.ximgproc.Ximgproc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -61,7 +61,7 @@ public static Mat projectionMap(Mat radon, int minAngle) {
return projectionMap;
}

public static int[] bestTraject(Mat projectionMap, double anglePenality, double pow) {
public static TrajectStep[] bestTraject(Mat projectionMap, double anglePenality, double pow) {
double[][] score = new double[projectionMap.rows()][projectionMap.cols()];
int[][] thetaPrev = new int[projectionMap.rows()][projectionMap.cols()];
for (int theta = 0; theta < projectionMap.cols(); theta++)
Expand Down Expand Up @@ -93,8 +93,9 @@ public static int[] bestTraject(Mat projectionMap, double anglePenality, double
// System.out.println(Arrays.toString(score[projectionMap.rows() - 1]));
// System.out.println(Arrays.deepToString(thetaPrev));
double maxScore = Double.NEGATIVE_INFINITY;

int prevTheta = -1;
int[] thetas = new int[projectionMap.rows()];

for (int theta = 0; theta < projectionMap.cols(); theta++) {
double lastScore = score[projectionMap.rows() - 1][theta];
// System.out.println(lastScore);
Expand All @@ -104,10 +105,10 @@ public static int[] bestTraject(Mat projectionMap, double anglePenality, double
}
}
assert prevTheta != -1;

// System.out.println(maxScore + " for theta : " + prevTheta);
TrajectStep[] thetas = new TrajectStep[projectionMap.rows()];
for (int k = projectionMap.rows() - 1; k >= 0; k--) {
thetas[k] = prevTheta;
thetas[k] = new TrajectStep(k, prevTheta, projectionMap.get(k, prevTheta)[0]);
// System.out.println(prevTheta);
prevTheta = thetaPrev[k][prevTheta];
}
Expand All @@ -126,7 +127,7 @@ public static Mat extractStrip(Mat src, int startX, int width) {
return new Mat(src, new Range(0, src.rows()), new Range(startX, startX + width));
}

public static List<PolynomialSplineFunction> estimateBaselines(Mat image, double anglePenalty, int minMaxAngle, double magnitudePow, int yStep) {
public static List<PolynomialSplineFunction> estimateBaselines(Mat image, double anglePenalty, int minAngle, int maxAngle, double magnitudePow, int yStep) {
Mat preprocessed = new Img(image, false).adaptativeGaussianInvThreshold(5, 3).getSrc();
List<PolynomialSplineFunction> hLines = new ArrayList<>();
// Number of overlapping vertical strips.
Expand All @@ -137,7 +138,7 @@ public static List<PolynomialSplineFunction> estimateBaselines(Mat image, double
// Image width = [n(1 - r) + r] w
double w = (image.width() / (n * (1 - r) + r));
double step = (int) ((1 - r) * w);
int[][] angles = new int[n][];
TrajectStep[][] angles = new TrajectStep[n][];

// 0, center of each vertical strip, image.width() - 1
double[] xs = new double[n + 2];
Expand All @@ -155,7 +156,7 @@ public static List<PolynomialSplineFunction> estimateBaselines(Mat image, double

List<double[]> values = new ArrayList<>();
for (int k = 0; k < image.height(); k++)
values.add(new double[] { k, angles[i][k] });
values.add(new double[] { k, angles[i][k].theta, angles[i][k].magnitude });
approxParams[i] = LevenbergImpl.fromBiFunction(f, values, new double[] { 0, 0, 0 }).getParams();
xs[i + 1] = x + .5 * w;
x += step;
Expand Down Expand Up @@ -195,12 +196,13 @@ public static List<PolynomialSplineFunction> estimateBaselines(Mat image, double
return hLines;
}

public static Function<Double, Double> approxTraject(int[] traj) {
public static Function<Double, Double> approxTraject(TrajectStep[] traj) {
List<double[]> values = new ArrayList<>();
for (int k = 0; k < traj.length; k++)
values.add(new double[] { k, traj[k] });
values.add(new double[] { k, traj[k].theta, traj[k].magnitude });
BiFunction<Double, double[], Double> f = (x, params) -> params[0] + params[1] * x + params[2] * x * x;
double[] params = LevenbergImpl.fromBiFunction(f, values, new double[] { 0, 0, 0 }).getParams();
BiFunction<double[], double[], Double> error = (xy, params) -> (f.apply(xy[0], params) - xy[1]);
double[] params = new LevenbergImpl<>(error, values, new double[] { 0, 0, 0 }).getParams();
return x -> f.apply(x, params);
}

Expand All @@ -222,7 +224,33 @@ public static List<OrientedPoint> toVerticalOrientedPoints(Function<Double, Doub
return orientedPoints;
}

public static List<OrientedPoint> toHorizontalFHTOrientedPoints(Function<Double, Double> f, int vStrip, int stripWidth, int height, int step, int minAngle) {
List<OrientedPoint> orientedPoints = new ArrayList<>();
for (int k = 0; k <= height; k += step) {
double angle = ((f.apply((double) k) / (2 * stripWidth - 1) * 90) - minAngle) / 180 * Math.PI;
orientedPoints.add(new OrientedPoint(new Point((vStrip + 1) * stripWidth / 2, k), angle, 1));
}
return orientedPoints;
}

public static List<OrientedPoint> toVerticalFHTOrientedPoints(Function<Double, Double> f, int hStrip, int stripHeight, int width, int step, int minAngle) {
List<OrientedPoint> orientedPoints = new ArrayList<>();
for (int k = 0; k <= width; k += step) {
double angle = (90 + minAngle - (f.apply((double) k) / (2 * stripHeight - 1) * 90)) / 180 * Math.PI;
orientedPoints.add(new OrientedPoint(new Point(k, (hStrip + 1) * stripHeight / 2), angle, 1));
}
return orientedPoints;
}

private static boolean inImage(Point p, Mat img) {
return p.x >= 0 && p.y >= 0 && p.x < img.width() && p.y < img.height();
}

public static Mat fastHoughTransform(Mat vStrip, int stripSize) {
Mat houghTransform = new Mat();
Ximgproc.FastHoughTransform(vStrip, houghTransform, CvType.CV_64FC1, Ximgproc.ARO_45_135, Ximgproc.FHT_ADD, Ximgproc.HDO_DESKEW);
Core.transpose(houghTransform, houghTransform);
Core.normalize(houghTransform, houghTransform, 0, 255, Core.NORM_MINMAX);
return new Mat(houghTransform, new Range(stripSize / 2, houghTransform.height() - stripSize / 2), new Range(0, houghTransform.width()));
}
}
Loading

0 comments on commit 05fdaf6

Please sign in to comment.