4

I have Mat difference which has some black pixels(or really nearly black pixels -> if earhquake occurs, buliding will move etc.) in it and the Mat current which consists real image with natural colors. I would like to replace pixels in Mat current with these black pixels in Mat difference. If I do it manually like this:

for(int i = 0; i < difference.rows(); i++){
            for(int j = 0; j < difference.cols(); j++){
                subtractedPixel = difference.get(i, j);
                if(subtractedPixel[0] < 10 && subtractedPixel[1] < 10 && subtractedPixel[2] < 10){
                    originalPixel = current.get(i, j);
                    difference.put(i, j, originalPixel);
                }
            }

it is extremely slow.

Full code(running):

package com.example.szpieg2;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Range;
import org.opencv.core.Size;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager;

public class TrackActivity extends Activity implements CvCameraViewListener {
    private Mat current;
    private CameraBridgeViewBase cameraView;
    private Mat previous;
    private Mat difference;//difference between previous and current
    private boolean first = true;
    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Log.i("Co sie dzieje?", "OpenCV loaded successfully");
                cameraView.enableView();
                // cameraView.setOnTouchListener(ColorBlobDetectionActivity.this);
            }
                break;
            default: {
                super.onManagerConnected(status);
            }
                break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        setContentView(R.layout.activity_track);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        cameraView = (CameraBridgeViewBase) findViewById(R.id.surface_view);
        cameraView.setCvCameraViewListener(this);
    }

    // --------Activity Actions---------
    @Override
    public void onPause() {
        if (cameraView != null)
            cameraView.disableView();
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this,
                mLoaderCallback);
    }

    public void onDestroy() {
        super.onDestroy();
        if (cameraView != null)
            cameraView.disableView();
    }

    // --------/Activity Actions/---------

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_track, menu);
        return true;
    }

    // --------listener method implementation-------------
    @Override
    public void onCameraViewStarted(int width, int height) {
        /*current = new Mat(width, height, CvType.CV_64FC4);
        previous = new Mat(width, height, CvType.CV_64FC4);
        difference = new Mat(width, height, CvType.CV_64FC4);*/
        current = new Mat(width, height, CvType.CV_8UC4);
        previous = new Mat(width, height, CvType.CV_8UC4);
        difference = new Mat(width, height, CvType.CV_8UC4);//RGBA 0..255
    }

    @Override
    public void onCameraViewStopped() {
        current.release();

    }

    @Override
    public Mat onCameraFrame(Mat inputFrame) {
        inputFrame.copyTo(current);
        if(first){//first is true at the first time
            inputFrame.copyTo(previous);
            first = false;
            Log.i("First processing", "Pierwszy przebieg");
        }   
        Core.absdiff(current, previous, difference);
    //  Core.absdiff( previous,current, difference);
        //I leave black pixels and load original colors
        double[] subtractedPixel, originalPixel;
        String s = "";
        for(int i = 0; i < difference.rows(); i++){
            for(int j = 0; j < difference.cols(); j++){
                subtractedPixel = difference.get(i, j);
                if(subtractedPixel[0] < 10 && subtractedPixel[1] < 10 && subtractedPixel[2] < 10){
                    originalPixel = previous.get(i, j);
                    difference.put(i, j, originalPixel);
                }
            }
        //  s+="\n";
        }
    //  Log.i("mat ", s);


//      Log.i("mat ",  difference.get(44,444)[0] + "");


        //---------------------------------------------
        inputFrame.copyTo(previous);    


        return difference;//UNREAL COLORS
    }

}
Yoda
  • 17,363
  • 67
  • 204
  • 344
  • @Aurelius Threshold is 10 so pixel(9,9,9) is treated as black. It does compile, mat has get and put. I posted full code. – Yoda Jun 13 '13 at 18:26
  • I didn't see the `java` tag until now. Also, the full code probably isn't necessary. I can understand your problem without it. – Aurelius Jun 13 '13 at 18:27
  • @Aurelius thanks so the thing is I want to copy only some pixels which fulfill logic requirement of being dark. – Yoda Jun 13 '13 at 18:31

1 Answers1

5

You can do the following.

  1. Threshold your image using inRange().

    Mat mask;
    void inRange(difference, Scalar(0,0,0), Scalar(9,9,9), mask)
    

    The output mask will be a binary mask where its pixel is set to 255 if its under threshold cv::Scalar(9,9,9);

  2. Copy difference image into current image through mask using copyTo().

    difference.copyTo(current, mask);
    
Alexey
  • 5,898
  • 9
  • 44
  • 81
  • Great minds think alike! Note that inRange is inclusive of both bounds. – Aurelius Jun 13 '13 at 18:48
  • yes, we answered at almost the same time! thanks, I just edited that. – Alexey Jun 13 '13 at 18:50
  • @Alexey thank you both I accept the earlier answer both helped(I uppvoted both) but it worked great it also occured to me that the problem is bit different I would like to copy only between certain area but THANK you BOTH – Yoda Jun 13 '13 at 19:12
  • @Yoda if you want to work only with a certain area you can use [region of interest](http://stackoverflow.com/a/12706208/1121420). – Alexey Jun 13 '13 at 19:15