Example usage for org.opencv.core Mat size

List of usage examples for org.opencv.core Mat size

Introduction

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

Prototype

public Size size() 

Source Link

Usage

From source file:org.ar.rubik.MonoChromatic.java

License:Open Source License

/**
  * Computer Mono Chromatic Filter using GPU and OpenCL
  * @param image/*from   ww  w .ja va 2 s. c  o  m*/
  * @return
  */
private static Mat monochromaticMedianImageFilterOpenCL(Mat image) {

    Log.i(Constants.TAG, "Mono Arg Image: " + image); // 720*1280 CV_8UC3

    //       Imgproc.resize(image, image, new Size(image.size().height/2, image.size().width/2));

    Size size = image.size();

    // Create OpenCL Output Bit Map
    Bitmap outputBitmap = Bitmap.createBitmap((int) size.width, (int) size.height, Bitmap.Config.ARGB_8888);

    // Create OpenCL Input Bit Map
    Bitmap inputBitmap = Bitmap.createBitmap((int) size.width, (int) size.height, Bitmap.Config.ARGB_8888);

    // Convert to Hue, Luminance, and Saturation
    //        long startHLS = System.currentTimeMillis();
    Mat hls_image = new Mat();
    Imgproc.cvtColor(image, hls_image, Imgproc.COLOR_BGR2YUV);
    //        Log.i(Constants.TAG, "Mono HLS Image: " + hls_image);  // 720*1280 CV_8UC3
    //        long endHLS = System.currentTimeMillis();
    //        Log.i(Constants.TAG, "HLS Conversion Time: " + (endHLS - startHLS) + "mS"); 

    // Convert image Mat to Bit Map.
    Utils.matToBitmap(hls_image, inputBitmap);

    // Call C++ code.
    nativeStepOpenCL((int) 7, (int) 5, 0, 0, true, inputBitmap, outputBitmap);

    Mat result = new Mat();
    Utils.bitmapToMat(outputBitmap, result);

    //        long startChannel = System.currentTimeMillis();
    List<Mat> channels = new LinkedList<Mat>();
    Core.split(result, channels);
    Mat channel0 = channels.get(0);
    //        long endChannel = System.currentTimeMillis();
    //        Log.i(Constants.TAG, "Channel Conversion Time: " + (endChannel - startChannel) + "mS"); 
    return channel0;

    //       return result;
}

From source file:org.ar.rubik.MonoChromatic.java

License:Open Source License

/**
 * Create submatrix using bytearray, then Mat.minmax().
 * This solution consumes about 10 seconds per frame.
 * /*from   w  w  w.  j ava 2  s  . c om*/
 * @param original_image
 * @return
 */
private static Mat monochromaticMedianImageFilterUtilizingOpenCv3(Mat original_image) {
    final Size imageSize = original_image.size();

    Mat monochromatic_image = new Mat(imageSize, CvType.CV_8UC1);
    Mat hsv_image = new Mat(imageSize, CvType.CV_8UC3);

    Imgproc.cvtColor(original_image, hsv_image, Imgproc.COLOR_RGB2HLS);
    //      Log.i(Constants.TAG, "HSV Image: " + hsv_image); // CV_8UC3

    // Try RGB below
    //      hsv_image = result;

    // Get hue channel into simple byte array for speed efficiency.
    final int numColumns = (int) original_image.size().width;
    final int numRows = (int) original_image.size().height;
    final int span = (int) 7;
    final int accuracy = (int) 5;
    List<Mat> channels = new LinkedList<Mat>();
    Core.split(hsv_image, channels);
    Mat hueMat = channels.get(0);
    Mat lumMat = channels.get(1);
    Mat satMat = channels.get(2);
    final int bufferSize = numColumns * numRows;
    byte[] hueByteArray = new byte[bufferSize];
    byte[] lumByteArray = new byte[bufferSize];
    byte[] satByteArray = new byte[bufferSize];
    hueMat.get(0, 0, hueByteArray); // get all the pixels
    lumMat.get(0, 0, lumByteArray); // get all the pixels
    satMat.get(0, 0, satByteArray); // get all the pixels

    // Output byte array for speed efficiency
    byte[] monochromaticByteArray = new byte[bufferSize];

    Mat subimageMat = new Mat(span, span, CvType.CV_8UC1);
    byte[] subimageByteArray = new byte[span * span];

    for (int row = 0; row < numRows; row++) {

        byte result_pixel = 0;

        for (int col = 0; col < numColumns; col++) {

            if (col < span || (col >= numColumns - span))
                result_pixel = 0; // Just put in black

            else if (row < span || (row >= numRows - span))
                result_pixel = 0; // Just put in black

            else {

                // Copy a row (or column)
                for (int i = 0; i < span; i++) {

                    // copy span bytes from (row + i) * numCol + col
                    int srcPos = (row + i) * numColumns + col;
                    int dstPos = i * span;
                    System.arraycopy(hueByteArray, srcPos, subimageByteArray, dstPos, span);
                }

                subimageMat.put(0, 0, subimageByteArray);
                Core.MinMaxLocResult minMaxResult = Core.minMaxLoc(subimageMat);

                if (((minMaxResult.maxVal - minMaxResult.maxVal) < accuracy)) //&& (lum_max - lum_min < accuracy) && (sat_max - sat_min < accuracy) )
                    result_pixel = (byte) 128;
                else
                    result_pixel = (byte) 0;

                //               Log.i(Constants.TAG, String.format("Lum %d %d", lum_min, lum_max));

            } // End of else

            if ((col >= span / 2) && (row >= span / 2))
                monochromaticByteArray[(row - span / 2) * numColumns + (col - span / 2)] = result_pixel;

            //            int test = (int)(satByteArray[row * numColumns + col]) & 0xFF;
            //            monochromaticByteArray[row * numColumns + (col - span/2)] = (byte) test;

        } // End of column sweep

    } // End of row sweep
    Log.i(Constants.TAG, "Completed MonoChromatic CV");
    monochromatic_image.put(0, 0, monochromaticByteArray);
    return monochromatic_image;
}

From source file:org.ar.rubik.MonoChromatic.java

License:Open Source License

/**
 * Use mask operation and then min max.//from w  w w.  j a  v  a2  s.c o m
 * This solution consumes about 20 minutes per frame!
 * 
 * @param original_image
 * @return
 */
