Tix
Tix

Reputation: 449

OpenCV Java, Getting region of interest from image

I am trying to detect a certain area(rectangle) in an image, and get its upper and lower bounds, but im stuck at the point where i have to get the Region of interest.

Starting from this image:

Starting image

I want to get the area of interest like so:

Blue ROI

I converted the python code answered by Alexander Reynolds here, But i cant seem to view the result as I'm getting an error:

java.lang.IllegalArgumentException: bmp == null

at

Utils.matToBitmap(roiMat,temp);

        bitmap = constructor.getBmp();
        Mat srcMat = new Mat();
        Utils.bitmapToMat(bitmap, srcMat);

        Mat hsvMat = new Mat();
        Imgproc.cvtColor(srcMat,hsvMat,Imgproc.COLOR_BGR2HSV);

        Mat roiMat;
        Range rowRange = new Range(95, 436); //95 837, top left// 436,837 top right,,//95 895,, btm left, //436, 895 btm right
        Range colRange = new Range(837, 895);
        roiMat = new Mat(hsvMat, colRange, rowRange); // public Mat(Mat m, Range rowRange, Range colRange)

        Utils.matToBitmap(roiMat, temp);
        ImageView imageView = (ImageView) findViewById(R.id.imageView);
        imageView.setImageBitmap(temp);
    }

Upvotes: 2

Views: 3445

Answers (1)

Andrii Omelchenko
Andrii Omelchenko

Reputation: 13343

You can try call this method:

private Bitmap findRoi(Bitmap sourceBitmap) {
    Bitmap roiBitmap = null;
    Scalar green = new Scalar(0, 255, 0, 255);
    Mat sourceMat = new Mat(sourceBitmap.getWidth(), sourceBitmap.getHeight(), CvType.CV_8UC3);
    Utils.bitmapToMat(sourceBitmap, sourceMat);
    Mat roiTmp = sourceMat.clone();

    final Mat hsvMat = new Mat();
    sourceMat.copyTo(hsvMat);

    // convert mat to HSV format for Core.inRange()
    Imgproc.cvtColor(hsvMat, hsvMat, Imgproc.COLOR_RGB2HSV);

    Scalar lowerb = new Scalar(85, 50, 40);         // lower color border for BLUE
    Scalar upperb = new Scalar(135, 255, 255);      // upper color border for BLUE
    Core.inRange(hsvMat, lowerb, upperb, roiTmp);   // select only blue pixels

    // find contours
    List<MatOfPoint> contours = new ArrayList<>();
    List<RotatedRect> boundingRects = new ArrayList<>();
    Imgproc.findContours(roiTmp, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);

    // find appropriate bounding rectangles
    for (MatOfPoint contour : contours) {
        MatOfPoint2f areaPoints = new MatOfPoint2f(contour.toArray());
        RotatedRect boundingRect = Imgproc.minAreaRect(areaPoints);

        double rectangleArea = boundingRect.size.area();

        // test min ROI area in pixels
        if (rectangleArea > 400) {
            Point rotated_rect_points[] = new Point[4];
            boundingRect.points(rotated_rect_points);

            Rect rect = Imgproc.boundingRect(new MatOfPoint(rotated_rect_points));

            // test horizontal ROI orientation
            if (rect.width > rect.height) {
                Imgproc.rectangle(sourceMat, rect.tl(), rect.br(), green, 3);
            }
        }
    }

    roiBitmap = Bitmap.createBitmap(sourceMat.cols(), sourceMat.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(sourceMat, roiBitmap);
    return roiBitmap;
}

from, for example, button click:

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

    if (!OpenCVLoader.initDebug()) {
        Log.d(TAG, "OpenCVLoader.initDebug() - ERROR");
    } else {
        Log.d(TAG, "OpenCVLoader.initDebug() - OK");
    }

    mImageView = (ImageView) findViewById(R.id.source_image_view);
    mProcessButton = (Button) findViewById(R.id.process_button);

    mProcessButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Bitmap bmSource = BitmapFactory.decodeResource(getResources(), R.drawable.test);
            Bitmap bmRoi = findRoi(bmSource);

            mImageView.setImageBitmap(bmRoi);
        }
    });
}

when activity_main.xml is:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.test.opencv.opencvstackoverflow.MainActivity">

    <ImageView
        android:id="@+id/source_image_view"
        android:layout_above="@+id/process_button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        app:srcCompat="@drawable/test"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        />

    <Button
        android:id="@+id/process_button"
        android:text="Find ROI"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentEnd="true"/>

</RelativeLayout>

and you'll got something like that as result:

enter image description here

NB! Maybe You should adjust Scalar lowerb and upperb according to Your condition as described (as You know) by Alexander Reynolds here:

This ROI contains only blue pixels, so I can find the mean blue value, and the standard deviation of the blue values to use as the values for inRange().

mu, sig = cv2.meanStdDev(roi)
a = 9

blue_mask = cv2.inRange(hsv, mu-a*sig, mu+a*sig)

and Micka there.

Also 400 in if (rectangleArea > 400) may needs to be adjusted according minimal area of ROI.

Upvotes: 2

Related Questions