2014年8月20日水曜日

AndroidでOpenCVを使って背景差分を取得する

Androidで画像に移った被写体との背景差分を取りたくて色々調べてみたところOpenCVというライブラリを使えばできることがわかった。

背景差分処理前の画像

背景差分処理後の画像

作ったサンプルコードは以下の通り

public class MainActivity extends Activity {
 static {
        if (!OpenCVLoader.initDebug()) {
            // Handle initialization error
        } else {
        }
    }
 private final static String TAG = "BGsubstractorTest";
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  if (savedInstanceState == null) {
   getFragmentManager().beginTransaction()
     .add(R.id.container, new PlaceholderFragment()).commit();
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 /**
  * A placeholder fragment containing a simple view.
  */
 public static class PlaceholderFragment extends Fragment {
  ImageView mImageView;

  public PlaceholderFragment() {
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   View rootView = inflater.inflate(R.layout.fragment_main, container,
     false);
   return rootView;
  }
  
  @Override
  public void onActivityCreated(Bundle savedInstanceState) {
   super.onActivityCreated(savedInstanceState);
   
   Mat input = new Mat();
   BackgroundSubtractorMOG mog = new BackgroundSubtractorMOG();
   Mat output = new Mat();
   
   Bitmap bitmap1 = loadBitmap(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/IMG_20140818_000833235.jpg");
   Utils.bitmapToMat(bitmap1, input);
   Imgproc.cvtColor(input, input, Imgproc.COLOR_RGBA2RGB);
   
   mog.apply(input, output);
   
   Bitmap bitmap2 = loadBitmap(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera/IMG_20140818_000849955.jpg");
   Utils.bitmapToMat(bitmap2, input);
   Imgproc.cvtColor(input, input, Imgproc.COLOR_RGBA2RGB);
   
   mog.apply(input, output);
   
   Bitmap bitmap3 = Bitmap.createBitmap(input.width(), input.height(), Bitmap.Config.ARGB_8888);
   Utils.matToBitmap(output, bitmap3);
   refreshImage(bitmap3);
  }
  
  private Bitmap loadBitmap(String imagefilePath) {
   BitmapFactory.Options options = new BitmapFactory.Options();
         options.inSampleSize = 4;
         options.inPreferredConfig = Config.ARGB_8888;
   Bitmap bm = BitmapFactory.decodeFile(imagefilePath, options);
   return bm;
  }
  
  private void refreshImage(Bitmap bmp) {
      mImageView = (ImageView)getActivity().findViewById(R.id.imageView1);
      mImageView.setImageBitmap(bmp);
  }
 }
}

つまづいた所としてはBackgroundSubtractorMOGに読み込ませる画像がRGBA形式だとエラーになってしまう。
そのため一度RGB形式に直してやらないとうまく動かない。

Imgproc.cvtColor(input, input, Imgproc.COLOR_RGBA2RGB);