@SuppressWarnings("unused")
private static Mat monochromaticMedianImageFilterUtilizingOpenCv2(Mat original_image) {

    final Size imageSize = original_image.size();
    final int numColumns = (int) original_image.size().width;
    final int numRows = (int) original_image.size().height;
    final int bufferSize = numColumns * numRows;
    final int span = (int) 7;
    final int accuracy = (int) 5;

    Mat hsv_image = new Mat(imageSize, CvType.CV_8UC3);
    Imgproc.cvtColor(original_image, hsv_image, Imgproc.COLOR_RGB2HLS);
    List<Mat> channels = new LinkedList<Mat>();
    Core.split(hsv_image, channels);
    Mat hueMat = channels.get(0);
    Mat lumMat = channels.get(1);
    Mat satMat = channels.get(2);

    // Output byte array for speed efficiency
    Mat monochromatic_image = new Mat(imageSize, CvType.CV_8UC1);
    byte[] monochromaticByteArray = new byte[bufferSize];

    Mat mask = Mat.zeros(numRows, numColumns, CvType.CV_8UC1);

    Log.i(Constants.TAG, "Begin MonoChromatic CV");
    for (int row = 0; row < numRows; row++) {

        byte result_pixel = 0;

        for (int col = 0; col < numColumns; col++) {

            if (col < span || (col >= numColumns - span))
                result_pixel = 0; // Just put in black

            else if (row < span || (row >= numRows - span))
                result_pixel = 0; // Just put in black

            else {

                //               Log.i(Constants.TAG, "Creating Mask at " + row +"," + col);
                Core.rectangle(mask, new Point(row, col), new Point(row + span, col + span),
                        new Scalar(1, 1, 1));

                //               Core.MinMaxLocResult minMaxResult = Core.minMaxLoc(hueMat, mask);
                Mat subset = new Mat();
                hueMat.copyTo(subset, mask);
                Core.MinMaxLocResult minMaxResult = Core.minMaxLoc(subset);

                if (((minMaxResult.maxVal - minMaxResult.maxVal) < accuracy)) //&& (lum_max - lum_min < accuracy) && (sat_max - sat_min < accuracy) )
                    result_pixel = (byte) 128;
                else
                    result_pixel = (byte) 0;
                //               Log.i(Constants.TAG, "Completed Mask at " + row +"," + col);

                Core.rectangle(mask, new Point(row, col), new Point(row + span, col + span),
                        new Scalar(0, 0, 0));
            }

            if ((col >= span / 2) && (row >= span / 2))
                monochromaticByteArray[(row - span / 2) * numColumns + (col - span / 2)] = result_pixel;
        }

        Log.i(Constants.TAG, "Completed Row: " + row);
    }

    monochromatic_image.put(0, 0, monochromaticByteArray);
    Log.i(Constants.TAG, "Completed MonoChromatic CV");
    //      System.exit(0);
    return monochromatic_image;
}

From source file:org.ar.rubik.MonoChromatic.java

License:Open Source License

/**
 * Use OpenCV minMax./*from  w w  w  .j a v  a2s .c  om*/
 * 
 * However, this is enormously slow, taking 10 minutes per frame!  Why?
 * I think because it is effective O(O^4) in computation.
 * 
 * @param original_image
 * @return
 */
@SuppressWarnings("unused")
private static Mat monochromaticMedianImageFilterUtilizingOpenCv(Mat original_image) {

    final Size imageSize = original_image.size();
    final int numColumns = (int) original_image.size().width;
    final int numRows = (int) original_image.size().height;
    final int bufferSize = numColumns * numRows;
    final int span = (int) 7;
    final int accuracy = (int) 5;

    Mat hsv_image = new Mat(imageSize, CvType.CV_8UC3);
    Imgproc.cvtColor(original_image, hsv_image, Imgproc.COLOR_RGB2HLS);
    List<Mat> channels = new LinkedList<Mat>();
    Core.split(hsv_image, channels);
    Mat hueMat = channels.get(0);
    Mat lumMat = channels.get(1);
    Mat satMat = channels.get(2);

    // Output byte array for speed efficiency
    Mat monochromatic_image = new Mat(imageSize, CvType.CV_8UC1);
    byte[] monochromaticByteArray = new byte[bufferSize];

    Mat mask = Mat.zeros(numRows, numColumns, CvType.CV_8UC1);

    Log.i(Constants.TAG, "Begin MonoChromatic CV");
    for (int row = 0; row < numRows; row++) {

        byte result_pixel = 0;

        for (int col = 0; col < numColumns; col++) {

            if (col < span || (col >= numColumns - span))
                result_pixel = 0; // Just put in black

            else if (row < span || (row >= numRows - span))
                result_pixel = 0; // Just put in black

            else {

                //               Log.i(Constants.TAG, "Creating Mask at " + row +"," + col);
                Core.rectangle(mask, new Point(row, col), new Point(row + span, col + span),
                        new Scalar(1, 1, 1));

                Core.MinMaxLocResult minMaxResult = Core.minMaxLoc(hueMat, mask);

                if (((minMaxResult.maxVal - minMaxResult.maxVal) < accuracy)) //&& (lum_max - lum_min < accuracy) && (sat_max - sat_min < accuracy) )
                    result_pixel = (byte) 128;
                else
                    result_pixel = (byte) 0;
                //               Log.i(Constants.TAG, "Completed Mask at " + row +"," + col);

                Core.rectangle(mask, new Point(row, col), new Point(row + span, col + span),
                        new Scalar(0, 0, 0));
            }

            if ((col >= span / 2) && (row >= span / 2))
                monochromaticByteArray[(row - span / 2) * numColumns + (col - span / 2)] = result_pixel;
        }

        Log.i(Constants.TAG, "Completed Row: " + row);

    }

    monochromatic_image.put(0, 0, monochromaticByteArray);
    Log.i(Constants.TAG, "Completed MonoChromatic CV");
    //      System.exit(0);
    return monochromatic_image;
}

From source file:org.ar.rubik.MonoChromatic.java

License:Open Source License

/**
 * Simple algorithm in Java.  Java byte arrays of the original image
 * are obtain and operated on to then produce a resulting Java byte
 * array./*from w w w. j  a va2 s .  c  o  m*/
 * 
 * 
 * @param original_image
 * @return
 */
