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

3/1/12

How to turn usb camera into motion sensor

I've tried to find simple and effective Java Image Processing library, that would help me to implement motion detection algorithm. I ended up coding it on my own.

Update: see this post for updated & bugfixed version of ImageProcessor class.

Things are put together in this post.


Source code:

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[][] 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[][] 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];

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

int red = (color & 0x00ff0000) >> 16;
int green = (color & 0x0000ff00) >> 8;
int blue = color & 0x000000ff;

int whiteNeighborPixelCount = 0;

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

result[i][j] = 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++) {
final int index = i + i*j;
result.setRGB(i, j, colorArray[i][j]);
}
}

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;
}

}



import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class MotionDetector {

private static final BufferedImage zrzut1 = loadImage("resources/zrzut_ekranu.png");
private static final BufferedImage zrzut2 = loadImage("resources/zrzut_ekranu-1.png");

public static void main(String[] args) {
JFrame frame = new JFrame("Swing Video Test");
frame.setLayout(new GridLayout(1, 1));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final ImageProcessor ic = new ImageProcessor();

// convert to grayscale
int[][] grayscaleArray1 = ic.getGrayscaleArray(zrzut1);
int[][] grayscaleArray2 = ic.getGrayscaleArray(zrzut2);

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

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

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

// inform about movement magnitude
int movementMagnitude = ic.countMovementMagnitude(erodedBlackAndWhiteArray);
System.out.println(movementMagnitude);

// display final image
final Image img = ic.getImage(zrzut1.getWidth(), zrzut1.getHeight(), erodedBlackAndWhiteArray);

JLabel currentImageLabel = new JLabel();
ImageIcon icon = new ImageIcon(img);
currentImageLabel.setIcon(icon);

currentImageLabel.setPreferredSize(new Dimension(720, 576));
frame.add(currentImageLabel);
frame.pack();
frame.setVisible(true);
}

private static BufferedImage loadImage(final String fileName) {
BufferedImage result = null;
try {
result = ImageIO.read(new File(fileName));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(0);
}
return result;
}

}

No comments:

Post a Comment