com.astrocytes.core.operationsengine.CoreOperations.java Source code

Java tutorial

Introduction

Here is the source code for com.astrocytes.core.operationsengine.CoreOperations.java

Source

/*
 * Copyright (c) Lobachevsky University, 2017. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
 * disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Developed by: Komarov Nikolay.
 */
package com.astrocytes.core.operationsengine;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;

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

import static org.opencv.imgproc.Imgproc.*;

/**
 * A bundle of basic operations for images, with customized some parameters
 * which are needed for project.
 */
public class CoreOperations {

    /**
     * Invert image.
     *
     * @param src - source image.
     * @return inverted image.
     */
    public static Mat invert(Mat src) {
        Mat dest = new Mat();
        Core.bitwise_not(src, dest);
        return dest;
    }

    /**
     * Applies thresholding for gray image.
     *
     * @param src - gray source image.
     * @param thresh - the level of threshold.
     * @return thresholded gray image.
     */
    public static Mat threshold(Mat src, int thresh) {
        Mat dest = new Mat();
        Imgproc.threshold(src, dest, thresh, 255, Imgproc.THRESH_BINARY);
        return dest;
    }

    /**
     * Applies thresholding for color image.
     *
     * @param src - color source image.
     * @param r - the value for red value in threshold.
     * @param g - the value for green value in threshold.
     * @param b - the value for blue value in threshold.
     * @return thresholded color image.
     */
    public static Mat threshold(Mat src, int r, int g, int b) {
        if (src.channels() < 3)
            return src;

        Mat dest = new Mat();
        Mat srcBin = new Mat();

        Imgproc.threshold(src, srcBin, 1, 255, Imgproc.THRESH_BINARY);
        Core.inRange(src, new Scalar(0), new Scalar(r, g, b), dest);
        dest = invert(dest);
        cvtColor(dest, dest, Imgproc.COLOR_GRAY2BGR);

        dest = xor(srcBin, dest);
        dest = and(src, dest);
        return dest;
    }

    /**
     * Converts a source color image to a gray image.
     *
     * @param src - BGR image.
     * @return gray image.
     */
    public static Mat grayscale(Mat src) {
        if (src.channels() < 3)
            return src;
        Mat dest = new Mat(src.rows(), src.cols(), CvType.CV_8UC1);
        cvtColor(src, dest, COLOR_BGR2GRAY);
        return dest;
    }

    /**
     * Applies morphological erosion.
     *
     * @param src - source image.
     * @param radius - radius of structure element.
     * @return eroded image.
     */
    public static Mat erode(Mat src, int radius) {
        Mat dest = new Mat();
        int kernelSize = radius * 2 + 1;
        Mat kernel = getStructuringElement(Imgproc.CV_SHAPE_ELLIPSE, new Size(kernelSize, kernelSize),
                new Point(radius, radius));
        Imgproc.erode(src, dest, kernel);
        return dest;
    }

    /**
     * Applies morphological dilation.
     *
     * @param src - source image.
     * @param radius - radius of structure element.
     * @return dilated image.
     */
    public static Mat dilate(Mat src, int radius) {
        Mat dest = new Mat();
        int kernelSize = radius * 2 + 1;
        Mat kernel = getStructuringElement(Imgproc.CV_SHAPE_ELLIPSE, new Size(kernelSize, kernelSize),
                new Point(radius, radius));
        Imgproc.dilate(src, dest, kernel);
        return dest;
    }

    public static Mat xor(Mat first, Mat second) {
        Mat dest = new Mat();
        Core.bitwise_xor(first, second, dest);
        return dest;
    }

    public static Mat and(Mat first, Mat second) {
        Mat dest = new Mat();
        Core.bitwise_and(first, second, dest);
        return dest;
    }

    public static Mat or(Mat first, Mat second) {
        Mat dest = new Mat();
        Core.bitwise_or(first, second, dest);
        return dest;
    }

    /**
     * Equalizes a histogram for the image (color).
     *
     * @param src - color image to be applyed auto contrast.
     * @return the source image with equalized histogram.
     */
    public static Mat equalize(Mat src) {
        Mat dest = new Mat();
        Imgproc.equalizeHist(grayscale(src), dest);
        return dest;
    }

