Example usage for org.opencv.core Point Point

List of usage examples for org.opencv.core Point Point

Introduction

In this page you can find the example usage for org.opencv.core Point Point.

Prototype

public Point(double x, double y) 

Source Link

Usage

From source file:com.seleniumtests.util.imaging.ImageDetector.java

License:Apache License

/**
 * Detect the object inside the scene/*from   w ww  .  j  av a2  s  .  co m*/
 * We also search the scale of the scene from 20% to 120% scale by steps
 * steps are 10%, with 0.6 accuracy
 * then when a good match is found, we search around by 5% scale steps with 0.7 accuracy
 * then when a good match is found, we search around by 2.5% scale steps with 0.8 accuracy
 * 
 * example:
 * first pass: scales are: 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200
 *             good matches are found around 600 and 700
 * second pass: scales are 550, 600, 650, 700, 750
 *             good matches are found at 650
 * third pass: scales are 625, 650, 675
 * 
 * The best match is at 675
 */
public void detectExactZoneWithScale() {

    Mat sceneImageMat = Imgcodecs.imread(sceneImage.getAbsolutePath(), Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);
    Mat objectImageMat = Imgcodecs.imread(objectImage.getAbsolutePath(), Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);

    List<TemplateMatchProperties> matches = Collections.synchronizedList(new ArrayList<>());

    Map<Integer, Double> scaleSteps = new LinkedHashMap<>();
    scaleSteps.put(100, 0.6);
    scaleSteps.put(50, 0.7);
    scaleSteps.put(25, 0.8);

    int currentStep = 100;

    Set<Integer> computedScales = new HashSet<>();

    while (currentStep >= 25) {
        final double currentThreshold = scaleSteps.get(currentStep);

        // first loop
        Set<Integer> localScales = Collections.synchronizedSet(new HashSet<>());
        if (currentStep == 100) {
            for (int scale = 200; scale < 1200; scale += currentStep) {
                localScales.add(scale);
            }
        } else {
            if (matches.isEmpty()) {
                throw new ImageSearchException("no matches");
            }
            for (TemplateMatchProperties tmpM : matches) {
                if (tmpM.isActive()) {
                    localScales.add(tmpM.getMatchScale() - currentStep);
                    localScales.add(tmpM.getMatchScale() + currentStep);
                }
            }
        }

        ExecutorService executorService = Executors
                .newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        for (int scale : localScales) {
            if (computedScales.contains(scale)) {
                continue;
            }
            computedScales.add(scale);

            // resize to scale factor
            final int localScale = scale;
            Size sz = new Size(sceneImageMat.cols() * scale / 1000.0,
                    sceneImageMat.rows() * localScale / 1000.0);

            // skip if resized image is smaller than object
            if (sz.width < objectImageMat.cols() || sz.height < objectImageMat.rows()) {
                continue;
            }

            executorService.submit(() -> {

                Mat resizeSceneImageMat = new Mat();
                Imgproc.resize(sceneImageMat, resizeSceneImageMat, sz);

                try {
                    TemplateMatchProperties match = detectExactZone2(resizeSceneImageMat, objectImageMat,
                            localScale, currentThreshold);
                    matches.add(match);
                } catch (ImageSearchException e) {
                }

            });
        }

        executorService.shutdown();
        try {
            executorService.awaitTermination(10, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.info("Could not compute scale within 10 seconds", e);
        }

        // shortcut if we find a very good match
        double cleanThreshold = currentThreshold;
        matches.sort((TemplateMatchProperties t1,
                TemplateMatchProperties t2) -> -(t1.getMatchValue().compareTo(t2.getMatchValue())));
        if (!matches.isEmpty() && matches.get(0).getMatchValue() > 0.9) {
            cleanThreshold = 0.9;
            currentStep = Math.min(currentStep, 50);
        }
        currentStep = currentStep / 2;

        // clean matches from too low matching values
        for (TemplateMatchProperties t : matches) {
            if (t.getMatchValue() < cleanThreshold) {
                t.setActive(false);
            }
        }
    }

    // get the best match
    matches.sort((TemplateMatchProperties t1,
            TemplateMatchProperties t2) -> -(t1.getMatchValue().compareTo(t2.getMatchValue())));

    if (!matches.isEmpty()) {
        TemplateMatchProperties bestMatch = matches.get(0);
        if (bestMatch.getMatchValue() < 1 - detectionThreshold) {
            throw new ImageSearchException(
                    String.format("No match found for threshold %.2f, match found with value %.2f",
                            1 - detectionThreshold, bestMatch.getMatchValue()));
        }

        detectedRectangle = new Rectangle((int) (bestMatch.getMatchLoc().x / bestMatch.getDoubleScale()),
                (int) (bestMatch.getMatchLoc().y / bestMatch.getDoubleScale()),
                (int) (objectImageMat.rows() / bestMatch.getDoubleScale()),
                (int) (objectImageMat.cols() / bestMatch.getDoubleScale()));

        if (debug) {
            try {
                Imgproc.rectangle(sceneImageMat, new Point(detectedRectangle.x, detectedRectangle.y),
                        new Point(detectedRectangle.x + detectedRectangle.width,
                                detectedRectangle.y + detectedRectangle.height),
                        new Scalar(0, 255, 0));

                showResultingPicture(sceneImageMat);
            } catch (IOException e) {
            }
        }
        rotationAngle = 0;
        sizeRatio = detectedRectangle.width / (double) objectImageMat.cols();

    } else {
        throw new ImageSearchException("no matching has been found");
    }

}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

/**
 * Perspective pattern discovery//from   w  w  w.  j  a  v  a2 s .c  o m
 * 
 * Works similar to arena calibration but does not try to identify the
 * outline of the projection area We are only concerned with size, not
 * alignment or angle
 * 
 * This function blanks out the pattern that it discovers in the Mat it is
 * provided. This is so that the pattern is not discovered by future pattern
 * discovery, e.g. auto-calibration
 * 
 * workingMat should be null for all external callers unless there is some
 * need to work off a different Mat than is having patterns blanked out by
 * this function
 */
public Optional<Dimension2D> findPaperPattern(MatOfPoint2f boardCorners, Mat mat, Mat workingMat) {

    if (workingMat == null)
        workingMat = mat.clone();

    initializeSize(workingMat.cols(), workingMat.rows());

    // Step 2: Estimate the pattern corners
    final BoundingBox box = getPaperPatternDimensions(workingMat, boardCorners);

    // OpenCV gives us the checkerboard corners, not the outside dimension
    // So this estimates where the outside corner would be, plus a fudge
    // factor for the edge of the paper
    // Printer margins are usually a quarter inch on each edge
    double width = ((double) box.getWidth() * ((double) (PATTERN_WIDTH + 1) / (double) (PATTERN_WIDTH - 1))
            * 1.048);
    double height = ((double) box.getHeight() * ((double) (PATTERN_HEIGHT + 1) / (double) (PATTERN_HEIGHT - 1))
            * 1.063);

    final double PAPER_PATTERN_SIZE_THRESHOLD = .25;
    if (width > PAPER_PATTERN_SIZE_THRESHOLD * workingMat.cols()
            || height > PAPER_PATTERN_SIZE_THRESHOLD * workingMat.rows()) {
        logger.trace("Pattern too big to be paper, must be projection, setting blank {} x {}", box.getWidth(),
                box.getHeight());

        workingMat.submat((int) box.getMinY(), (int) box.getMaxY(), (int) box.getMinX(), (int) box.getMaxX())
                .setTo(new Scalar(0, 0, 0));

        if (logger.isTraceEnabled()) {
            String filename = String.format("blanked-box.png");
            File file = new File(filename);
            filename = file.toString();
            Highgui.imwrite(filename, workingMat);

        }

        final Optional<MatOfPoint2f> boardCornersNew = findChessboard(workingMat);

        if (!boardCornersNew.isPresent())
            return Optional.empty();

        logger.trace("Found new pattern, attempting findPaperPattern {}", boardCornersNew.get());

        return findPaperPattern(boardCornersNew.get(), mat, workingMat);

    }

    if (logger.isTraceEnabled()) {
        logger.trace("pattern width {} height {}", box.getWidth(), box.getHeight());

        logger.trace("paper width {} height {}", width, height);

        int widthOffset = ((int) width - (int) box.getWidth()) / 2;
        int heightOffset = ((int) height - (int) box.getHeight()) / 2;

        logger.trace("offset width {} height {}", widthOffset, heightOffset);

        Mat fullpattern = workingMat.clone();

        // TODO: This doesn't work if the pattern is upside down, but this is for debugging anyway right now
        // Should fix in case it causes an out of bounds or something
        Point topLeft = new Point(boardCorners.get(0, 0)[0], boardCorners.get(0, 0)[1]);
        Point topRight = new Point(boardCorners.get(PATTERN_WIDTH - 1, 0)[0],
                boardCorners.get(PATTERN_WIDTH - 1, 0)[1]);
        Point bottomRight = new Point(boardCorners.get(PATTERN_WIDTH * PATTERN_HEIGHT - 1, 0)[0],
                boardCorners.get(PATTERN_WIDTH * PATTERN_HEIGHT - 1, 0)[1]);
        Point bottomLeft = new Point(boardCorners.get(PATTERN_WIDTH * (PATTERN_HEIGHT - 1), 0)[0],
                boardCorners.get(PATTERN_WIDTH * (PATTERN_HEIGHT - 1), 0)[1]);

        Core.circle(fullpattern, topLeft, 1, new Scalar(255, 0, 0), -1);
        Core.circle(fullpattern, topRight, 1, new Scalar(255, 0, 0), -1);
        Core.circle(fullpattern, bottomRight, 1, new Scalar(255, 0, 0), -1);
        Core.circle(fullpattern, bottomLeft, 1, new Scalar(255, 0, 0), -1);

        String filename = String.format("marked-box.png");
        File file = new File(filename);
        filename = file.toString();
        Highgui.imwrite(filename, fullpattern);

        fullpattern = fullpattern.submat((int) box.getMinY() - heightOffset,
                (int) box.getMinY() - heightOffset + (int) height, (int) box.getMinX() - widthOffset,
                (int) box.getMinX() - widthOffset + (int) width);

        filename = String.format("full-box.png");
        file = new File(filename);
        filename = file.toString();
        Highgui.imwrite(filename, fullpattern);

        Mat cropped = workingMat.submat((int) box.getMinY(), (int) box.getMaxY(), (int) box.getMinX(),
                (int) box.getMaxX());

        filename = String.format("pattern-box.png");
        file = new File(filename);
        filename = file.toString();
        Highgui.imwrite(filename, cropped);
    }

    mat.submat((int) box.getMinY(), (int) box.getMaxY(), (int) box.getMinX(), (int) box.getMaxX())
            .setTo(new Scalar(0, 0, 0));

    return Optional.of(new Dimension2D(width, height));
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private BoundingBox getPaperPatternDimensions(Mat traceMat, MatOfPoint2f boardCorners) {
    // Turn the chessboard into corners
    final MatOfPoint2f boardRect = calcBoardRectFromCorners(boardCorners);

    final Point pt1 = new Point(boardRect.get(0, 0)[0], boardRect.get(0, 0)[1]);
    final Point pt2 = new Point(boardRect.get(1, 0)[0], boardRect.get(1, 0)[1]);
    final Point pt3 = new Point(boardRect.get(2, 0)[0], boardRect.get(2, 0)[1]);
    final Point pt4 = new Point(boardRect.get(3, 0)[0], boardRect.get(3, 0)[1]);

    Point[] patternCorners = { pt1, pt2, pt3, pt4 };
    patternCorners = sortCorners(patternCorners);

    final Point topLeft = patternCorners[0];
    final Point topRight = patternCorners[1];
    final Point bottomLeft = patternCorners[2];
    final Point bottomRight = patternCorners[3];

    logger.trace("Paper Corners {} {} {} {}", topLeft, topRight, bottomRight, bottomLeft);

    final double topWidth = Math
            .sqrt(Math.pow(topRight.x - topLeft.x, 2) + Math.pow(topRight.y - topLeft.y, 2));
    final double leftHeight = Math
            .sqrt(Math.pow(bottomLeft.x - topLeft.x, 2) + Math.pow(bottomLeft.y - topLeft.y, 2));
    final double bottomWidth = Math
            .sqrt(Math.pow(bottomRight.x - bottomLeft.x, 2) + Math.pow(bottomRight.y - bottomLeft.y, 2));
    final double rightHeight = Math
            .sqrt(Math.pow(bottomRight.x - topRight.x, 2) + Math.pow(bottomRight.y - topRight.y, 2));

    final double width = ((topWidth + bottomWidth) / 2);
    final double height = ((leftHeight + rightHeight) / 2);

    return new BoundingBox(topLeft.x, topLeft.y, width, height);
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private MatOfPoint2f estimatePatternRect(Mat traceMat, MatOfPoint2f boardCorners) {
    // Turn the chessboard into corners
    final MatOfPoint2f boardRect = calcBoardRectFromCorners(boardCorners);

    // We use this to calculate the angle
    final RotatedRect boardBox = Imgproc.minAreaRect(boardRect);
    final double boardBoxAngle = boardBox.size.height > boardBox.size.width ? 90.0 + boardBox.angle
            : boardBox.angle;/*ww  w.  ja  va2 s.c  o  m*/

    // This is the board corners with the angle eliminated
    final Mat unRotMat = getRotationMatrix(massCenterMatOfPoint2f(boardRect), boardBoxAngle);
    final MatOfPoint2f unRotatedRect = rotateRect(unRotMat, boardRect);

    // This is the estimated projection area that has minimum angle (Not
    // rotated)
    final MatOfPoint2f estimatedPatternSizeRect = estimateFullPatternSize(unRotatedRect);

    // This is what we'll use as the transformation target and bounds given
    // back to the cameramanager
    boundsRect = Imgproc.minAreaRect(estimatedPatternSizeRect);

    // We now rotate the estimation back to the original angle to use for
    // transformation source
    final Mat rotMat = getRotationMatrix(massCenterMatOfPoint2f(estimatedPatternSizeRect), -boardBoxAngle);

    final MatOfPoint2f rotatedPatternSizeRect = rotateRect(rotMat, estimatedPatternSizeRect);

    if (logger.isTraceEnabled()) {
        logger.trace("center {} angle {} width {} height {}", boardBox.center, boardBoxAngle,
                boardBox.size.width, boardBox.size.height);

        logger.debug("boundsRect {} {} {} {}", boundsRect.boundingRect().x, boundsRect.boundingRect().y,
                boundsRect.boundingRect().x + boundsRect.boundingRect().width,
                boundsRect.boundingRect().y + boundsRect.boundingRect().height);

        Core.circle(traceMat, new Point(boardRect.get(0, 0)[0], boardRect.get(0, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);
        Core.circle(traceMat, new Point(boardRect.get(1, 0)[0], boardRect.get(1, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);
        Core.circle(traceMat, new Point(boardRect.get(2, 0)[0], boardRect.get(2, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);
        Core.circle(traceMat, new Point(boardRect.get(3, 0)[0], boardRect.get(3, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);

        Core.line(traceMat, new Point(unRotatedRect.get(0, 0)[0], unRotatedRect.get(0, 0)[1]),
                new Point(unRotatedRect.get(1, 0)[0], unRotatedRect.get(1, 0)[1]), new Scalar(0, 255, 0));
        Core.line(traceMat, new Point(unRotatedRect.get(1, 0)[0], unRotatedRect.get(1, 0)[1]),
                new Point(unRotatedRect.get(2, 0)[0], unRotatedRect.get(2, 0)[1]), new Scalar(0, 255, 0));
        Core.line(traceMat, new Point(unRotatedRect.get(3, 0)[0], unRotatedRect.get(3, 0)[1]),
                new Point(unRotatedRect.get(2, 0)[0], unRotatedRect.get(2, 0)[1]), new Scalar(0, 255, 0));
        Core.line(traceMat, new Point(unRotatedRect.get(3, 0)[0], unRotatedRect.get(3, 0)[1]),
                new Point(unRotatedRect.get(0, 0)[0], unRotatedRect.get(0, 0)[1]), new Scalar(0, 255, 0));

        Core.line(traceMat,
                new Point(estimatedPatternSizeRect.get(0, 0)[0], estimatedPatternSizeRect.get(0, 0)[1]),
                new Point(estimatedPatternSizeRect.get(1, 0)[0], estimatedPatternSizeRect.get(1, 0)[1]),
                new Scalar(255, 255, 0));
        Core.line(traceMat,
                new Point(estimatedPatternSizeRect.get(1, 0)[0], estimatedPatternSizeRect.get(1, 0)[1]),
                new Point(estimatedPatternSizeRect.get(2, 0)[0], estimatedPatternSizeRect.get(2, 0)[1]),
                new Scalar(255, 255, 0));
        Core.line(traceMat,
                new Point(estimatedPatternSizeRect.get(3, 0)[0], estimatedPatternSizeRect.get(3, 0)[1]),
                new Point(estimatedPatternSizeRect.get(2, 0)[0], estimatedPatternSizeRect.get(2, 0)[1]),
                new Scalar(255, 255, 0));
        Core.line(traceMat,
                new Point(estimatedPatternSizeRect.get(3, 0)[0], estimatedPatternSizeRect.get(3, 0)[1]),
                new Point(estimatedPatternSizeRect.get(0, 0)[0], estimatedPatternSizeRect.get(0, 0)[1]),
                new Scalar(255, 255, 0));

        Core.line(traceMat, new Point(rotatedPatternSizeRect.get(0, 0)[0], rotatedPatternSizeRect.get(0, 0)[1]),
                new Point(rotatedPatternSizeRect.get(1, 0)[0], rotatedPatternSizeRect.get(1, 0)[1]),
                new Scalar(255, 255, 0));
        Core.line(traceMat, new Point(rotatedPatternSizeRect.get(1, 0)[0], rotatedPatternSizeRect.get(1, 0)[1]),
                new Point(rotatedPatternSizeRect.get(2, 0)[0], rotatedPatternSizeRect.get(2, 0)[1]),
                new Scalar(255, 255, 0));
        Core.line(traceMat, new Point(rotatedPatternSizeRect.get(3, 0)[0], rotatedPatternSizeRect.get(3, 0)[1]),
                new Point(rotatedPatternSizeRect.get(2, 0)[0], rotatedPatternSizeRect.get(2, 0)[1]),
                new Scalar(255, 255, 0));
        Core.line(traceMat, new Point(rotatedPatternSizeRect.get(3, 0)[0], rotatedPatternSizeRect.get(3, 0)[1]),
                new Point(rotatedPatternSizeRect.get(0, 0)[0], rotatedPatternSizeRect.get(0, 0)[1]),
                new Scalar(255, 255, 0));
    }

    return rotatedPatternSizeRect;
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private MatOfPoint2f estimateFullPatternSize(MatOfPoint2f rect) {
    // Result Mat
    final MatOfPoint2f result = new MatOfPoint2f();
    result.alloc(4);//from   www  . ja v a  2s  .com

    // Get the sources as points
    final Point topLeft = new Point(rect.get(0, 0)[0], rect.get(0, 0)[1]);
    final Point topRight = new Point(rect.get(1, 0)[0], rect.get(1, 0)[1]);
    final Point bottomRight = new Point(rect.get(2, 0)[0], rect.get(2, 0)[1]);
    final Point bottomLeft = new Point(rect.get(3, 0)[0], rect.get(3, 0)[1]);

    // We need the heights and widths to estimate the square sizes

    final double topWidth = Math
            .sqrt(Math.pow(topRight.x - topLeft.x, 2) + Math.pow(topRight.y - topLeft.y, 2));
    final double leftHeight = Math
            .sqrt(Math.pow(bottomLeft.x - topLeft.x, 2) + Math.pow(bottomLeft.y - topLeft.y, 2));
    final double bottomWidth = Math
            .sqrt(Math.pow(bottomRight.x - bottomLeft.x, 2) + Math.pow(bottomRight.y - bottomLeft.y, 2));
    final double rightHeight = Math
            .sqrt(Math.pow(bottomRight.x - topRight.x, 2) + Math.pow(bottomRight.y - topRight.y, 2));

    if (logger.isTraceEnabled()) {
        logger.trace("points {} {} {} {}", topLeft, topRight, bottomRight, bottomLeft);

        double angle = Math.atan((topRight.y - topLeft.y) / (topRight.x - topLeft.x)) * 180 / Math.PI;
        double angle2 = Math.atan((bottomRight.y - bottomLeft.y) / (bottomRight.x - bottomLeft.x)) * 180
                / Math.PI;

        logger.trace("square size {} {} - angle {}", topWidth / (PATTERN_WIDTH - 1),
                leftHeight / (PATTERN_HEIGHT - 1), angle);
        logger.trace("square size {} {} - angle {}", bottomWidth / (PATTERN_WIDTH - 1),
                rightHeight / (PATTERN_HEIGHT - 1), angle2);
    }

    // Estimate the square widths, that is what we base the estimate of the
    // real corners on

    double squareTopWidth = (1 + BORDER_FACTOR) * (topWidth / (PATTERN_WIDTH - 1));
    double squareLeftHeight = (1 + BORDER_FACTOR) * (leftHeight / (PATTERN_HEIGHT - 1));
    double squareBottomWidth = (1 + BORDER_FACTOR) * (bottomWidth / (PATTERN_WIDTH - 1));
    double squareRightHeight = (1 + BORDER_FACTOR) * (rightHeight / (PATTERN_HEIGHT - 1));

    // The estimations
    double[] newTopLeft = { topLeft.x - squareTopWidth, topLeft.y - squareLeftHeight };
    double[] newBottomLeft = { bottomLeft.x - squareBottomWidth, bottomLeft.y + squareLeftHeight };
    double[] newTopRight = { topRight.x + squareTopWidth, topRight.y - squareRightHeight };
    double[] newBottomRight = { bottomRight.x + squareBottomWidth, bottomRight.y + squareRightHeight };

    // Populate the result
    result.put(0, 0, newTopLeft);
    result.put(1, 0, newTopRight);
    result.put(2, 0, newBottomRight);
    result.put(3, 0, newBottomLeft);

    // Calculate the new heights (We don't need the widths but I'll leave
    // the code here commented out)

    // double newTopWidth = Math.sqrt(Math.pow(newTopRight[0] -
    // newTopLeft[0],2) + Math.pow(newTopRight[1] - newTopLeft[1],2));
    // double newBottomWidth = Math.sqrt(Math.pow(newBottomRight[0] -
    // newBottomLeft[0],2) + Math.pow(newBottomRight[1] -
    // newBottomLeft[1],2));
    double newLeftHeight = Math.sqrt(
            Math.pow(newBottomLeft[0] - newTopLeft[0], 2) + Math.pow(newBottomLeft[1] - newTopLeft[1], 2));
    double newRightHeight = Math.sqrt(
            Math.pow(newBottomRight[0] - newTopRight[0], 2) + Math.pow(newBottomRight[1] - newTopRight[1], 2));

    // The minimum dimension is always from the height because the pattern
    // is shorter on that side
    // Technically it is possible that the pattern is super stretched out,
    // but in that case I think we're
    // better off failing
    minimumDimension = newLeftHeight < newRightHeight ? newLeftHeight : newRightHeight;

    return result;
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private MatOfPoint2f rotateRect(Mat rotMat, MatOfPoint2f boardRect) {
    final MatOfPoint2f result = new MatOfPoint2f();
    result.alloc(4);//from   w ww.j a  v  a2s  .c om
    for (int i = 0; i < 4; i++) {
        final Point rPoint = rotPoint(rotMat, new Point(boardRect.get(i, 0)[0], boardRect.get(i, 0)[1]));
        final double[] rPointD = new double[2];
        rPointD[0] = rPoint.x;
        rPointD[1] = rPoint.y;
        result.put(i, 0, rPointD);
    }
    return result;
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private Optional<MatOfPoint2f> findIdealCorners(final Mat frame, final MatOfPoint2f estimatedPatternRect) {
    Mat traceMat = null;/*from  w ww  .j  a  v  a 2 s  .com*/
    if (logger.isTraceEnabled()) {
        Mat traceMatTemp = frame.clone();
        traceMat = new Mat();

        Imgproc.cvtColor(traceMatTemp, traceMat, Imgproc.COLOR_GRAY2BGR);
    }

    // pixel distance, dynamic because we want to allow any resolution or
    // distance from pattern
    final int toleranceThreshold = (int) (minimumDimension / (double) (PATTERN_HEIGHT - 1) / 1.5);

    // Grey scale conversion.
    //final Mat grey = new Mat();
    //Imgproc.cvtColor(frame, grey, Imgproc.COLOR_BGR2GRAY);
    final Mat grey = frame;

    // Find edges
    Imgproc.Canny(grey, grey, CANNY_THRESHOLD_1, CANNY_THRESHOLD_2);

    // Blur the lines, otherwise the lines algorithm does not consider them
    Imgproc.GaussianBlur(grey, grey, gaussianBlurSize, GAUSSIANBLUR_SIGMA);

    if (logger.isTraceEnabled()) {
        logger.trace("tolerance threshold {} minimumDimension {}", toleranceThreshold, minimumDimension);

        String filename = String.format("calibrate-undist-grey-lines.png");
        File file = new File(filename);
        filename = file.toString();
        Highgui.imwrite(filename, grey);
    }

    if (logger.isDebugEnabled())
        logger.debug("estimation {} {} {} {}", estimatedPatternRect.get(0, 0), estimatedPatternRect.get(1, 0),
                estimatedPatternRect.get(2, 0), estimatedPatternRect.get(3, 0));

    // Easier to work off of Points
    final Point[] estimatedPoints = matOfPoint2fToPoints(estimatedPatternRect);

    if (logger.isTraceEnabled()) {
        Core.circle(traceMat, estimatedPoints[0], 1, new Scalar(0, 0, 255), -1);
        Core.circle(traceMat, estimatedPoints[1], 1, new Scalar(0, 0, 255), -1);
        Core.circle(traceMat, estimatedPoints[2], 1, new Scalar(0, 0, 255), -1);
        Core.circle(traceMat, estimatedPoints[3], 1, new Scalar(0, 0, 255), -1);
    }

    // Find lines
    // These parameters are just guesswork right now
    final Mat mLines = new Mat();
    final int minLineSize = (int) (minimumDimension * .90);
    final int lineGap = toleranceThreshold;

    // Do it
    Imgproc.HoughLinesP(grey, mLines, HOUGHLINES_RHO, HOUGHLINES_THETA, HOUGHLINES_THRESHOLD, minLineSize,
            lineGap);

    // Find the lines that match our estimates
    final Set<double[]> verifiedLines = new HashSet<double[]>();

    for (int x = 0; x < mLines.cols(); x++) {
        final double[] vec = mLines.get(0, x);
        final double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];
        final Point start = new Point(x1, y1);
        final Point end = new Point(x2, y2);

        if (nearPoints(estimatedPoints, start, toleranceThreshold)
                && nearPoints(estimatedPoints, end, toleranceThreshold)) {
            verifiedLines.add(vec);

            if (logger.isTraceEnabled()) {
                Core.line(traceMat, start, end, new Scalar(255, 0, 0), 1);
            }
        }
    }

    if (logger.isTraceEnabled())
        logger.trace("verifiedLines: {}", verifiedLines.size());

    // Reduce the lines to possible corners
    final Set<Point> possibleCorners = new HashSet<Point>();

    for (double[] line1 : verifiedLines) {
        for (double[] line2 : verifiedLines) {
            if (line1 == line2)
                continue;

            Optional<Point> intersection = computeIntersect(line1, line2);

            if (intersection.isPresent())
                possibleCorners.add(intersection.get());
        }
    }

    // Reduce the possible corners to ideal corners
    Point[] idealCorners = new Point[4];
    final double[] idealDistances = { toleranceThreshold, toleranceThreshold, toleranceThreshold,
            toleranceThreshold };

    for (Point pt : possibleCorners) {
        for (int i = 0; i < 4; i++) {
            final double distance = euclideanDistance(pt, estimatedPoints[i]);

            if (distance < idealDistances[i]) {
                idealDistances[i] = distance;
                idealCorners[i] = pt;
            }
        }
    }

    if (logger.isTraceEnabled()) {
        logger.trace("idealDistances {} {} {} {}", idealDistances[0], idealDistances[1], idealDistances[2],
                idealDistances[3]);

        String filename = String.format("calibrate-lines.png");
        File file = new File(filename);
        filename = file.toString();
        Highgui.imwrite(filename, traceMat);
    }

    // Verify that we have the corners we need
    for (Point pt : idealCorners) {
        if (pt == null)
            return Optional.empty();

        if (logger.isTraceEnabled()) {
            logger.trace("idealCorners {}", pt);
            Core.circle(traceMat, pt, 1, new Scalar(0, 255, 255), -1);
        }
    }

    if (logger.isTraceEnabled()) {
        String filename = String.format("calibrate-lines-with-corners.png");
        File file = new File(filename);
        filename = file.toString();
        Highgui.imwrite(filename, traceMat);
    }

    // Sort them into the correct order
    // 1st-------2nd
    // | |
    // | |
    // | |
    // 3rd-------4th
    idealCorners = sortCorners(idealCorners);

    // build the MatofPoint2f
    final MatOfPoint2f sourceCorners = new MatOfPoint2f();
    sourceCorners.alloc(4);

    for (int i = 0; i < 4; i++) {
        sourceCorners.put(i, 0, new double[] { idealCorners[i].x, idealCorners[i].y });
    }

    return Optional.of(sourceCorners);
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private Point[] sortCorners(final Point[] corners) {
    final Point[] result = new Point[4];

    final Point center = new Point(0, 0);
    for (Point corner : corners) {
        center.x += corner.x;/*from www .j  a v a2  s . c om*/
        center.y += corner.y;
    }

    center.x *= 1.0 / corners.length;
    center.y *= 1.0 / corners.length;

    final List<Point> top = new ArrayList<Point>();
    final List<Point> bot = new ArrayList<Point>();

    for (int i = 0; i < corners.length; i++) {
        if (corners[i].y < center.y)
            top.add(corners[i]);
        else
            bot.add(corners[i]);
    }

    result[0] = top.get(0).x > top.get(1).x ? top.get(1) : top.get(0);
    result[1] = top.get(0).x > top.get(1).x ? top.get(0) : top.get(1);
    result[2] = bot.get(0).x > bot.get(1).x ? bot.get(1) : bot.get(0);
    result[3] = bot.get(0).x > bot.get(1).x ? bot.get(0) : bot.get(1);

    return result;
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private void initializeWarpPerspective(final Mat frame, final MatOfPoint2f sourceCorners) {
    final MatOfPoint2f destCorners = new MatOfPoint2f();
    destCorners.alloc(4);// w  ww.j a v a2 s  . c  o m

    // 1st-------2nd
    // | |
    // | |
    // | |
    // 3rd-------4th
    destCorners.put(0, 0, new double[] { boundsRect.boundingRect().x, boundsRect.boundingRect().y });
    destCorners.put(1, 0, new double[] { boundsRect.boundingRect().x + boundsRect.boundingRect().width,
            boundsRect.boundingRect().y });
    destCorners.put(2, 0, new double[] { boundsRect.boundingRect().x,
            boundsRect.boundingRect().y + boundsRect.boundingRect().height });
    destCorners.put(3, 0, new double[] { boundsRect.boundingRect().x + boundsRect.boundingRect().width,
            boundsRect.boundingRect().y + boundsRect.boundingRect().height });

    if (logger.isDebugEnabled()) {
        logger.debug("initializeWarpPerspective {} {} {} {}", sourceCorners.get(0, 0), sourceCorners.get(1, 0),
                sourceCorners.get(2, 0), sourceCorners.get(3, 0));
        logger.debug("initializeWarpPerspective {} {} {} {}", destCorners.get(0, 0), destCorners.get(1, 0),
                destCorners.get(2, 0), destCorners.get(3, 0));
    }

    perspMat = Imgproc.getPerspectiveTransform(sourceCorners, destCorners);

    int width = boundsRect.boundingRect().width;
    int height = boundsRect.boundingRect().height;

    // Make them divisible by two for video recording purposes
    if ((width & 1) == 1)
        width++;
    if ((height & 1) == 1)
        height++;

    boundingBox = new BoundingBox(boundsRect.boundingRect().x, boundsRect.boundingRect().y, width, height);

    warpInitialized = true;

    if (logger.isTraceEnabled()) {
        Mat debugFrame = frame.clone();

        Core.circle(debugFrame, new Point(sourceCorners.get(0, 0)[0], sourceCorners.get(0, 0)[1]), 1,
                new Scalar(255, 0, 255), -1);
        Core.circle(debugFrame, new Point(sourceCorners.get(1, 0)[0], sourceCorners.get(1, 0)[1]), 1,
                new Scalar(255, 0, 255), -1);
        Core.circle(debugFrame, new Point(sourceCorners.get(2, 0)[0], sourceCorners.get(2, 0)[1]), 1,
                new Scalar(255, 0, 255), -1);
        Core.circle(debugFrame, new Point(sourceCorners.get(3, 0)[0], sourceCorners.get(3, 0)[1]), 1,
                new Scalar(255, 0, 255), -1);

        Core.circle(debugFrame, new Point(destCorners.get(0, 0)[0], destCorners.get(0, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);
        Core.circle(debugFrame, new Point(destCorners.get(1, 0)[0], destCorners.get(1, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);
        Core.circle(debugFrame, new Point(destCorners.get(2, 0)[0], destCorners.get(2, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);
        Core.circle(debugFrame, new Point(destCorners.get(3, 0)[0], destCorners.get(3, 0)[1]), 1,
                new Scalar(255, 0, 0), -1);

        Core.line(debugFrame, new Point(boundingBox.getMinX(), boundingBox.getMinY()),
                new Point(boundingBox.getMaxX(), boundingBox.getMinY()), new Scalar(0, 255, 0));
        Core.line(debugFrame, new Point(boundingBox.getMinX(), boundingBox.getMinY()),
                new Point(boundingBox.getMinX(), boundingBox.getMaxY()), new Scalar(0, 255, 0));
        Core.line(debugFrame, new Point(boundingBox.getMaxX(), boundingBox.getMaxY()),
                new Point(boundingBox.getMaxX(), boundingBox.getMinY()), new Scalar(0, 255, 0));
        Core.line(debugFrame, new Point(boundingBox.getMaxX(), boundingBox.getMaxY()),
                new Point(boundingBox.getMinX(), boundingBox.getMaxY()), new Scalar(0, 255, 0));

        String filename = String.format("calibrate-transformation.png");
        File file = new File(filename);
        filename = file.toString();
        Highgui.imwrite(filename, debugFrame);
    }
}

From source file:com.shootoff.camera.autocalibration.AutoCalibrationManager.java

License:Open Source License

private MatOfPoint2f calcBoardRectFromCorners(MatOfPoint2f corners) {
    MatOfPoint2f result = new MatOfPoint2f();
    result.alloc(4);/*from w  w w  .  j  a v  a  2s.  c o  m*/

    Point topLeft = new Point(corners.get(0, 0)[0], corners.get(0, 0)[1]);
    Point topRight = new Point(corners.get(PATTERN_WIDTH - 1, 0)[0], corners.get(PATTERN_WIDTH - 1, 0)[1]);
    Point bottomRight = new Point(corners.get(PATTERN_WIDTH * PATTERN_HEIGHT - 1, 0)[0],
            corners.get(PATTERN_WIDTH * PATTERN_HEIGHT - 1, 0)[1]);
    Point bottomLeft = new Point(corners.get(PATTERN_WIDTH * (PATTERN_HEIGHT - 1), 0)[0],
            corners.get(PATTERN_WIDTH * (PATTERN_HEIGHT - 1), 0)[1]);

    result.put(0, 0, topLeft.x, topLeft.y, topRight.x, topRight.y, bottomRight.x, bottomRight.y, bottomLeft.x,
            bottomLeft.y);

    return result;
}