|
|
@@ -30,6 +30,7 @@ import org.opencv.core.CvType; |
|
|
|
import org.opencv.core.Mat; |
|
|
|
import org.opencv.core.MatOfPoint; |
|
|
|
import org.opencv.core.Scalar; |
|
|
|
import org.opencv.core.Size; |
|
|
|
import org.opencv.imgproc.Imgproc; |
|
|
|
|
|
|
|
import java.nio.ByteBuffer; |
|
|
@@ -66,10 +67,6 @@ public class VideoDetector extends Detector { |
|
|
|
|
|
|
|
|
|
|
|
// Parameters |
|
|
|
private static final float PIXEL_THRESHOLD = 40f; // Luminosity (brightness channel of YUV_420_888) |
|
|
|
private static final int BLUR_KERNEL_SIZE = 5; |
|
|
|
private static final int DILATE_KERNEL_SIZE = 5; |
|
|
|
private static final float CONTOUR_THRESHOLD = 250; |
|
|
|
private static final float ALARM_THRESHOLD = 0.5f; // Percent of pixels changed |
|
|
|
private static final long START_DELAY = 1000; // milliseconds |
|
|
|
private static final android.util.Size IMAGE_RES = new android.util.Size(640, 480); |
|
|
@@ -140,7 +137,6 @@ public class VideoDetector extends Detector { |
|
|
|
isDetectionRunning = false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Permission handling |
|
|
|
*/ |
|
|
@@ -172,29 +168,25 @@ public class VideoDetector extends Detector { |
|
|
|
Image image = imageProxy.getImage(); |
|
|
|
assert image != null; |
|
|
|
|
|
|
|
if (image != null) { |
|
|
|
Mat currentMat = extractYChannel(image); |
|
|
|
|
|
|
|
Mat mat = extractYChannel(image); |
|
|
|
Mat mat = currentMat.clone(); |
|
|
|
debugMat(mat, imageView2); |
|
|
|
|
|
|
|
debugMat(mat, imageView2); |
|
|
|
mat = processImage(mat); |
|
|
|
debugMat(mat, imageView1); |
|
|
|
Mat processed = processImage(mat); |
|
|
|
|
|
|
|
int n = 0; |
|
|
|
n = countNonZeroPixels(mat); |
|
|
|
debugMat(processed, imageView1); |
|
|
|
|
|
|
|
int pixelCount = image.getWidth() * image.getHeight(); |
|
|
|
float percentChanged = (float)n / pixelCount; |
|
|
|
// report violation |
|
|
|
if (percentChanged * 100 > ALARM_THRESHOLD) { |
|
|
|
reportViolation("Video", n); |
|
|
|
} |
|
|
|
int n = countNonZeroPixels(processed); |
|
|
|
int pixelCount = image.getWidth() * image.getHeight(); |
|
|
|
float percentChanged = (float)n / pixelCount; |
|
|
|
// report violation |
|
|
|
if (percentChanged * 100 > ALARM_THRESHOLD) { |
|
|
|
reportViolation("Video", n); |
|
|
|
} |
|
|
|
} |
|
|
|
imageProxy.close(); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Create Preview |
|
|
|
Preview preview = new Preview.Builder().build(); |
|
|
|
// Specify which Camera to use |
|
|
@@ -217,26 +209,42 @@ public class VideoDetector extends Detector { |
|
|
|
* @param image: OpenCV Mat file that should be processed |
|
|
|
*/ |
|
|
|
private Mat processImage(Mat image){ |
|
|
|
|
|
|
|
// Preprocess Image |
|
|
|
Mat preprocessed = image.clone(); |
|
|
|
preprocessed = addGaussianBlur(preprocessed, new Size(21, 21)); |
|
|
|
preprocessed = addBlur(preprocessed, new Size(3, 3)); |
|
|
|
|
|
|
|
if (previousImage == null) { |
|
|
|
previousImage = image; |
|
|
|
previousImage = preprocessed; |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
Mat mat = addGaussianBlur(image, BLUR_KERNEL_SIZE); |
|
|
|
mat = thresholdPixels(mat, previousImage); |
|
|
|
mat = dilateNonZero(mat, DILATE_KERNEL_SIZE); |
|
|
|
mat = thresholdContourArea(mat, CONTOUR_THRESHOLD); |
|
|
|
// Process Image |
|
|
|
Mat processed = preprocessed.clone(); |
|
|
|
processed = thresholdPixels(processed, previousImage, 25); |
|
|
|
processed = dilateBinaryMat(processed, new Size(3,3)); |
|
|
|
processed = dilateBinaryMat(processed, new Size(3,3)); |
|
|
|
processed = thresholdContourArea(processed, 500); |
|
|
|
|
|
|
|
previousImage = image.clone(); |
|
|
|
return mat; |
|
|
|
previousImage = preprocessed.clone(); |
|
|
|
return processed; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** OpenCV helper methods **/ |
|
|
|
private Mat addGaussianBlur(Mat inputMat, Size kernelSize){ |
|
|
|
Mat outputMat = new Mat(); |
|
|
|
Imgproc.GaussianBlur(inputMat, outputMat, kernelSize, 0); |
|
|
|
return outputMat; |
|
|
|
} |
|
|
|
|
|
|
|
private Mat addBlur(Mat inputMat, Size kernelSize){ |
|
|
|
Mat outputMat = new Mat(); |
|
|
|
Imgproc.blur(inputMat, outputMat, kernelSize); |
|
|
|
return outputMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Convert Android Image to OpenCV Mat file with only y-Channel |
|
|
|
* |
|
|
|
* @param img: Android Image |
|
|
|
* @return yChannel of Image in OpenCV Mat Format |
|
|
|
*/ |
|
|
|
private Mat extractYChannel(@NonNull Image img) { |
|
|
|
ByteBuffer yBuffer = img.getPlanes()[0].getBuffer(); |
|
|
|
byte[] yData = new byte[yBuffer.remaining()]; |
|
|
@@ -248,54 +256,14 @@ public class VideoDetector extends Detector { |
|
|
|
return yMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Threshold all Pixels |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param previousImage: previous Image (openCV Mat) |
|
|
|
* @return Binary Mat Image |
|
|
|
*/ |
|
|
|
private Mat thresholdPixels(Mat inputMat, Mat previousImage){ |
|
|
|
private Mat thresholdPixels(Mat inputMat, Mat previousImage, int threshold){ |
|
|
|
Mat diffImage = new Mat(); |
|
|
|
Core.absdiff(inputMat, previousImage, diffImage); |
|
|
|
|
|
|
|
Mat binaryMat = new Mat(); |
|
|
|
Imgproc.threshold(diffImage, binaryMat, VideoDetector.PIXEL_THRESHOLD, 255, Imgproc.THRESH_BINARY); |
|
|
|
|
|
|
|
Imgproc.threshold(diffImage, binaryMat, threshold, 255, Imgproc.THRESH_BINARY); |
|
|
|
return binaryMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Dilate Pixels of Binary Image |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param kernelSize: kernel Size |
|
|
|
* @return binary Image with dilated Pixels |
|
|
|
*/ |
|
|
|
private Mat dilateNonZero(Mat inputMat, int kernelSize){ |
|
|
|
Mat dilatedMat = new Mat(); |
|
|
|
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new org.opencv.core.Size(kernelSize, kernelSize)); |
|
|
|
Imgproc.dilate(inputMat, dilatedMat, kernel); |
|
|
|
return dilatedMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Add Gaussian Blur to OpenCV Mat Image |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param kernelSize: kernel Size |
|
|
|
* @return Mat Image |
|
|
|
*/ |
|
|
|
private Mat addGaussianBlur(Mat inputMat, int kernelSize){ |
|
|
|
Mat outputMat = new Mat(); |
|
|
|
Imgproc.GaussianBlur(inputMat, outputMat, new org.opencv.core.Size(kernelSize, kernelSize), 0); |
|
|
|
return outputMat; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Filter Contour Areas by Size |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param areaThreshold: Threshold |
|
|
|
* @return Binary Mat Image |
|
|
|
*/ |
|
|
|
private Mat thresholdContourArea(Mat inputMat, float areaThreshold){ |
|
|
|
List<MatOfPoint> contours = new ArrayList<>(); |
|
|
|
Mat hierarchy = new Mat(); |
|
|
@@ -315,11 +283,13 @@ public class VideoDetector extends Detector { |
|
|
|
return outputMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Count all Pixels that are non Zero |
|
|
|
* @param inputImage: Input Image in OpenCV Mat Format |
|
|
|
* @return Count of Pixels that are non zero |
|
|
|
*/ |
|
|
|
private Mat dilateBinaryMat(Mat inputMat, Size kernelSize){ |
|
|
|
Mat dilatedMat = new Mat(); |
|
|
|
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, kernelSize); |
|
|
|
Imgproc.dilate(inputMat, dilatedMat, kernel); |
|
|
|
return dilatedMat; |
|
|
|
} |
|
|
|
|
|
|
|
private int countNonZeroPixels(Mat inputImage) { |
|
|
|
if (inputImage != null) |
|
|
|
return Core.countNonZero(inputImage); |
|
|
@@ -327,11 +297,8 @@ public class VideoDetector extends Detector { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Show OpenCV Mat on ImageView |
|
|
|
* @param mat: current OpenCV Mat Image |
|
|
|
* @param imageView: ImageView xml-Element |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
private void debugMat(Mat mat, ImageView imageView) { |
|
|
|
if (imageView == null || mat == null) |
|
|
|
return; |