openCV任意几何形状感兴趣区域(ROI)提取

图像感兴趣区域(ROI)提取主要使用掩模来进行。掩模是二值图像,感兴趣区域的掩模值设置为255,非感兴趣区域的掩模值为0
获取掩模的方法主要有两种

方法一 使用opencv中Mat函数方法,调用Mat(Rect).setTo方法设置掩模

 Mat Mat::operator()( const Rect& roi ) const
 //调用Mat(Rect).setTo方法
 mask(rect).setTo(255);

方法二 在全为0的原始掩模中画一个封闭区域,使用漫水填充算法填充封闭区域,将封闭区域的值都设置为255,实现掩模的提取

方法三 将边界转换为轮廓,使用cv::drawContours(mask, contours, -1, cv::Scalar::all(255),CV_FILLED);
函数提取感兴趣区域(ROI)。
下文对矩形、椭圆,有方向的矩形,轮廓进行提取

1.矩形感兴趣区域提取

1.1 调用Mat(Rect).setTo方法设置掩模

使用方法一对矩形感兴趣区域进行提取示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
//方法1,假如区域为长方形,使用MAT 构造函数设置区域内的值为255
int main()
{
	Mat image=imread("lena.jpg");
	//初始化掩模矩阵
	Mat mask = Mat::zeros(image.size(), CV_8UC1);
	
	Rect rect;
	rect.x = 100;
	rect.y = 100;
	rect.width = 100;
	rect.height = 100;	
	//设置矩形掩模
	mask(rect).setTo(255);

	Mat img2;
	image.copyTo(img2, mask);
	imshow("mask", mask);
	imshow("img2", img2);
	waitKey();
	return 0;
}

1.2 使用漫水填充算法获取矩形ROI

思路:
1)新建一个值全为零的掩模图像(全是黑的,值为0)
2)在掩模图像上用白色画出矩形的边界(边界值为255)
3)选取矩形的中心作为种子点,使用漫水填充算法将矩形的内部填充为白色(255),最后得到掩模图像,使用掩模实现感兴趣区域提取。

#include<cv.h>
#include<highgui.h>
using namespace cv;
int main()
{
	Mat image = imread("lena.jpg");
	Mat mask = Mat::zeros(image.size(), CV_8UC1);
	Rect rect;
	rect.x = 100;
	rect.y = 100;
	rect.width = 100;
	rect.height = 100;
	//画矩形
	rectangle(mask, rect, Scalar(255));
	//设置种子点位置
	Point seed;
	seed.x = 150;
	seed.y = 150;
	//pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
	//使用漫水填充算法填充
	floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);
	//mask(rect).setTo(255);
	Mat img2;
	image.copyTo(img2, mask);
	imshow("mask", mask);
	imshow("img2", img2);
	waitKey();
	return 0;
}

2.任意几何形状ROI提取

任意几何形状感兴趣区域的提取主要使用方法二和方法三。提取的关键是画出几何形状的边界或获得轮廓。

2.1 旋转的矩形(CvBox2D)、椭圆(RotatedRect)、圆的感兴趣区域的提取

示例代码如下:

#include<cv.h>
#include<highgui.h>
using namespace cv;
#define WIDTH 256
#define HEIGHT 256
void DrawBox(CvBox2D box, IplImage* img)
{
	CvPoint2D32f point[4];
	int i;
	for (i = 0; i<4; i++)

	{
		point[i].x = 0;
		point[i].y = 0;

	}
	cvBoxPoints(box, point); //计算二维盒子顶点
	CvPoint pt[4];
	for (i = 0; i<4; i++)
	{
		pt[i].x = (int)point[i].x;
		pt[i].y = (int)point[i].y;

	}
	
	cvLine(img, pt[0], pt[1], cvScalar(255), 2, 8, 0);
	cvLine(img, pt[1], pt[2], cvScalar(255), 2, 8, 0);
	cvLine(img, pt[2], pt[3], cvScalar(255), 2, 8, 0);
	cvLine(img, pt[3], pt[0], cvScalar(255), 2, 8, 0);

}

