[Java][Webカメラ][背景差分]Webカメラで撮っている動画に簡単な背景差分を適用してみる

Target

1. Webカメラで動画取得
2. その動画にシンプルな背景差分を適用

Environment

  • OS
    • Windows 7 Enterprise SP1
  • java
    • 1.7.0_51-b13
  • webcam-capture
    • 0.3.10
  • web camera
    • PC購入時に本体についていたもの

Develop

ライブラリの準備

Webカメラの制御に「webcam-capture」というライブラリを利用している。
インストールはダウンロードして解凍するだけ。
  1. 上記リンクからダウンロード
  2. 解凍
  3. 3つのjarファイル(bridj-0.6.2.jar, slf4j-api-1.7.2.jar, webcam-capture-0.3.10.jar)をプロジェクトに追加
今回はIDEは特に利用しないため、以下のように配置した。
.
├── BackgroundSubtraction.java
├── BackgroundSubtraction.class
└── lib
      ├── bridj-0.6.2.jar
      ├── slf4j-api-1.7.2.jar
      └── webcam-capture-0.3.10.jar

1 directories, 5 files

ソースコード

import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.io.*;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamUtils;
import com.github.sarxos.webcam.util.ImageUtils;
import com.github.sarxos.webcam.WebcamPanel;
import com.github.sarxos.webcam.WebcamResolution;
import com.github.sarxos.webcam.WebcamImageTransformer;

public class BackgroundSubtraction implements WebcamImageTransformer {
  private BufferedImage background = null;

  public static int getR(int c) { return c>>16&0xff; }
  public static int getG(int c) { return c>>8&0xff;  }
  public static int getB(int c) { return c&0xff;       }
  public static int rgb(int r,int g,int b)  { return 0xff000000 | r <<16 | g <<8 | b; }
  
  // Get background image
  public void takePicture() throws IOException {
    Webcam webcam = null;
    webcam = Webcam.getDefault();
    if (webcam != null) {
      System.out.println("Webcam : " + webcam.getName());
      WebcamUtils.capture(webcam, "capture", ImageUtils.FORMAT_PNG);
    } else {
      System.out.println("Failed: Webcam Not Found Error");
      System.exit(1);
    }
    
    try {
      background = ImageIO.read(new File("./capture.png"));
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }
  }
  
  @Override
  public BufferedImage transform(BufferedImage image) {
    int         width  = image.getWidth();
    int         height = image.getHeight();
    BufferedImage newImage = new BufferedImage(width, height, 5);

    // Background Subtraction Part
    for (int i = 0; i < width; i++) {
      for(int j = 0; j < height; j++) {
        int c = image.getRGB(i,j);
        int fr = getR(c);
        int fg = getG(c);
        int fb = getB(c);
        
        c = background.getRGB(i,j);
        int br = getR(c);
        int bg = getG(c);
        int bb = getB(c);
        int dist = Math.abs(fr - br) + Math.abs(fg - bg) + Math.abs(fb - bb);

        // Using only color value difference
        // In actual situation, more sophisticated technique is needed.
        if (dist > 50) {
          newImage.setRGB(i, j, image.getRGB(i,j));
        } else {
          // Background color is white
          newImage.setRGB(i, j, rgb(255,255,255));
        }
      }
    }

    return newImage;
  }

  public BackgroundSubtraction() {
    try {
      takePicture();
    } catch(IOException e) {
      System.out.println("Failed to take screenshot");
      System.exit(1);
    }

    Webcam webcam = Webcam.getDefault();
    webcam.setImageTransformer(this);

    WebcamPanel panel = new WebcamPanel(webcam);
    panel.setFPSDisplayed(true);
    panel.setFillArea(true);
    panel.setDisplayDebugInfo(true);
    //panel.setImageSizeDisplayed(true);
    panel.setMirrored(true);

    javax.swing.JFrame frame = new javax.swing.JFrame("BackgroundSubtraction");
    frame.add(panel);
    frame.setResizable(true);
    frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }

  public static void main(String[] args) {
    new BackgroundSubtraction();
  }
}

コンパイルと実行

以下のコマンドでコンパイルと実行ができる。
javac -cp .\lib\webcam-capture-0.3.10.jar;.\lib\bridj-0.6.2.jar;.\lib\slf4j-api-1.7.2.jar BackgroundSubtraction.java
java -cp .;.\lib\webcam-capture-0.3.10.jar;.\lib\bridj-0.6.2.jar;.\lib\slf4j-api-1.7.2.jar BackgroundSubtraction

Demo

zuqqhi2

某Web系の会社でエンジニアをやっています。 学術的なことに非常に興味があります。 趣味は楽器演奏、ジョギング、読書、料理などなど手広くやっています。