#header-inner {background-position: right !important; width: 100% !important;}

3/6/12

Putting pieces together

I've integrated camera image capture with image processor, creating simple but functional motion detector that can be actually run.

not sure if it's still working after possible GStreamer-Java version updates... perhaps can be corrected if not.

Source code:


import java.awt.image.BufferedImage;

public class MotionDetector {

private final ImageProcessor ip;
private final ImageCapture ic;
private final Thread motionDetectorThread;
private final int threshold;
private final Runnable motionDetectorRunnable = new Runnable() {

private BufferedImage overlayImage = null;
private BufferedImage foregroundImage = null;

@Override
public void run() {
while(true) {
try {
Thread.sleep(100); // wait 0.1 second
} catch (InterruptedException e) {
}

int difference = compareImages(overlayImage, foregroundImage);
if (difference >= threshold) {
System.out.println("motion detected with difference of " + difference);
}

overlayImage = foregroundImage;
foregroundImage = ic.getCurrentImage();
}
}
};

public MotionDetector(final ImageCapture ic, final ImageProcessor ip, final int threshold) {
this.ic = ic;
this.ip = ip;
this.threshold = threshold;
motionDetectorThread = new Thread(motionDetectorRunnable);
motionDetectorThread.start();
}

private int compareImages(final BufferedImage img1, final BufferedImage img2) {
if (img1 == null || img2 == null) {
return 0;
}

// convert to grayscale
int[][] grayscaleArray1 = ip.getGrayscaleArray(img1);
int[][] grayscaleArray2 = ip.getGrayscaleArray(img2);

// apply compensate background light change filter
int[][] compensatedGrayScaleArray1 = ip.applyCompensateBackgroundLightChangeFilter(
grayscaleArray1, grayscaleArray2, 3);

// apply difference filter (difference between pixel values)
int[][] differenceArray = ip.applyDifferenceFilter(compensatedGrayScaleArray1, grayscaleArray2);

// apply threshold filter (if pixel value > threshold it's white, otherwise black)
int[][] blackAndWhiteArray = ip.applyThresholdFilter(differenceArray, 108);

// apply erosion filter (blacken pixels that do not have x white neighbors)
int[][] erodedBlackAndWhiteArray = ip.applyErosionFilter(blackAndWhiteArray, 1);

// inform about movement magnitude
int movementMagnitude = ip.countMovementMagnitude(erodedBlackAndWhiteArray);

return movementMagnitude;
}

public static void main(final String[] args) {
final int threshold = 100;
final ImageCapture ic = new ImageCapture(args);
final ImageProcessor ip = new ImageProcessor();
final MotionDetector md = new MotionDetector(ic, ip, threshold);
}


}





import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.nio.IntBuffer;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

import org.gstreamer.Caps;
import org.gstreamer.Element;
import org.gstreamer.ElementFactory;
import org.gstreamer.Gst;
import org.gstreamer.Pipeline;
import org.gstreamer.State;
import org.gstreamer.elements.RGBDataSink;

public class ImageCapture {

private Pipeline pipe;
private BufferedImage currentImage = null;
private JLabel currentImageLabel = new JLabel();

public ImageCapture(final String[] args) {
preparePipeline(args);
pipe.setState(State.PLAYING);
}

public final BufferedImage getCurrentImage() {
return currentImage;
}

public final JLabel getCurrentImageLabel() {
return currentImageLabel;
}

private void preparePipeline(String[] args) {
args = Gst.init("SwingVideoTest", args);
pipe = new Pipeline("pipeline");
ElementFactory.make("videotestsrc", "source");
final Element videosrc = ElementFactory.make("v4l2src", "source");
final Element videofilter = ElementFactory.make("capsfilter", "flt");
videofilter.setCaps(Caps
.fromString("video/x-raw-yuv, width=640, height=480"));

RGBDataSink.Listener imageCaptureListener = new RGBDataSink.Listener() {
@Override
public void rgbFrame(boolean isPreRollImage, int width, int height,
IntBuffer rgb) {
currentImage = getBufferedImage(width, height);
copyDataToImage(rgb, currentImage, width, height);

// One way to display image on JPanel..
ImageIcon icon = new ImageIcon(currentImage);
currentImageLabel.setIcon(icon);
}

private BufferedImage getBufferedImage(int width, int height) {
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
bufferedImage.setAccelerationPriority(0.0f);
return bufferedImage;
}

private void copyDataToImage(IntBuffer rgb, BufferedImage image,
int width, int height) {
int[] pixels = ((DataBufferInt) image.getRaster()
.getDataBuffer()).getData();
rgb.get(pixels, 0, width * height);
}
};

final RGBDataSink videosink = new RGBDataSink("rgb",
imageCaptureListener);

pipe.addMany(videosrc, videofilter, videosink);
Element.linkMany(videosrc, videofilter, videosink);

}

}





import java.awt.Color;
import java.awt.image.BufferedImage;