//方法3.在掩模图像中画旋转的矩形(CvBox2D)、椭圆(RotatedRect)、圆,使用漫水填充算法将几何图形内部的值设置为255
int main()
{
	Mat image = imread("dot_link_11.jpg");

	Mat mask = Mat::zeros(image.size(), CV_8UC1);
	CvBox2D box;
	box.size.width = 100;
	box.size.height = 50;
	box.angle = 30;
	box.center.x = 200;
	box.center.y = 200;
	
	情况1.画旋转的矩形(CvBox2D)
	//opencv 2.4.9
	//IplImage* imask = &IplImage(mask);
	//opencv 3.0
	//IplImage* imask = new IplImage(mask);
	//DrawBox(box,imask);
	//Point seed;
	//seed.x = box.center.x;
	//seed.y = box.center.y;

	//情况2.画椭圆
	//RotatedRect roRect;
	//roRect.angle = 30;
	//roRect.center.x = 200;
	//roRect.center.y = 200;
	//roRect.size.width = 100;
	//roRect.size.height = 50;
	//ellipse(mask, roRect, cvScalar(255));
	//Point seed;
	//seed.x = roRect.center.x;
	//seed.y = roRect.center.y;
	
	情况3.画圆
	Point center;
	center.x = 100;
	center.y = 100;
	float radius = 50;
	circle(mask, center, radius, Scalar(255));

	Point seed;
	seed.x = center.x;
	seed.y = center.y;
	//漫水填充
	//pi的值表示为 v(pi),if  v(seed)-loDiff<v(pi)<v(seed)+upDiff,将pi的值设置为newVal
	floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);
	//mask(rect).setTo(255);
	Mat maskImage;
	image.copyTo(maskImage, mask);
	imshow("mask", mask);
	imshow("img2", maskImage);
	waitKey();
	return 0;
}

2.2 感兴趣区域为轮廓的提取

(1)漫水填充算法思路:
1)调用opencv的画图函数cvLine将轮廓中相邻的点连接为区域
2)获取轮廓中心,使用漫水填充算法填充
示例代码如下:

void draw_external_contour_gray(CvSeq *seq, Mat grayImage)
{
    if (seq->total < 2)
    {
        return;
    }
    Point* prePoint = (Point*)cvGetSeqElem(seq, 0);
    Point* lastPoint = (Point*)cvGetSeqElem(seq, seq->total - 1);
    cv::line(grayImage, *prePoint, *lastPoint,cvScalar(255), 1, 8, 0);
    for (int i = 1; i<seq->total; i++) {
        Point* p=(Point*)cvGetSeqElem(seq,i);
        cv::line(grayImage, *prePoint, *p, cvScalar(255), 1, 8, 0);
        *prePoint = *p;
    }
}
//方法4,假如区域边界为轮廓,使用掩模图像中画轮廓,使用漫水填充算法将几何图形内部的值设置为255
int main()
{
    Mat image=imread("lena.jpg");
    if(image.empty())
    {
        cout<<"image is empty"<<endl;
        return 0;
    }

    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    CvMemStorage* storage = cvCreateMemStorage(0);
//	CvSeq* contour = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);

    CvSeqWriter writer;
    cvStartWriteSeq(CV_32SC2, sizeof(CvSeq), sizeof(CvPoint),storage,&writer);

    CvPoint p1 = { 25, 60 };  CvPoint p2 = { 50, 110 };  CvPoint p4 = { 100, 60 }; CvPoint p3 = { 100, 110 }; CvPoint p5 = { 50, 10 };
    CV_WRITE_SEQ_ELEM(p1, writer);
    CV_WRITE_SEQ_ELEM(p2, writer);
    CV_WRITE_SEQ_ELEM(p3, writer);
    CV_WRITE_SEQ_ELEM(p4, writer);
    CV_WRITE_SEQ_ELEM(p5, writer);

    cvFlushSeqWriter(&writer);
    CvSeq* contour = cvEndWriteSeq(&writer);
    printf("contour.size=%d", contour->total);
    draw_external_contour_gray(contour, mask);
    Point seed;
    seed.x = 35;
    seed.y = 60;
    //漫水填充
    floodFill(mask, seed, 255, NULL, cvScalarAll(0), cvScalarAll(0), CV_FLOODFILL_FIXED_RANGE);

    Mat maskImage;
    image.copyTo(maskImage, mask);
    imshow("mask", maskImage);
    waitKey();
    return 0;
}

(2)将边界转换为轮廓,使用cv::drawContours(mask, contours, -1, cv::Scalar::all(255),CV_FILLED);
函数提取感兴趣区域(ROI)

代码如下:

#include <opencv2/core/core.hpp>
#include<opencv2/opencv.hpp>
#include<iostream>
#include <string>
using namespace cv;
using namespace std;
int main()
{
    Mat image=imread("lena.jpg");
    if(image.empty())
    {
        cout<<"image is empty"<<endl;
        return 0;
    }
    Mat mask = Mat::zeros(image.size(), CV_8UC1);
    Point p1 = { 25, 60 };  Point p2 = { 50, 110 };  Point p4 = { 100, 60 }; Point p3 = { 100, 110 }; Point p5 = { 50, 10 };
    vector<Point> contour;
    contour.push_back(p1);
    contour.push_back(p2);
    contour.push_back(p3);
    contour.push_back(p4);
    contour.push_back(p5);
    vector<vector<Point> > contours;
    contours.push_back(contour);
    cv::drawContours(mask, contours, -1, cv::Scalar::all(255),CV_FILLED);
    imshow("maskRegion",mask);
    waitKey();
    Mat maskImage;
    image.copyTo(maskImage, mask);
    imshow("getMaskImage", maskImage);
    waitKey();
    return 0;
}

注意:drawContours方法也是通用的提取感兴趣区域的方法

  • 32
    点赞
  • 290
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值