【问题标题】:OpenCV Java, Getting region of interest from imageOpenCV Java,从图像中获取感兴趣区域
【发布时间】:2018-01-15 14:50:28
【问题描述】:

我正在尝试检测图像中的某个区域(矩形),并获取其上限和下限,但我停留在我必须获得感兴趣区域的点。

从这张图片开始:

我想像这样获得感兴趣的区域:

我转换了 Alexander Reynolds here 回答的 python 代码, 但由于出现错误,我似乎无法查看结果:

java.lang.IllegalArgumentException: bmp == null

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);
    }

【问题讨论】:

  • 什么是 tmp?你确定是valid Bitmap object of the same size as the Mat and of type 'ARGB_8888' or 'RGB_565'.
  • @arqam,很抱歉,我不确定如何检查和/或将位图/垫子转换为相同的大小和类型,我会去查一下
  • 问题出在哪里?
  • 我检查了,似乎我的构造函数可能是我目前正在修复它的问题

标签: java android opencv


【解决方案1】:

你可以试试调用这个方法:

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;
}

来自,例如,按钮点击:

@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);
        }
    });
}

activity_main.xml 是:

<?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>

你会得到类似的结果:

注意!也许您应该根据Alexander Reynolds here 描述的(如您所知)您的情况调整Scalar lowerbupperb

这个 ROI 只包含蓝色像素,所以我可以找到平均蓝色值, 和蓝色值的标准偏差用作值 范围内()。

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

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

Mickathere

另外,if (rectangleArea &gt; 400) 中的400 可能需要根据 ROI 的最小区域进行调整。

【讨论】:

  • 嘿@Andrii Omelchenko,感谢您的回答,它有效,我可以知道您是如何找到蓝色的lowerb 和upperb 的吗? Scalar lowerb = new Scalar(85, 50, 40);Scalar upperb = new Scalar(135, 255, 255); 以防我碰巧改变了底座的颜色。我需要打开另一个问题才能得到答案吗?
  • 我不确定我必须在Scalar 中调整什么值才能使其适合我需要的颜色。
  • 我从here 得到的。您应该调整第一个值(第一个 - 色调 == 颜色,第二个 - 饱和度,第三个 - 值 == 亮度)注意! Hue for OpenCV 8-bit images is Hue/2,所以 85 作为第一个参数意味着 HSV 模型中的 85x2 = 170 色调。如果您将第一个参数设置为小于 85,您将在 ROI 中获得“更多绿色”像素,如果您将其设置为大于 135,您将在 ROI 中获得“更多红色”像素。另请查看this 链接。
  • 内容非常丰富,非常感谢您的帮助
  • @AndriiOmelchenko 你可以在这里帮助我:stackoverflow.com/questions/68685304/…
猜你喜欢
  • 2021-10-11
  • 2018-06-17
  • 2013-03-03
  • 1970-01-01
  • 2017-09-28
  • 2017-06-05
  • 2016-04-25
  • 2012-04-25
  • 1970-01-01
相关资源
最近更新 更多