private static Mat monochromaticMedianImageFilterBruteForceInJava(Mat original_image) {

    final Size imageSize = original_image.size();

    Mat monochromatic_image = new Mat(imageSize, CvType.CV_8UC1);
    Mat hsv_image = new Mat(imageSize, CvType.CV_8UC3);

    Imgproc.cvtColor(original_image, hsv_image, Imgproc.COLOR_RGB2HLS);
    //      Log.i(Constants.TAG, "HSV Image: " + hsv_image); // CV_8UC3

    // Try RGB below
    //      hsv_image = result;

    // Get hue channel into simple byte array for speed efficiency.
    final int numColumns = (int) original_image.size().width;
    final int numRows = (int) original_image.size().height;
    List<Mat> channels = new LinkedList<Mat>();
    Core.split(hsv_image, channels);
    Mat hueMat = channels.get(0);
    Mat lumMat = channels.get(1);
    Mat satMat = channels.get(2);
    final int bufferSize = numColumns * numRows;
    byte[] hueByteArray = new byte[bufferSize];
    byte[] lumByteArray = new byte[bufferSize];
    byte[] satByteArray = new byte[bufferSize];
    hueMat.get(0, 0, hueByteArray); // get all the pixels
    lumMat.get(0, 0, lumByteArray); // get all the pixels
    satMat.get(0, 0, satByteArray); // get all the pixels

    // Output byte array for speed efficiency
    byte[] monochromaticByteArray = new byte[bufferSize];

    for (int row = 0; row < numRows; row++) {

        final int span = (int) 7;
        final int accuracy = (int) 5;

        byte result_pixel = 0;

        for (int col = 0; col < numColumns; col++) {

            if (col < span)
                result_pixel = 0; // Just put in black

            else if (row < span)
                result_pixel = 0; // Just put in black

            else {

                int hue_min = 255;
                int hue_max = 0;
                int lum_min = 255;
                int lum_max = 0;
                //               int sat_min = 255;
                //               int sat_max = 0;

                for (int i = 0; i < span; i++) {

                    for (int j = 0; j < span; j++) {

                        int hue = (int) hueByteArray[(row - j) * numColumns + (col - i)] & 0xFF;
                        if (hue > hue_max)
                            hue_max = hue;
                        if (hue < hue_min)
                            hue_min = hue;

                        int lum = (int) lumByteArray[(row - j) * numColumns + (col - i)] & 0xFF;
                        if (lum > lum_max)
                            lum_max = lum;
                        if (lum < lum_min)
                            lum_min = lum;

                        // =+= Saturation does not look correct when veiw as gray scale image.  Not sure what is going on.
                        //                  int sat = (int)satByteArray[row * numColumns + (col - i) ] & 0xFF;
                        //                  if(sat > sat_max)
                        //                     sat_max = sat;
                        //                  if(sat < sat_min)
                        //                     sat_min = sat;

                    } // End of row min/max sweep
                } // End of column min/max sweep

                if ((hue_max - hue_min < accuracy)) //&& (lum_max - lum_min < accuracy) && (sat_max - sat_min < accuracy) )
                    result_pixel = (byte) 128;
                else
                    result_pixel = (byte) 0;

                // Eliminate all black areas from consideration even if they are very flat.
                // For some reason, keying off minimum lumosity works best.   
                if (lum_min < 30)
                    result_pixel = 0;

                //               Log.i(Constants.TAG, String.format("Lum %d %d", lum_min, lum_max));

            } // End of else

            if ((col >= span / 2) && (row >= span / 2))
                monochromaticByteArray[(row - span / 2) * numColumns + (col - span / 2)] = result_pixel;

            //            int test = (int)(satByteArray[row * numColumns + col]) & 0xFF;
            //            monochromaticByteArray[row * numColumns + (col - span/2)] = (byte) test;

        } // End of column sweep

    } // End of row sweep

    monochromatic_image.put(0, 0, monochromaticByteArray);
    return monochromatic_image;
}

From source file:org.lasarobotics.vision.ftc.resq.Beacon.java

License:Open Source License

/**
 * Analyze the current frame using the selected analysis method, using custom color blob detectors
 *
 * @param redDetector  Red color blob detector
 * @param blueDetector Blue color blob detector
 * @param img          Image to analyze// ww w.  j  a va 2s.c o  m
 * @param gray         Grayscale image to analyze
 * @param orientation  Screen orientation compensation, given by the android.Sensors class
 * @return Beacon analysis class
 */
public BeaconAnalysis analyzeFrame(ColorBlobDetector redDetector, ColorBlobDetector blueDetector, Mat img,
        Mat gray, ScreenOrientation orientation) {
    if (this.bounds == null)
        this.bounds = new Rectangle(img.size());
    switch (method) {
    case REALTIME:
        blueDetector.process(img);
        redDetector.process(img);
        return BeaconAnalyzer.analyze_REALTIME(redDetector.getContours(), blueDetector.getContours(), img,
                orientation, this.debug);
    case FAST:
    case DEFAULT:
    default:
        return BeaconAnalyzer.analyze_FAST(redDetector, blueDetector, img, gray, orientation, this.bounds,
                this.debug);
    case COMPLEX:
        blueDetector.process(img);
        redDetector.process(img);
        return BeaconAnalyzer.analyze_COMPLEX(redDetector.getContours(), blueDetector.getContours(), img, gray,
                orientation, this.bounds, this.debug);
    }
}

From source file:org.lasarobotics.vision.ftc.resq.BeaconAnalyzer.java

License:Open Source License

