これ
以下、プレビュー
以下、ソースコード
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
}
}