public class ImageProcessor {
public int[][] getColorArray(final BufferedImage img) {
assert img != null;

final int width = img.getWidth();
final int height = img.getHeight();

final int[][] result = new int[width][height];

for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
result[i][j] = img.getRGB(i, j);
}
}

return result;
}

public int[][] getGrayscaleArray(final BufferedImage img) {
assert img != null;

final int width = img.getWidth();
final int height = img.getHeight();

final int[][] result = new int[width][height];

for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int color = img.getRGB(i, j);

int red = (color & 0x00ff0000) >> 16;
int green = (color & 0x0000ff00) >> 8;
int blue = color & 0x000000ff;
int avgGray = (red + green + blue) / 3;
Color grayColor = new Color(avgGray, avgGray, avgGray);

result[i][j] = grayColor.getRGB();
}
}

return result;
}

public int[][] applyCompensateBackgroundLightChangeFilter(final int[][] grayscaleToCompensate, final int[][] grayscaleToCompensateWith, final int iterations) {
int[][] result = grayscaleToCompensate;
for (int i=0; i<iterations; i++) {
int averageGray1 = getAverageGrayscaleValue(result);
int averageGray2 = getAverageGrayscaleValue(grayscaleToCompensateWith);
int averageGrayDifference = averageGray1 - averageGray2;
result = compensateLightDifference(result, averageGrayDifference);
}
return result;
}

public int[][] applyDifferenceFilter(final int[][] colorArray1, final int[][] colorArray2) {
assert colorArray1 != null;
assert colorArray2 != null;
assert colorArray1.length > 0;
assert colorArray2.length > 0;
assert colorArray1.length == colorArray2.length;
assert colorArray1[0].length == colorArray2[0].length;

final int width = colorArray1.length;
final int height = colorArray1[0].length;

final int[][] result = new int[width][height];

for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int color1 = colorArray1[i][j];
int color2 = colorArray2[i][j];

int red1 = (color1 & 0x00ff0000) >> 16;
int red2 = (color2 & 0x00ff0000) >> 16;

int green1 = (color1 & 0x0000ff00) >> 8;
int green2 = (color2 & 0x0000ff00) >> 8;

int blue1 = color1 & 0x000000ff;
int blue2 = color2 & 0x000000ff;

result[i][j] = new Color(
Math.abs(red1 - red2), Math.abs(green1 - green2), Math.abs(blue1 - blue2)).getRGB();
}
}

return result;
}

public int[][] applyThresholdFilter(int[][] colorArray, int threshold) {
final int width = colorArray.length;
final int height = colorArray[0].length;

final int[][] result = new int[width][height];

for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int color = colorArray[i][j];
int red = (color & 0x00ff0000) >> 16;
int green = (color & 0x0000ff00) >> 8;
int blue = color & 0x000000ff;
int avgGray = (red + green + blue) / 3;

result[i][j] = avgGray > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}
}

return result;
}

/**
* @param colorArray
* @param threshold number of neighboring white pixels needed to retain visibility of pixel
* @return
*/
public int[][] applyErosionFilter(int[][] grayscaleArray, int threshold) {
final int width = grayscaleArray.length;
final int height = grayscaleArray[0].length;

final int[][] result = new int[width][height];

// interior
for (int i = 1; i < width-1; i++) {
for (int j = 1; j < height-1; j++) {
int color = grayscaleArray[i][j];

if (color != Color.WHITE.getRGB()) { // check only white pixels
result[i][j] = Color.BLACK.getRGB();
continue;
}

int whiteNeighborPixelCount = 0;

whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i-1][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i+1][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i-1][j]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i+1][j]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i-1][j+1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i][j+1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i+1][j+1]);

result[i][j] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}
}

// borders
for (int i=1; i<width-1; i++) {
int upperBorderColor = grayscaleArray[i][0];

if (upperBorderColor != Color.WHITE.getRGB()) { // check only white pixels
result[i][0] = Color.BLACK.getRGB();
continue;
}

int whiteNeighborPixelCount = 3;

whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i-1][0]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i+1][0]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i-1][1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i][1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i+1][1]);

result[i][0] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

for (int i=1; i<width-1; i++) {
int lowerBorderColor = grayscaleArray[i][height-1];

if (lowerBorderColor != Color.WHITE.getRGB()) { // check only white pixels
result[i][height-1] = Color.BLACK.getRGB();
continue;
}

int whiteNeighborPixelCount = 3;

whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i-1][height-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i+1][height-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i-1][height-2]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i][height-2]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[i+1][height-2]);

result[i][height-1] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