static Beacon.BeaconAnalysis analyze_FAST(ColorBlobDetector detectorRed, ColorBlobDetector detectorBlue,
        Mat img, Mat gray, ScreenOrientation orientation, Rectangle bounds, boolean debug) {
    //Figure out which way to read the image
    double orientationAngle = orientation.getAngle();
    boolean swapLeftRight = orientationAngle >= 180; //swap if LANDSCAPE_WEST or PORTRAIT_REVERSE
    boolean readOppositeAxis = orientation == ScreenOrientation.PORTRAIT
            || orientation == ScreenOrientation.PORTRAIT_REVERSE; //read other axis if any kind of portrait

    //Bound the image
    if (readOppositeAxis)
        //Force the analysis box to transpose inself in place
        //noinspection SuspiciousNameCombination
        bounds = new Rectangle(new Point(bounds.center().y / img.height() * img.width(),
                bounds.center().x / img.width() * img.height()), bounds.height(), bounds.width())
                        .clip(new Rectangle(img.size()));
    if (!swapLeftRight && readOppositeAxis)
        //Force the analysis box to flip across its primary axis
        bounds = new Rectangle(
                new Point((img.size().width / 2) + Math.abs(bounds.center().x - (img.size().width / 2)),
                        bounds.center().y),
                bounds.width(), bounds.height());
    else if (swapLeftRight && !readOppositeAxis)
        //Force the analysis box to flip across its primary axis
        bounds = new Rectangle(new Point(bounds.center().x, img.size().height - bounds.center().y),
                bounds.width(), bounds.height());
    bounds = bounds.clip(new Rectangle(img.size()));

    //Get contours within the bounds
    detectorRed.process(img);/*from   ww  w.java  2 s. c o  m*/
    detectorBlue.process(img);
    List<Contour> contoursRed = detectorRed.getContours();
    List<Contour> contoursBlue = detectorBlue.getContours();

    //DEBUG Draw contours before filtering
    if (debug)
        Drawing.drawContours(img, contoursRed, new ColorRGBA("#FF0000"), 2);
    if (debug)
        Drawing.drawContours(img, contoursBlue, new ColorRGBA("#0000FF"), 2);

    if (debug)
        Drawing.drawRectangle(img, bounds, new ColorRGBA("#aaaaaa"), 4);

    //Get the largest contour in each - we're calling this one the main light
    int largestIndexRed = findLargestIndexInBounds(contoursRed, bounds);
    int largestIndexBlue = findLargestIndexInBounds(contoursBlue, bounds);
    Contour largestRed = (largestIndexRed != -1) ? contoursRed.get(largestIndexRed) : null;
    Contour largestBlue = (largestIndexBlue != -1) ? contoursBlue.get(largestIndexBlue) : null;

    //If we don't have a main light for one of the colors, we know both colors are the same
    //TODO we should re-filter the contours by size to ensure that we get at least a decent size
    if (largestRed == null && largestBlue == null)
        return new Beacon.BeaconAnalysis();

    //INFO The best contour from each color (if available) is selected as red and blue
    //INFO The two best contours are then used to calculate the location of the beacon

    //If we don't have a main light for one of the colors, we know both colors are the same
    //TODO we should re-filter the contours by size to ensure that we get at least a decent size

    //If the largest part of the non-null color is wider than a certain distance, then both are bright
    //Otherwise, only one may be lit
    //If only one is lit, and is wider than a certain distance, it is bright
    //TODO We are currently assuming that the beacon cannot be in a "bright" state
    if (largestRed == null)
        return new Beacon.BeaconAnalysis();
    else if (largestBlue == null)
        return new Beacon.BeaconAnalysis();

    //The height of the beacon on screen is the height of the best contour
    Contour largestHeight = ((largestRed.size().height) > (largestBlue.size().height)) ? largestRed
            : largestBlue;
    double beaconHeight = largestHeight.size().height;

    //Get beacon width on screen by extrapolating from height
    final double beaconActualHeight = Constants.BEACON_HEIGHT; //cm, only the lit up portion - 14.0 for entire
    final double beaconActualWidth = Constants.BEACON_WIDTH; //cm
    final double beaconWidthHeightRatio = Constants.BEACON_WH_RATIO;
    double beaconWidth = beaconHeight * beaconWidthHeightRatio;
    Size beaconSize = new Size(beaconWidth, beaconHeight);

    //Look at the locations of the largest contours
    //Check to see if the largest red contour is more left-most than the largest right contour
    //If it is, then we know that the left beacon is red and the other blue, and vice versa

    Point bestRedCenter = largestRed.centroid();
    Point bestBlueCenter = largestBlue.centroid();

    //DEBUG R/B text
    if (debug)
        Drawing.drawText(img, "R", bestRedCenter, 1.0f, new ColorRGBA(255, 0, 0));
    if (debug)
        Drawing.drawText(img, "B", bestBlueCenter, 1.0f, new ColorRGBA(0, 0, 255));

    //Test which side is red and blue
    //If the distance between the sides is smaller than a value, then return unknown
    final int minDistance = (int) (Constants.DETECTION_MIN_DISTANCE * beaconSize.width); //percent of beacon width

    boolean leftIsRed;
    Contour leftMostContour, rightMostContour;
    if (readOppositeAxis) {
        if (bestRedCenter.y + minDistance < bestBlueCenter.y) {
            leftIsRed = true;
        } else if (bestBlueCenter.y + minDistance < bestRedCenter.y) {
            leftIsRed = false;
        } else {
            return new Beacon.BeaconAnalysis();
        }
    } else {
        if (bestRedCenter.x + minDistance < bestBlueCenter.x) {
            leftIsRed = true;
        } else if (bestBlueCenter.x + minDistance < bestRedCenter.x) {
            leftIsRed = false;
        } else {
            return new Beacon.BeaconAnalysis();
        }
    }

    //Swap left and right if necessary
    leftIsRed = swapLeftRight != leftIsRed;

    //Get the left-most best contour (or top-most if axis swapped) (or right-most if L/R swapped)
    if (readOppositeAxis) {
        //Get top-most best contour
        leftMostContour = ((largestRed.topLeft().y) < (largestBlue.topLeft().y)) ? largestRed : largestBlue;
        //Get bottom-most best contour
        rightMostContour = ((largestRed.topLeft().y) < (largestBlue.topLeft().y)) ? largestBlue : largestRed;
    } else {
        //Get left-most best contour
        leftMostContour = ((largestRed.topLeft().x) < (largestBlue.topLeft().x)) ? largestRed : largestBlue;
        //Get the right-most best contour
        rightMostContour = ((largestRed.topLeft().x) < (largestBlue.topLeft().x)) ? largestBlue : largestRed;
    }

    //DEBUG Logging
    if (debug)
        Log.d("Beacon", "Orientation: " + orientation + "Angle: " + orientationAngle + " Swap Axis: "
                + readOppositeAxis + " Swap Direction: " + swapLeftRight);

    //Swap left and right if necessary
    //BUGFIX: invert when we swap
    if (!swapLeftRight) {
        Contour temp = leftMostContour;
        leftMostContour = rightMostContour;
        rightMostContour = temp;
    }

    //Now that we have the two contours, let's find ellipses that match

    //Draw the box surrounding both contours
    //Get the width of the contours
    double widthBeacon = rightMostContour.right() - leftMostContour.left();

    //Center of contours is the average of centroids of the contours
    Point center = new Point((leftMostContour.centroid().x + rightMostContour.centroid().x) / 2,
            (leftMostContour.centroid().y + rightMostContour.centroid().y) / 2);

    //Get the combined height of the contours
    double heightContours = Math.max(leftMostContour.bottom(), rightMostContour.bottom())
            - Math.min(leftMostContour.top(), rightMostContour.top());

    //The largest size ratio of tested over actual is the scale ratio
    double scale = Math.max(widthBeacon / beaconActualWidth, heightContours / beaconActualHeight);

    //Define size of bounding box by scaling the actual beacon size
    Size beaconSizeFinal = new Size(beaconActualWidth * scale, beaconActualHeight * scale);

    //Swap x and y if we rotated the view
    if (readOppositeAxis) {
        //noinspection SuspiciousNameCombination
        beaconSizeFinal = new Size(beaconSizeFinal.height, beaconSizeFinal.width);
    }

    //Get points of the bounding box
    Point beaconTopLeft = new Point(center.x - (beaconSizeFinal.width / 2),
            center.y - (beaconSizeFinal.height / 2));
    Point beaconBottomRight = new Point(center.x + (beaconSizeFinal.width / 2),
            center.y + (beaconSizeFinal.height / 2));
    Rectangle boundingBox = new Rectangle(new Rect(beaconTopLeft, beaconBottomRight));

    //Get ellipses in region of interest
    //Make sure the rectangles don't leave the image size
    Rectangle leftRect = leftMostContour.getBoundingRectangle().clip(new Rectangle(img.size()));
    Rectangle rightRect = rightMostContour.getBoundingRectangle().clip(new Rectangle(img.size()));
    Mat leftContourImg = gray.submat((int) leftRect.top(), (int) leftRect.bottom(), (int) leftRect.left(),
            (int) leftRect.right());
    Mat rightContourImg = gray.submat((int) rightRect.top(), (int) rightRect.bottom(), (int) rightRect.left(),
            (int) rightRect.right());

    //Locate ellipses in the image to process contours against
    List<Ellipse> ellipsesLeft = PrimitiveDetection.locateEllipses(leftContourImg).getEllipses();
    Detectable.offset(ellipsesLeft, new Point(leftRect.left(), leftRect.top()));
    List<Ellipse> ellipsesRight = PrimitiveDetection.locateEllipses(rightContourImg).getEllipses();
    Detectable.offset(ellipsesRight, new Point(rightRect.left(), rightRect.top()));

    //Score ellipses
    BeaconScoringCOMPLEX scorer = new BeaconScoringCOMPLEX(img.size());
    List<BeaconScoringCOMPLEX.ScoredEllipse> scoredEllipsesLeft = scorer.scoreEllipses(ellipsesLeft, null, null,
            gray);
    scoredEllipsesLeft = filterEllipses(scoredEllipsesLeft);
    ellipsesLeft = BeaconScoringCOMPLEX.ScoredEllipse.getList(scoredEllipsesLeft);
    if (debug)
        Drawing.drawEllipses(img, ellipsesLeft, new ColorRGBA("#00ff00"), 3);
    List<BeaconScoringCOMPLEX.ScoredEllipse> scoredEllipsesRight = scorer.scoreEllipses(ellipsesRight, null,
            null, gray);
    scoredEllipsesRight = filterEllipses(scoredEllipsesRight);
    ellipsesRight = BeaconScoringCOMPLEX.ScoredEllipse.getList(scoredEllipsesRight);
    if (debug)
        Drawing.drawEllipses(img, ellipsesRight, new ColorRGBA("#00ff00"), 3);

    //Calculate ellipse center if present
    Point centerLeft;
    Point centerRight;
    boolean done = false;
    do {
        centerLeft = null;
        centerRight = null;
        if (scoredEllipsesLeft.size() > 0)
            centerLeft = scoredEllipsesLeft.get(0).ellipse.center();
        if (scoredEllipsesRight.size() > 0)
            centerRight = scoredEllipsesRight.get(0).ellipse.center();

        //Flip axis if necesary
        if (centerLeft != null && readOppositeAxis) {
            centerLeft.set(new double[] { centerLeft.y, centerLeft.x });
        }
        if (centerRight != null && readOppositeAxis) {
            centerRight.set(new double[] { centerRight.y, centerRight.x });
        }

        //Make very, very sure that we didn't just find the same ellipse
        if (centerLeft != null && centerRight != null) {
            if (Math.abs(centerLeft.x - centerRight.x) < Constants.ELLIPSE_MIN_DISTANCE * beaconSize.width) {
                //Are both ellipses on the left or right side of the beacon? - remove the opposite side's ellipse
                if (Math.abs(centerLeft.x - leftRect.center().x) < Constants.ELLIPSE_MIN_DISTANCE
                        * beaconSize.width)
                    scoredEllipsesRight.remove(0);
                else
                    scoredEllipsesLeft.remove(0);
            } else
                done = true;
        } else
            done = true;

    } while (!done);

    //Improve the beacon center if both ellipses present
    byte ellipseExtrapolated = 0;
    if (centerLeft != null && centerRight != null) {
        if (readOppositeAxis)
            center.y = (centerLeft.x + centerRight.x) / 2;
        else
            center.x = (centerLeft.x + centerRight.x) / 2;
    }
    //Extrapolate other ellipse location if one present
    //FIXME: This method of extrapolation may not work when readOppositeAxis is true
    else if (centerLeft != null) {
        ellipseExtrapolated = 2;
        if (readOppositeAxis)
            centerRight = new Point(centerLeft.x - 2 * Math.abs(center.x - centerLeft.x),
                    (centerLeft.y + center.y) / 2);
        else
            centerRight = new Point(centerLeft.x + 2 * Math.abs(center.x - centerLeft.x),
                    (centerLeft.y + center.y) / 2);
        if (readOppositeAxis)
            centerRight.set(new double[] { centerRight.y, centerRight.x });
    } else if (centerRight != null) {
        ellipseExtrapolated = 1;
        if (readOppositeAxis)
            centerLeft = new Point(centerRight.x + 2 * Math.abs(center.x - centerRight.x),
                    (centerRight.y + center.y) / 2);
        else
            centerLeft = new Point(centerRight.x - 2 * Math.abs(center.x - centerRight.x),
                    (centerRight.y + center.y) / 2);
        if (readOppositeAxis)
            centerLeft.set(new double[] { centerLeft.y, centerLeft.x });
    }

    //Draw center locations
    if (debug)
        Drawing.drawCross(img, center, new ColorRGBA("#ffffff"), 10, 4);
    if (debug && centerLeft != null) {
        ColorRGBA c = ellipseExtrapolated != 1 ? new ColorRGBA("#ffff00") : new ColorRGBA("#ff00ff");
        //noinspection SuspiciousNameCombination
        Drawing.drawCross(img, !readOppositeAxis ? centerLeft : new Point(centerLeft.y, centerLeft.x), c, 8, 3);
    }
    if (debug && centerRight != null) {
        ColorRGBA c = ellipseExtrapolated != 2 ? new ColorRGBA("#ffff00") : new ColorRGBA("#ff00ff");
        //noinspection SuspiciousNameCombination
        Drawing.drawCross(img, !readOppositeAxis ? centerRight : new Point(centerRight.y, centerRight.x), c, 8,
                3);
    }

    //Draw the rectangle containing the beacon
    if (debug)
        Drawing.drawRectangle(img, boundingBox, new ColorRGBA(0, 255, 0), 4);

    //Tell us the height of the beacon
    //TODO later we can get the distance away from the beacon based on its height and position

    //Remove the largest index and look for the next largest
    //If the next largest is (mostly) within the area of the box, then merge it in with the largest
    //Check if the size of the largest contour(s) is about twice the size of the other
    //This would indicate one is brightly lit and the other is not
    //If this is not true, then neither part of the beacon is highly lit

    //Get confidence approximation
    double WH_ratio = widthBeacon / beaconHeight;
    double ratioError = Math.abs((Constants.BEACON_WH_RATIO - WH_ratio)) / Constants.BEACON_WH_RATIO; // perfect value = 0;
    double averageHeight = (leftMostContour.height() + rightMostContour.height()) / 2.0;
    double dy = Math.abs((leftMostContour.centroid().y - rightMostContour.centroid().y) / averageHeight
            * Constants.FAST_HEIGHT_DELTA_FACTOR);
    double dArea = Math.sqrt(leftMostContour.area() / rightMostContour.area());
    double buttonsdy = (centerLeft != null && centerRight != null)
            ? (Math.abs(centerLeft.y - centerRight.y) / averageHeight * Constants.FAST_HEIGHT_DELTA_FACTOR)
            : Constants.ELLIPSE_PRESENCE_BIAS;
    double confidence = MathUtil.normalPDFNormalized(
            MathUtil.distance(MathUtil.distance(MathUtil.distance(ratioError, dy), dArea), buttonsdy)
                    / Constants.FAST_CONFIDENCE_ROUNDNESS,
            Constants.FAST_CONFIDENCE_NORM, 0.0);

    //Get button ellipses
    Ellipse leftEllipse = scoredEllipsesLeft.size() > 0 ? scoredEllipsesLeft.get(0).ellipse : null;
    Ellipse rightEllipse = scoredEllipsesRight.size() > 0 ? scoredEllipsesRight.get(0).ellipse : null;

    //Test for color switching
    if (leftEllipse != null && rightEllipse != null && leftEllipse.center().x > rightEllipse.center().x) {
        Ellipse tE = leftEllipse;
        leftEllipse = rightEllipse;
        rightEllipse = tE;
    } else if ((leftEllipse != null && leftEllipse.center().x > center.x)
            || (rightEllipse != null && rightEllipse.center().x < center.x)) {
        Ellipse tE = leftEllipse;
        leftEllipse = rightEllipse;
        rightEllipse = tE;
    }

    //Axis correction for ellipses
    if (swapLeftRight) {
        if (leftEllipse != null)
            leftEllipse = new Ellipse(
                    new RotatedRect(new Point(img.width() - leftEllipse.center().x, leftEllipse.center().y),
                            leftEllipse.size(), leftEllipse.angle()));
        if (rightEllipse != null)
            rightEllipse = new Ellipse(
                    new RotatedRect(new Point(img.width() - rightEllipse.center().x, rightEllipse.center().y),
                            rightEllipse.size(), rightEllipse.angle()));
        //Swap again after correcting axis to ensure left is left and right is right
        Ellipse tE = leftEllipse;
        leftEllipse = rightEllipse;
        rightEllipse = tE;
    }

    //Switch axis if necessary
    if (readOppositeAxis)
        boundingBox = boundingBox.transpose();

    if (leftIsRed)
        return new Beacon.BeaconAnalysis(Beacon.BeaconColor.RED, Beacon.BeaconColor.BLUE, boundingBox,
                confidence, leftEllipse, rightEllipse);
    else
        return new Beacon.BeaconAnalysis(Beacon.BeaconColor.BLUE, Beacon.BeaconColor.RED, boundingBox,
                confidence, leftEllipse, rightEllipse);
}

