2

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);
    }
Tix
  • 449
  • 1
  • 8
  • 27
  • What is tmp? Are you sure its `valid Bitmap object of the same size as the Mat and of type 'ARGB_8888' or 'RGB_565'.` – arqam Aug 08 '17 at 07:59
  • 1
    @arqam , I'm sorry im not sure how to check and or convert the bitmaps / mats to the same size and type I'll go look it up – Tix Aug 08 '17 at 08:04
  • That was the problem? – arqam Aug 08 '17 at 08:59
  • 1
    I checked, and it seems like my constructor may be the issue im currently fixing it – Tix Aug 08 '17 at 09:04

1 Answers1

2

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.

Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79
  • Hey @Andrii Omelchenko, Thanks for the answer, it works, may I know how you found the lowerb and upperb for the blue color? `Scalar lowerb = new Scalar(85, 50, 40);` and `Scalar upperb = new Scalar(135, 255, 255);` In case i happen to change the color of the base. Do i need to open another question to get an answer on this? – Tix Aug 09 '17 at 07:25
  • I'm not sure what value exactly i have to adjust in `Scalar` to get it to fit the color i need. – Tix Aug 09 '17 at 07:45
  • I got it from [here](https://stackoverflow.com/q/34200353/6950238). You should adjust 1st value (1st - Hue==Color, 2nd - Saturation, 3rd - Value == Brightness) NB! [Hue for OpenCV 8-bit images is Hue/2](http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor), so 85 as 1st param means 85x2 = 170 hue in HSV model. If You set 1st param less then 85 You'll got "more green" pixels in ROI, and if You set it grate than 135 You'll got "more red" pixels in ROI. Also take a look at [this](http://colorizer.org/) link. – Andrii Omelchenko Aug 09 '17 at 07:59
  • That is very very informative, thank you very much for the help – Tix Aug 09 '17 at 11:59
  • @AndriiOmelchenko u can help me pls here: https://stackoverflow.com/questions/68685304/opencv-java-how-to-get-a-region-of-interest-from-a-document-image – Tecnologia da Net Aug 06 '21 at 18:21