for (int j=1; j<height-1; j++) {
int leftBorderColor = grayscaleArray[0][j];

if (leftBorderColor != Color.WHITE.getRGB()) { // check only white pixels
result[0][j] = Color.BLACK.getRGB();
continue;
}

int whiteNeighborPixelCount = 3;

whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[0][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[0][j+1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[1][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[1][j]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[1][j+1]);

result[0][j] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

for (int j=1; j<height-1; j++) {
int rightBorderColor = grayscaleArray[0][j];

if (rightBorderColor != Color.WHITE.getRGB()) { // check only white pixels
result[width-1][j] = Color.BLACK.getRGB();
continue;
}

int whiteNeighborPixelCount = 3;

whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-1][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-1][j+1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-2][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-2][j-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-2][j+1]);

result[width-1][j] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

// corners
int upperLeftColor = grayscaleArray[0][0];
if (upperLeftColor != Color.WHITE.getRGB()) { // check only white pixels
result[0][0] = Color.BLACK.getRGB();
} else {
int whiteNeighborPixelCount = 5;
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[0][1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[1][1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[1][0]);

result[0][0] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

int upperRightColor = grayscaleArray[width-1][0];
if (upperRightColor != Color.WHITE.getRGB()) { // check only white pixels
result[width-1][0] = Color.BLACK.getRGB();
} else {
int whiteNeighborPixelCount = 5;
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-1][0]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-2][1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-2][0]);

result[width-1][0] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

int lowerLeftColor = grayscaleArray[0][height-1];
if (lowerLeftColor != Color.WHITE.getRGB()) { // check only white pixels
result[0][height-1] = Color.BLACK.getRGB();
} else {
int whiteNeighborPixelCount = 5;
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[0][height-2]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[1][height-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[1][height-2]);

result[0][height-1] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

int lowerRightColor = grayscaleArray[width-1][height-1];
if (lowerRightColor != Color.WHITE.getRGB()) { // check only white pixels
result[width-1][height-1] = Color.BLACK.getRGB();
} else {
int whiteNeighborPixelCount = 5;
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-1][height-2]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-2][height-1]);
whiteNeighborPixelCount = adjustWhiteNeighborPixelCount(whiteNeighborPixelCount, grayscaleArray[width-2][height-2]);

result[width-1][height-1] = whiteNeighborPixelCount > threshold ? Color.WHITE.getRGB() : Color.BLACK.getRGB();
}

return result;
}

public final int countMovementMagnitude(int[][] erodedBlackAndWhiteArray) {
final int width = erodedBlackAndWhiteArray.length;
final int height = erodedBlackAndWhiteArray[0].length;

int result = 0;

for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int color = erodedBlackAndWhiteArray[i][j];

if (color == Color.WHITE.getRGB()) {
result = result + 1;
}
}
}

return result;
}


public BufferedImage getImage(final int width, final int height, final int[][] colorArray) {
assert width > 0;
assert height > 0;
assert colorArray != null;

final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

for (int i=0; i<width; i++) {
for (int j=0; j<height; j++) {
result.setRGB(i, j, colorArray[i][j]);
}
}

return result;
}

/**
* @param grayscaleArray reference image.
* At each pixel, color samples adhere to rule:
* image(x,y).getRed == pixel(x,y).getGreen == pixel(x,y).getBlue
* @return
*/
public int getAverageGrayscaleValue(int[][] grayscaleArray) {
assert grayscaleArray != null;

final int width = grayscaleArray.length;
final int height = grayscaleArray[0].length;

long averageGrayscaleValue = 0;

for (int i=0; i<width; i++) {
for (int j=0; j<height; j++) {
int red = new Color(grayscaleArray[i][j]).getRed();
int green = new Color(grayscaleArray[i][j]).getGreen();
int blue = new Color(grayscaleArray[i][j]).getBlue();
if (red != green || green != blue) throw new IllegalArgumentException("red != green || green != blue");

averageGrayscaleValue = averageGrayscaleValue + green;
}
}

averageGrayscaleValue = averageGrayscaleValue / (width*height);
return (int) averageGrayscaleValue;
}

public int[][] compensateLightDifference(int[][] grayscaleArray, int lightDifference) {
assert grayscaleArray != null;

final int width = grayscaleArray.length;
final int height = grayscaleArray[0].length;

int[][] result = new int[width][height];

for (int i=0; i<width; i++) {
for (int j=0; j<height; j++) {
int red = new Color(grayscaleArray[i][j]).getRed();
int green = new Color(grayscaleArray[i][j]).getGreen();
int blue = new Color(grayscaleArray[i][j]).getBlue();
if (red != green || green != blue) throw new IllegalArgumentException("red != green || green != blue");

int compensatedValue = green - lightDifference;

if (compensatedValue > 255) {
compensatedValue = 255;
}

if (compensatedValue < 0) {
compensatedValue = 0;
}

result[i][j] = new Color(compensatedValue, compensatedValue, compensatedValue).getRGB();
}
}

return result;
}


/**
* @param whiteNeighborPixelCount initial whiteNeighborPixelCount
* @param neighborPixelColor color of neighbor pixel to check
* @return adjusted white neighbor pixel count
*/
private int adjustWhiteNeighborPixelCount(final int whiteNeighborPixelCount, int neighborPixelColor) {
return neighborPixelColor == Color.WHITE.getRGB() ? whiteNeighborPixelCount + 1 : whiteNeighborPixelCount;
}

}

No comments:

Post a Comment