From source file:org.lasarobotics.vision.ftc.resq.BeaconAnalyzer.java

License:Open Source License

static Beacon.BeaconAnalysis analyze_COMPLEX(List<Contour> contoursRed, List<Contour> contoursBlue, Mat img,
        Mat gray, ScreenOrientation orientation, Rectangle bounds, boolean debug) {
    //The idea behind the SmartScoring algorithm is that the largest score in each contour/ellipse set will become the best
    //DONE First, ellipses and contours are are detected and pre-filtered to remove eccentricities
    //Second, ellipses, and contours are scored independently based on size and color ... higher score is better
    //Third, comparative analysis is used on each ellipse and contour to create a score for the contours
    //Ellipses within rectangles strongly increase in value
    //Ellipses without nearby/contained contours are removed
    //Ellipses with nearby/contained contours associate themselves with the contour
    //Pairs of ellipses (those with similar size and x-position) greatly increase the associated contours' value
    //Contours without nearby/contained ellipses lose value
    //Contours near another contour of the opposite color increase in value
    //Contours and ellipses near the expected area (if any expected area) increase in value
    //Finally, a fraction of the ellipse value is added to the value of the contour
    //The best ellipse is found first, then only this ellipse adds to the value
    //The best contour from each color (if available) is selected as red and blue
    //The two best contours are then used to calculate the location of the beacon

    //TODO Filter out bad contours - filtering currently ignored

    //DEBUG Draw contours before filtering
    if (debug)/*from w  ww  . j av  a2  s. co  m*/
        Drawing.drawContours(img, contoursRed, new ColorRGBA("#FFCDD2"), 2);
    if (debug)
        Drawing.drawContours(img, contoursBlue, new ColorRGBA("#BBDEFB"), 2);

    //Score contours
    BeaconScoringCOMPLEX scorer = new BeaconScoringCOMPLEX(img.size());
    List<BeaconScoringCOMPLEX.ScoredContour> scoredContoursRed = scorer.scoreContours(contoursRed, null, null,
            img, gray);
    List<BeaconScoringCOMPLEX.ScoredContour> scoredContoursBlue = scorer.scoreContours(contoursBlue, null, null,
            img, gray);

    //DEBUG Draw red and blue contours after filtering
    if (debug)
        Drawing.drawContours(img, BeaconScoringCOMPLEX.ScoredContour.getList(scoredContoursRed),
                new ColorRGBA(255, 0, 0), 2);
    if (debug)
        Drawing.drawContours(img, BeaconScoringCOMPLEX.ScoredContour.getList(scoredContoursBlue),
                new ColorRGBA(0, 0, 255), 2);

    //Locate ellipses in the image to process contours against
    //Each contour must have an ellipse of correct specification
    PrimitiveDetection primitiveDetection = new PrimitiveDetection();
    PrimitiveDetection.EllipseLocationResult ellipseLocationResult = PrimitiveDetection.locateEllipses(gray);

    //Filter out bad ellipses - TODO filtering currently ignored
    List<Ellipse> ellipses = ellipseLocationResult.getEllipses();

    //DEBUG Ellipse data before filtering
    //Drawing.drawEllipses(img, ellipses, new ColorRGBA("#ff0745"), 1);

    //Score ellipses
    List<BeaconScoringCOMPLEX.ScoredEllipse> scoredEllipses = scorer.scoreEllipses(ellipses, null, null, gray);

    //DEBUG Ellipse data after filtering
    if (debug)
        Drawing.drawEllipses(img, BeaconScoringCOMPLEX.ScoredEllipse.getList(scoredEllipses),
                new ColorRGBA("#FFC107"), 2);

    //DEBUG draw top 5 ellipses
    if (scoredEllipses.size() > 0 && debug) {
        Drawing.drawEllipses(img,
                BeaconScoringCOMPLEX.ScoredEllipse.getList(
                        scoredEllipses.subList(0, scoredEllipses.size() > 5 ? 5 : scoredEllipses.size())),
                new ColorRGBA("#d0ff00"), 3);
        Drawing.drawEllipses(img,
                BeaconScoringCOMPLEX.ScoredEllipse.getList(
                        scoredEllipses.subList(0, scoredEllipses.size() > 3 ? 3 : scoredEllipses.size())),
                new ColorRGBA("#00ff00"), 3);
    }

    //Third, comparative analysis is used on each ellipse and contour to create a score for the contours
    BeaconScoringCOMPLEX.MultiAssociatedContours associations = scorer.scoreAssociations(scoredContoursRed,
            scoredContoursBlue, scoredEllipses);
    double score = (associations.blueContours.size() > 0 ? associations.blueContours.get(0).score : 0)
            + (associations.redContours.size() > 0 ? associations.redContours.get(0).score : 0);
    double confidence = score / Constants.CONFIDENCE_DIVISOR;

    //INFO The best contour from each color (if available) is selected as red and blue
    //INFO The two best contours are then used to calculate the location of the beacon

    //Get the best contour in each (starting with the largest) if any contours exist
    //We're calling this one the main light
    Contour bestRed = (associations.redContours.size() > 0) ? associations.redContours.get(0).contour.contour
            : null;
    Contour bestBlue = (associations.blueContours.size() > 0) ? associations.blueContours.get(0).contour.contour
            : null;
    Ellipse bestRedEllipse = (associations.redContours.size() > 0
            && associations.redContours.get(0).ellipses.size() > 0)
                    ? associations.redContours.get(0).ellipses.get(0).ellipse
                    : null;
    Ellipse bestBlueEllipse = (associations.blueContours.size() > 0
            && associations.blueContours.get(0).ellipses.size() > 0)
                    ? associations.blueContours.get(0).ellipses.get(0).ellipse
                    : null;

    //If we don't have a main light for one of the colors, we know both colors are the same
    //TODO we should re-filter the contours by size to ensure that we get at least a decent size
    if (bestRed == null && bestBlue == null)
        return new Beacon.BeaconAnalysis(Beacon.BeaconColor.UNKNOWN, Beacon.BeaconColor.UNKNOWN,
                new Rectangle(), 0.0f);

    //TODO rotate image based on camera rotation here

    //The height of the beacon on screen is the height of the best contour
    Contour largestHeight = ((bestRed != null ? bestRed.size().height
            : 0) > (bestBlue != null ? bestBlue.size().height : 0)) ? bestRed : bestBlue;
    assert largestHeight != null;
    double beaconHeight = largestHeight.size().height;

    //Get beacon width on screen by extrapolating from height
    final double beaconActualHeight = Constants.BEACON_HEIGHT; //cm, only the lit up portion - 14.0 for entire
    final double beaconActualWidth = Constants.BEACON_WIDTH; //cm
    final double beaconWidthHeightRatio = Constants.BEACON_WH_RATIO;
    double beaconWidth = beaconHeight * beaconWidthHeightRatio;
    Size beaconSize = new Size(beaconWidth, beaconHeight);

    //If the largest part of the non-null color is wider than a certain distance, then both are bright
    //Otherwise, only one may be lit
    //If only one is lit, and is wider than a certain distance, it is bright
    //TODO We are currently assuming that the beacon cannot be in a "bright" state
    if (bestRed == null)
        return new Beacon.BeaconAnalysis();
    else if (bestBlue == null)
        return new Beacon.BeaconAnalysis();

    //Look at the locations of the largest contours
    //Check to see if the largest red contour is more left-most than the largest right contour
    //If it is, then we know that the left beacon is red and the other blue, and vice versa

    Point bestRedCenter = bestRed.centroid();
    Point bestBlueCenter = bestBlue.centroid();

    //DEBUG R/B text
    if (debug)
        Drawing.drawText(img, "R", bestRedCenter, 1.0f, new ColorRGBA(255, 0, 0));
    if (debug)
        Drawing.drawText(img, "B", bestBlueCenter, 1.0f, new ColorRGBA(0, 0, 255));

    //Test which side is red and blue
    //If the distance between the sides is smaller than a value, then return unknown
    final int minDistance = (int) (Constants.DETECTION_MIN_DISTANCE * beaconSize.width); //percent of beacon width
    //Figure out which way to read the image
    double orientationAngle = orientation.getAngle();
    boolean swapLeftRight = orientationAngle >= 180; //swap if LANDSCAPE_WEST or PORTRAIT_REVERSE
    boolean readOppositeAxis = orientation == ScreenOrientation.PORTRAIT
            || orientation == ScreenOrientation.PORTRAIT_REVERSE; //read other axis if any kind of portrait

    boolean leftIsRed;
    Contour leftMostContour, rightMostContour;
    Ellipse leftEllipse, rightEllipse;
    if (readOppositeAxis) {
        if (bestRedCenter.y + minDistance < bestBlueCenter.y) {
            leftIsRed = true;
        } else if (bestBlueCenter.y + minDistance < bestRedCenter.y) {
            leftIsRed = false;
        } else {
            return new Beacon.BeaconAnalysis();
        }
    } else {
        if (bestRedCenter.x + minDistance < bestBlueCenter.x) {
            leftIsRed = true;
        } else if (bestBlueCenter.x + minDistance < bestRedCenter.x) {
            leftIsRed = false;
        } else {
            return new Beacon.BeaconAnalysis();
        }
    }

    //Swap left and right if necessary
    leftIsRed = swapLeftRight != leftIsRed;

    //Get the left-most best contour (or top-most if axis swapped) (or right-most if L/R swapped)
    if (readOppositeAxis) {
        //Get top-most best contour
        leftMostContour = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestRed : bestBlue;
        leftEllipse = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestRedEllipse : bestBlueEllipse;
        //Get bottom-most best contour
        rightMostContour = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestBlue : bestRed;
        rightEllipse = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestBlueEllipse : bestRedEllipse;
    } else {
        //Get left-most best contour
        leftMostContour = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestRed : bestBlue;
        leftEllipse = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestRedEllipse : bestBlueEllipse;
        //Get the right-most best contour
        rightMostContour = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestBlue : bestRed;
        rightEllipse = ((bestRed.topLeft().y) < (bestBlue.topLeft().y)) ? bestBlueEllipse : bestRedEllipse;
    }

    //Swap left and right if necessary
    //BUGFIX: invert when we swap
    if (swapLeftRight) {
        Contour temp = leftMostContour;
        leftMostContour = rightMostContour;
        rightMostContour = temp;

        Ellipse tE = leftEllipse;
        leftEllipse = rightEllipse;
        rightEllipse = tE;
    }

    //Draw the box surrounding both contours
    //Get the width of the contours
    double widthBeacon = rightMostContour.right() - leftMostContour.left();

    //Center of contours is the average of centers of the contours
    Point center = new Point((leftMostContour.centroid().x + rightMostContour.centroid().x) / 2,
            (leftMostContour.centroid().y + rightMostContour.centroid().y) / 2);

    //Get the combined height of the contours
    double heightContours = Math.max(leftMostContour.bottom(), rightMostContour.bottom())
            - Math.min(leftMostContour.top(), rightMostContour.top());

    //The largest size ratio of tested over actual is the scale ratio
    double scale = Math.max(widthBeacon / beaconActualWidth, heightContours / beaconActualHeight);

    //Define size of bounding box by scaling the actual beacon size
    Size beaconSizeFinal = new Size(beaconActualWidth * scale, beaconActualHeight * scale);

    //Swap x and y if we rotated the view
    if (readOppositeAxis) {
        //noinspection SuspiciousNameCombination
        beaconSizeFinal = new Size(beaconSizeFinal.height, beaconSizeFinal.width);
    }

    //Get points of the bounding box
    Point beaconTopLeft = new Point(center.x - (beaconSizeFinal.width / 2),
            center.y - (beaconSizeFinal.height / 2));
    Point beaconBottomRight = new Point(center.x + (beaconSizeFinal.width / 2),
            center.y + (beaconSizeFinal.height / 2));
    Rectangle boundingBox = new Rectangle(new Rect(beaconTopLeft, beaconBottomRight));

    //Draw the rectangle containing the beacon
    if (debug)
        Drawing.drawRectangle(img, boundingBox, new ColorRGBA(0, 255, 0), 4);

    //Tell us the height of the beacon
    //TODO later we can get the distance away from the beacon based on its height and position

    //Remove the largest index and look for the next largest
    //If the next largest is (mostly) within the area of the box, then merge it in with the largest

    //Check if the size of the largest contour(s) is about twice the size of the other
    //This would indicate one is brightly lit and the other is not

    //Draw some more debug info
    if (debug)
        Drawing.drawCross(img, center, new ColorRGBA("#ffffff"), 10, 4);
    if (debug && leftEllipse != null)
        Drawing.drawCross(img, leftEllipse.center(), new ColorRGBA("#ffff00"), 8, 3);
    if (debug && rightEllipse != null)
        Drawing.drawCross(img, rightEllipse.center(), new ColorRGBA("#ffff00"), 8, 3);

    //Test for color switching
    if (leftEllipse != null && rightEllipse != null && leftEllipse.center().x > rightEllipse.center().x) {
        Ellipse tE = leftEllipse;
        leftEllipse = rightEllipse;
        rightEllipse = tE;
    } else if ((leftEllipse != null && leftEllipse.center().x > center.x)
            || (rightEllipse != null && rightEllipse.center().x < center.x)) {
        Ellipse tE = leftEllipse;
        leftEllipse = rightEllipse;
        rightEllipse = tE;
    }

    //Axis correction for ellipses
    if (swapLeftRight) {
        if (leftEllipse != null)
            leftEllipse = new Ellipse(
                    new RotatedRect(new Point(img.width() - leftEllipse.center().x, leftEllipse.center().y),
                            leftEllipse.size(), leftEllipse.angle()));
        if (rightEllipse != null)
            rightEllipse = new Ellipse(
                    new RotatedRect(new Point(img.width() - rightEllipse.center().x, rightEllipse.center().y),
                            rightEllipse.size(), rightEllipse.angle()));
        //Swap again after correcting axis to ensure left is left and right is right
        Ellipse tE = leftEllipse;
        leftEllipse = rightEllipse;
        rightEllipse = tE;
    }

    //Make very, very sure that we didn't just find the same ellipse
    if (leftEllipse != null && rightEllipse != null) {
        if (Math.abs(leftEllipse.center().x - rightEllipse.center().x) < Constants.ELLIPSE_MIN_DISTANCE
                * beaconSize.width) {
            //Are both ellipses on the left or right side of the beacon? - remove the opposite side's ellipse
            if (Math.abs(leftEllipse.center().x - leftMostContour.center().x) < Constants.ELLIPSE_MIN_DISTANCE
                    * beaconSize.width)
                rightEllipse = null;
            else
                leftEllipse = null;
        }
    }

    //Switch axis if necessary
    if (readOppositeAxis)
        boundingBox = boundingBox.transpose();

    //If this is not true, then neither part of the beacon is highly lit
    if (leftIsRed)
        return new Beacon.BeaconAnalysis(Beacon.BeaconColor.RED, Beacon.BeaconColor.BLUE, boundingBox,
                confidence, leftEllipse, rightEllipse);
    else
        return new Beacon.BeaconAnalysis(Beacon.BeaconColor.BLUE, Beacon.BeaconColor.RED, boundingBox,
                confidence, leftEllipse, rightEllipse);
}

