OpenCV + Java(Android) 设置ROI

在处理图像时, 我们经常需要提取图片中的重要部分进行分析,滤除不重要的噪声背景。通常的操作是设置感兴趣区域(Region of Interest, ROI),然后分割图片。由于操作对象形状的不同,ROI也会具有不同的形状。从简单的矩形,到稍复杂的圆形、椭圆,以及更为复杂的不规则形状。网上有很多关于C++版本的OpenCV设置ROI的博文,但是Java语言版的颇少,本文就着重介绍一下在Java或者Android环境下如何对图像设置ROI。

1. 矩形ROI设置

矩形的ROI设置比较简单,可以直接利用Mat类的构造函数提取一块矩形区域。代码中MatView.openFile()与MatView.imshow()是我自己写的方法,Java平台上的OpenCV并没有提供显示图片imshow()函数。方法体内容可参考我的另一篇博文:绘制灰度直方图(OpenCV + Java)

Mat imgOrigin = new Mat();
try {
    imgOrigin = MatView.openFile("picture/clock.jpg"); // 读取一张图片
 } catch (Exception e) {
     e.printStackTrace();
}
MatView.imshow(imgOrigin, "Original Image"); // 在JFrame中显示读取的图片

Rect rect = new Rect(30, 120, 340, 350); // 设置矩形ROI的位置
Mat imgRectROI= new Mat(imgOrigin, rect);      // 从原图中截取图片
MatView.imshow(imgRectROI, "Rectangle ROI"); // 显示截取后的图片

原图
矩形ROI

2. 圆形ROI设置

圆形ROI的设置需要用到mask掩膜。首先新建一个大小和原图一样的mask,得到原图感兴趣区域的轮廓并在mask相同的地方画出,这一步可以通过Canny等边缘检测算子实现。然后利用漫水填充法将mask中闭合区域填充为自己设置的颜色(这里我们选择填充为白色)。最后可以通过copyto()方法,结合自己创建的mask将ROI区域提取出来。
漫水填充法floodFill()的详细讲解可以参考博文:【OpenCV入门教程之十五】水漫金山:OpenCV漫水填充算法(Floodfill)。需要注意的是,C++环境中提供了两个版本的floodFill()函数,第一个版本没有mask形参,第二个版本带有mask形参。然而,在Java环境中此方法都要设置mask形参,而且floodFill的mask的width和height都必须比输入图像大至少两个像素,否则程序会报错。floodFill和copyto都有mask,注意区分。由于floodFill必须要有mask形参,所以要创建一个尺寸较大的mask,而我们真正想要的是copyTo()方法的mask。

Mat maskCopyTo = Mat.zeros(imgOrigin.size(), CV_8UC1); // 创建copyTo方法的mask,大小与原图保持一致
Mat maskFill = Mat.zeros(new Size(imgOrigin.cols() + 2, imgOrigin.rows() + 2), CV_8UC1); // 创建floodFill方法的mask,尺寸比原图大一些
Imgproc.circle(maskCopyTo, new Point(207, 290), 165, Scalar.all(255), 2, 8, 0); // 画出圆的轮廓
Imgproc.floodFill(maskCopyTo, maskFloodFill, new Point(207, 290), Scalar.all(255), null, Scalar.all(20), Scalar.all(20), 4 ); // 漫水填充法填充圆的内部
MatView.imshow(maskFloodFill,  "Mask of floodFill"); // 画出copyTo方法的mask
MatView.imshow(maskCopyTo,  "Mask of copyTo");   // 画出floodFill方法的mask
Mat imgCircularROI = new Mat();
imgOrigin.copyTo(imgCircularROI, maskCopyTo); // 提取圆形的ROI
MatView.imshow(imgCircularROI,  "Circular ROI"); // 显示圆形的ROI

mask的逻辑是:mask某个位置为0,此位置上的操作不起作用;某个位置如果不为0,在此位置上的操作起作用。
在创建maskCopyTo与maskFloodFill 两个掩膜时,最好要初始化为0,不能简单的new Mat()。new出的mask可能会包涵非零像素点,这些像素点在提取ROI时会起作用,从而导致存在一些噪声。
这里写图片描述
这里写图片描述
这里写图片描述

3. 不规则形状ROI设置

不规则形状的ROI设置基本思想与圆形ROI一致。首先需要得到一张轮廓掩膜图(Canny或者findCounters等方法),然后通过漫水填充等方法生成mask,最后利用copyTo方法提取。

Mat maskCopyTo2 = Mat.zeros(imgOrigin.size(), CV_8UC1); // 创建copyTo方法的mask,大小与原图保持一致
List<MatOfPoint> counter = new ArrayList<>();
counter.add(new MatOfPoint(new Point(20, 230), new Point(200, 70) , new Point(380, 230), new Point(300, 460), new Point(90, 460), new Point(20, 230))); // 绘制一个不规则的多边形
Imgproc.drawContours(maskCopyTo2, counter, -1, Scalar.all(255)); // 画出轮廓
MatView.imshow(maskCopyTo2,  "Irregular shape edge");
Mat maskFloodFill2 = new Mat(imgOrigin.rows() + 2, imgOrigin.cols() + 2, CV_8UC1); // 创建floodFill方法的mask,尺寸比原图大一些
Imgproc.floodFill(maskCopyTo2, maskFloodFill2, new Point(207, 290), Scalar.all(255), null, Scalar.all(20), Scalar.all(20), 4 ); // 漫水填充法填充内部
MatView.imshow(maskFloodFill2,  "Irregular shape:Mask of floodFill"); // 画出copyTo方法的mask
MatView.imshow(maskCopyTo2,  "Irregular shape:Mask of copyTo");   // 画出floodFill方法的mask
Mat imgIrregularROI = new Mat();
imgOrigin.copyTo(imgIrregularROI, maskCopyTo2); // 提取不规则形状的ROI
MatView.imshow(imgIrregularROI,  "Irregular shape ROI");

这里写图片描述

附上代码的下载地址:http://download.csdn.net/detail/mengchicmc/9888844

猜你喜欢

转载自blog.csdn.net/MengchiCMC/article/details/74352122