LoginSignup
4
4

More than 5 years have passed since last update.

【メモ】Android OpenCV-FloodFill

Posted at

これ

以下、プレビュー

ezgif-5-43ace14d23.gif

以下、ソースコード

MainActivity.class
package com.example.c_heo.floodfilltest;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnTouchListener, SurfaceHolder.Callback2, View.OnClickListener{
    private static final String TAG = MainActivity.class.getSimpleName();

    static {
        Log.d(TAG, "static initializer: Trying to load OpenCV library.");
        OpenCVLoader.initDebug();
    }

    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;

    private Bitmap bitmap;
    private Mat mat;

    private List<CircleCoordinate> circleCoordinateList = new ArrayList<>();
    private List<LineCoordinate> lineCoordinateList = new ArrayList<>();
    private List<SeedCoordinate> seedCoordinateList = new ArrayList<>();
    private Mode mode;
    private float preX, preY, postX, postY;

    private Paint circlePaint;
    private Paint linePaint;
    private Paint pathPaint; // TODO: memory管理のため、lineをpathに書き換え

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        surfaceView = findViewById(R.id.surfaceView);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);

        circlePaint = new Paint();
        circlePaint.setColor(Color.LTGRAY);

        linePaint = new Paint();
        linePaint.setColor(Color.LTGRAY);
        linePaint.setStrokeWidth(5.0f);

        findViewById(R.id.drawingButton).setOnClickListener(this);
        findViewById(R.id.floodFillButton).setOnClickListener(this);
    }

    @Override
    public void surfaceRedrawNeeded(SurfaceHolder holder) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        surfaceView.setOnTouchListener(this);
        Log.d(TAG, "surfaceChanged: [width, height] # ["+width+", "+height+"]");

        bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        mat = new Mat();

        circleCoordinateList.clear();
        lineCoordinateList.clear();

        mode = Mode.Drawing;

        Canvas canvas = surfaceHolder.lockCanvas();
        drawing(canvas);
        surfaceHolder.unlockCanvasAndPost(canvas);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        surfaceView.setOnTouchListener(null);

        // garbage collection
        mat.release();
        bitmap.recycle();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (mode == Mode.Drawing) {
            drawing(event);
        }
        else if (mode == Mode.FloodFill) {
            floodFilling(event);
        }


        Canvas canvas = surfaceHolder.lockCanvas();
        drawing(canvas);
        surfaceHolder.unlockCanvasAndPost(canvas);
        return true;
    }

    private void floodFilling(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN :
                addSeed(new SeedCoordinate((int) event.getX(), (int) event.getY()));
                break;
        }
    }

    private void drawing(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN :
                preX = event.getX();
                preY = event.getY();
                addCircle(new CircleCoordinate(preX, preY));
                break;

            case MotionEvent.ACTION_MOVE :
                postX = event.getX();
                postY = event.getY();
                addLine(new LineCoordinate(preX, preY, postX, postY));

                preX = postX;
                preY = postY;
                break;

            case MotionEvent.ACTION_UP :
                postX = event.getX();
                postY = event.getY();
                addCircle(new CircleCoordinate(postX, postY));

                preX = .0f;
                preY = .0f;
                postX = .0f;
                postY = .0f;
                break;
        }
    }

    private void addLine(LineCoordinate lineCoordinate) {
        lineCoordinateList.add(lineCoordinate);
    }
    private void addCircle(CircleCoordinate circleCoordinate) {
        circleCoordinateList.add(circleCoordinate);
    }

    private void addSeed(SeedCoordinate seedCoordinate) {
        seedCoordinateList.add(seedCoordinate);
    }

    // TODO: memory管理のため、canvasのdrawBitmap及び、setBitmapを以下のAPIに書き換え(: canvasのdrawBitmap withRect及び、setMatrix)
    private void drawing(Canvas canvas) {
        Canvas tempCanvas = new Canvas(bitmap);
        tempCanvas.drawColor(Color.GRAY);

        // draw Circles
        for (CircleCoordinate circleCoordinate : circleCoordinateList) {
            tempCanvas.drawCircle(circleCoordinate.cX, circleCoordinate.cY, 10.0f, circlePaint);
        }

        // draw Lines
        for (LineCoordinate lineCoordinate : lineCoordinateList) {
            tempCanvas.drawLine(lineCoordinate.startX, lineCoordinate.startY, lineCoordinate.stopX, lineCoordinate.stopY, linePaint);
        }

        // floodFill
        for (SeedCoordinate seedCoordinate : seedCoordinateList) {
            // load the input image
            Utils.bitmapToMat(bitmap, mat);
            Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGBA2RGB);

            // define the seed point
            Point seedPoint = new Point(seedCoordinate.cX, seedCoordinate.cY);

            // flood fill with red
            Imgproc.floodFill(
                    mat,
                    new Mat(),
                    seedPoint,
                    new Scalar(204, 204, 204), // LTGRAY
                    new Rect(),
                    new Scalar(0, 0, 0),
                    new Scalar(0, 0, 0),
                    4
            );

            // show the output
            Utils.matToBitmap(mat, bitmap);
        }

        // draw
        canvas.drawBitmap(bitmap, 0, 0, null);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.drawingButton :
                mode = Mode.Drawing;
                Log.d(TAG, "onClick: Drawing Mode.");
                break;

            case R.id.floodFillButton :
                mode = Mode.FloodFill;
                Log.d(TAG, "onClick: FloodFill Mode.");
                break;
        }
    }

    private class CircleCoordinate {
        float cX;
        float cY;

        CircleCoordinate(float cX, float cY) {
            this.cX = cX;
            this.cY = cY;
        }
    }

    private class LineCoordinate {
        float startX;
        float startY;
        float stopX;
        float stopY;

        LineCoordinate(float startX, float startY, float stopX, float stopY) {
            this.startX = startX;
            this.startY = startY;
            this.stopX = stopX;
            this.stopY = stopY;
        }
    }

    private class SeedCoordinate {
        int cX;
        int cY;

        SeedCoordinate(int cX, int cY) {
            this.cX = cX;
            this.cY = cY;
        }
    }

    private enum Mode {
        Drawing,
        FloodFill
    }
}

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4