From source file:org.lasarobotics.vision.ftc.resq.BeaconScoringCOMPLEX.java

License:Open Source License

@SuppressWarnings("unchecked")
List<ScoredEllipse> scoreEllipses(List<Ellipse> ellipses, Point estimateLocation, Double estimateDistance,
        Mat gray) {
    List<ScoredEllipse> scores = new ArrayList<>();

    for (Ellipse ellipse : ellipses) {
        double score = 1;

        //Find the eccentricity - the closer it is to 0, the better
        double eccentricity = ellipse.eccentricity();
        double eccentricitySubscore = createSubscore(eccentricity, Constants.ELLIPSE_ECCENTRICITY_BEST,
                Constants.ELLIPSE_ECCENTRICITY_NORM, Constants.ELLIPSE_ECCENTRICITY_BIAS, false);
        score *= eccentricitySubscore;/*  ww w  . j  av a2 s  .  c o  m*/
        //f(0.3) = 5, f(0.75) = 0

        //Find the area - the closer to a certain range, the better
        double area = ellipse.area() / gray.size().area(); //area as a percentage of the area of the screen
        //Best value is the root mean squared of the min and max areas
        final double areaBestValue = Math.sqrt(Constants.ELLIPSE_AREA_MIN * Constants.ELLIPSE_AREA_MIN
                + Constants.ELLIPSE_AREA_MAX * Constants.ELLIPSE_AREA_MAX) / 2;
        double areaSubscore = createSubscore(area, areaBestValue, Constants.ELLIPSE_AREA_NORM,
                Constants.ELLIPSE_AREA_BIAS, true);
        score *= areaSubscore;

        //TODO Find the on-screen location - the closer it is to the estimate, the better

        //Find the color - the more black, the better (significantly)
        Ellipse e = ellipse.scale(0.5); //get the center 50% of data
        double averageColor = e.averageColor(gray, ColorSpace.GRAY).getScalar().val[0];
        double colorSubscore = createSubscore(averageColor, Constants.ELLIPSE_CONTRAST_THRESHOLD,
                Constants.ELLIPSE_CONTRAST_NORM, Constants.ELLIPSE_CONTRAST_BIAS, false);
        score *= colorSubscore;

        //If score is above a value, keep the ellipse
        if (score >= Constants.ELLIPSE_SCORE_MIN)
            scores.add(new ScoredEllipse(ellipse, score));
    }

    return (List<ScoredEllipse>) Scorable.sort(scores);
}

From source file:org.lasarobotics.vision.image.Transform.java

License:Open Source License

/**
 * Rotate an image by an angle (counterclockwise)
 *
 * @param image Transform matrix//from   w  w  w.j ava  2  s  . c om
 * @param angle Angle to rotate by (counterclockwise) from -360 to 360
 */
public static void rotate(Mat image, double angle) {
    //Calculate size of new matrix
    double radians = Math.toRadians(angle);
    double sin = Math.abs(Math.sin(radians));
    double cos = Math.abs(Math.cos(radians));

    int newWidth = (int) (image.width() * cos + image.height() * sin);
    int newHeight = (int) (image.width() * sin + image.height() * cos);

    // rotating image
    Point center = new Point(newWidth / 2, newHeight / 2);
    Mat rotMatrix = Imgproc.getRotationMatrix2D(center, angle, 1.0); //1.0 means 100 % scale

    Size size = new Size(newWidth, newHeight);
    Imgproc.warpAffine(image, image, rotMatrix, image.size());
}