iSight第5弾 動体検出!


今回やったこと
・前回やった動き検出の、フレームごとの平均をとる
・動きの大きさ(平均)を白四角で表現する
・動きを検出した範囲を四角で囲む

一つ前のプログラムと同じく、独自クラスImgIOクラスを使用しております。

    /**
     * 前回の画像との差の平均を検出し、その平均座標に平均値に応じた四角を描画します。
     * @param iio
     * @param img
     */
    public void drawDiffAve(ImgIO iio, BufferedImage img) {
 
        //イメージの大きさ
        int w = img.getWidth();
        int h = img.getHeight();
 
        //平均値
        int aveX = 0;
        int aveY = 0;
        int sumCount = 0;
 
        //最大値、最小値
        int maxX = 0;
        int maxY = 0;
        int minX = img.getWidth();
        int minY = img.getHeight();
 
        //Graphicsを取得
        Graphics2D gbg = (Graphics2D) img.getGraphics();
 
        //α値を設定。1.0は不透明。
        gbg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
 
        //一つ前の画像がnullだったら何もしない
        if (oldImgIO != null) {
 
            //各ピクセルを線形探索
            for (int y = 0; y < h; y++) {
                for (int x = 0; x < w; x++) {
 
                    //明度を取得
                    double Y = iio.getAveYValue(x, y, 1, 1);
 
                    //一つ前の画像から明度を取得
                    double oldY = oldImgIO.getAveYValue(x, y, 1, 1);
 
                    //差の絶対値を取得する
                    double diff = Math.abs(oldY - Y);
 
 
                    //明度が大きく変わっているところを動きがあったところと認識する
                    if (diff > 20) {
 
                        //最大値と最小値を更新
                        if (maxX < x) {
                            maxX = x;
                        }
                        if (maxY < y) {
                            maxY = y;
                        }
                        if (minX > x) {
                            minX = x;
                        }
                        if (minY > y) {
                            minY = y;
                        }
 
                        //平均値を更新
                        aveX = aveX + x;
                        aveY = aveY + y;
                        sumCount++;
                    }
                }
            }
        }
 
        if (sumCount != 0) {
 
            //平均の座標を計算
            aveX = aveX / sumCount;
            aveY = aveY / sumCount;
 
            //色を設定
            gbg.setColor(Color.WHITE);
            //動きの中心を描画
            gbg.drawLine(aveX, 0, aveX, img.getHeight());
            gbg.drawLine(0, aveY, img.getWidth(), aveY);
            //動きの大きさを描画
            gbg.fillRect(aveX - (sumCount / 200), aveY - (sumCount / 200), sumCount / 100,
                    sumCount / 100);
            //動きの範囲を描画
            gbg.drawRect(minX, minY, maxX - minX, maxY - minY);
        }
        //画像のコピーを保存する
        oldImgIO = new ImgIO(iio.copyImage());
 
        //Graphicesを破棄
        gbg.dispose();
    }


~お約束~
このコードを利用することであなたが何らかの損害を被ったとしても、私白峰はなんの保証も行わないこととします。

欠点として、
・たまに拾ったノイズを動体と認識してしまうので白枠の四角がやたらと大きくなったりする。
・物の影も動体として拾ってしまう
・どれだけ動体があっても一つの物として扱ってしまう
などなど。

防犯システムとかに使われてるようなシステムにするには別な人は別な人と分けて認識してますからね。そういうこともできるようにしたいなとか思っています。