    /**
     * Remove all small contours on binary image with areas less than specified threshold.
     *
     * @param src - binary source image.
     * @param thresh - minimum area of contour.
     * @return a source image with removed all contours with area less than {@param thresh}.
     */
    public static Mat clearContours(Mat src, int thresh) {
        if (src.channels() > 1)
            return src;

        Mat dest = src.clone();
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
        Mat hierarchy = new Mat();

        findContours(src, contours, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_TC89_L1);

        Mat maskWhite = new Mat(src.rows(), src.cols(), CvType.CV_8UC1, new Scalar(255));
        Mat maskBlack = maskWhite.clone();

        for (int i = 0; i < contours.size(); i++) {
            Double contourArea = contourArea(contours.get(i));

            if (contourArea < thresh) {
                int pixelColor = averageIntensity(src, contours.get(i));
                drawContours(pixelColor > 127 ? maskWhite : maskBlack, contours, i, new Scalar(0), Core.FILLED);
            }
        }

        maskWhite = erode(maskWhite, 2);
        maskBlack = erode(maskBlack, 2);
        dest = and(maskWhite, dest);
        dest = or(invert(maskBlack), dest);

        return dest;
    }

    /**
     * Calculates an average intensity of pixels on image within specified contour.
     *
     * @param src - source image used for calculating an average intensity.
     * @param contour - a contour which is presented as some region of interest for operation.
     * @return a level of average intensity.
     */
    public static int averageIntensity(Mat src, MatOfPoint contour) {
        int averageIntensityWithinContour = 0;
        int quantityOfPixelsWithinContour = 0;
        Rect boundingRectangle = boundingRect(contour);

        for (int xCoord = (int) boundingRectangle.tl().x; xCoord <= (int) boundingRectangle.br().x; xCoord++) {
            for (int yCoord = (int) boundingRectangle.tl().y; yCoord <= (int) boundingRectangle.br().y; yCoord++) {
                if (pointPolygonTest(new MatOfPoint2f(contour.toArray()), new Point(xCoord, yCoord), false) > 0) {
                    averageIntensityWithinContour += intensity(src, xCoord, yCoord);
                    quantityOfPixelsWithinContour++;
                }
            }
        }

        if (quantityOfPixelsWithinContour == 0) {
            quantityOfPixelsWithinContour = 1;
            averageIntensityWithinContour = intensity(src, boundingRectangle.x, boundingRectangle.y);
            if (src.channels() == 1) {
                averageIntensityWithinContour = averageIntensityWithinContour > 127 ? 0 : 255;
            }
        }

        return averageIntensityWithinContour / quantityOfPixelsWithinContour;
    }

    /**
     * Calculates an intensity of specified pixel on image. Use for color image.
     *
     * @param src - source image
     * @param x - a column of pixel on image.
     * @param y - a row of pixel on image.
     * @return an intensity of pixel ({@param x}, {@param y}).
     */
    public static int intensity(Mat src, int x, int y) {
        double[] pixel = src.get(y, x);

        if (pixel == null)
            return 0;

        if (pixel.length == 1) {
            return (int) pixel[0];
        }

        return (int) (0.11 * pixel[2] + 0.53 * pixel[1] + 0.36 * pixel[0]);
    }

    /**
     * Apply Gaussian blur on source image.
     *
     * @param src - source image.
     * @param size - kernel's size (must be odd).
     * @return image with applied Gaussian blur.
     */
    public static Mat gaussianBlur(Mat src, int size) {
        Mat dest = new Mat();
        GaussianBlur(src, dest, new Size(size, size), 1.4, 1.4);
        return dest;
    }

    /**
     * Apply Canny edge detector for image with given min and max thresholds.
     *
     * @param src - source image for applying filter.
     * @param minThresh - minimal threshold for filter.
     * @param maxThresh - maximum threshold for filter.
     * @return output image after applying Canny filter for {@param src} image.
     */
    public static Mat cannyFilter(Mat src, int minThresh, int maxThresh) {
        Mat result = new Mat();

        minThresh = Math.min(Math.max(minThresh, 0), 255);
        maxThresh = Math.max(Math.min(maxThresh, 255), 0);

        Mat blurredImage = gaussianBlur(grayscale(src), 9);
        Canny(blurredImage, result, minThresh, maxThresh, 3, true);

        return result;
    }

    /**
     * Draw all contours of source image.
     *
     * @param src - source image.
     * @return binary image with black background and white contours.
     */
    public static int drawAllContours(Mat src, Mat dest) {
        List<MatOfPoint> contours = new ArrayList<MatOfPoint>();

        findContours(grayscale(src), contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_TC89_L1);
        for (int i = 0; i < contours.size(); i++) {
            drawContours(dest, contours, i, new Scalar(255));
        }

        return contours.size();
    }
}