opencv#23 ROI区域截取

1.图像截取

Range()

cv::Range::Range(int_start,
                 int_end
                )

·start:区间的起始

·end:区间的结束

Rect(_Tp_x,_Tp_y,Tp_width,_Tp_height)

·_Tp:数据类型,C++模板特性,可以用int,double,float等替换。

·_x:矩形区域左上角第一个像素的x坐标,也就是第一个像素的列数。

·_y:矩形区域左上角第一个像素的y坐标,也就是第一个像素的行数。

·_width:矩形的宽,单位为像素,即矩形区域跨越的列数。

·_height:矩形的高,单位为像素,即矩形区域跨越的行数。

2.图像的深拷贝与浅拷贝

我们先来回顾一下图像中Mat类型是如何存储数据的,Mat是由矩阵头和数据组成,当存入信息后,占据内存中主要部分是数据,为了节省内存,若定义了两个Mat类,Mat1和Mat2,它俩引用的是同一个数据,最好的方式就是告诉Mat1和Mat2,引用的是同一个图像,这样就节省了一个图像的存储空间,但是会造成一个问题,如果将Mat1进行删除,它可能会连带着图像一起删除了,这时再通过Mat2访问图像时,就访问不到数据,造成数据丢失,这里在Mat矩阵头中定义了一个引用次数,也就是我可以知道图像是被引用了几次,如果引用次数是2,删除Mat1造成的结果就是将2变为1,并不会删除矩阵中的数据,从而避免上述问题。

还有一种问题,就是两个矩阵头共用一个数据时,当我通过Mat1访问数据,对它进行修改,比如增加了一部分, 那么我再通过Mat2访问的是同样的数据,那么它就会对图像进行改变,访问的数据就不是原先的图像,但我只希望对Mat1中的数据改变,Mat2数据不变,就涉及到如何存放Mat1和Mat2,当然可以把这张图片,分别存储Mat1和Mat2,使数据分离开,那么这样会造成程序比较复杂,而且如果我在程序中只使用图像的某个区域,是没有办法通过这种形式创建新的这样的数据,这里就设计深拷贝和浅拷贝。

我通过Mat1得到Mat2,只是复制了矩阵头,而没有复制数据,没有在内存中重新创建数据,那么深拷贝就是Mat3是由Mat2得到的,但是Mat3的矩阵头不指向Mat2,而是将这个数据重新再内存中进行创建,是由Mat3指向新创建的这样的一个数据。深拷贝的好处是可以避免由其它矩阵头对数据的改变,缺点是会创建很多数据,占用内存。

浅拷贝可以直接通过等式的形式给出,比如有一个Mat2,我想全拷贝成Mat3,可以直接Mat3 = Mat2就可以了。前面的图像截取就属于浅拷贝。

opencv中提供了两种进行深拷贝的方式,都是copyTo的形式,函数名相同,但是两者存在的类名不同,一个是存在Mat类中,一个是存在cv命名空间中,存在cv的命名空间中是一个独立的函数,我们可以直接调用这个函数,但是存在Mat类的函数,就需要你现有Mat类的变量,之后才能进行copy to的拷贝。

深拷贝函数

copyTo()

void cv::copy To(InputArray     src,
                 OutputArray    dst,
                 InputArray     mask
                )

·src:待拷贝图像。

·dst:深拷贝后的图像。

· mask:深拷贝时的掩码矩阵。

copyTo()

void cv::Mat::copyTo(OutputArray     m,
                     InputArray      mask,
                    )                const

这种形式是调用Mat里面的copyTo,由于已经指定copy的对象,所以只有两个输入参数。 

·m:深拷贝后的图像。

·mask:深拷贝时的掩码矩阵。

示例

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv; //opencv的命名空间
using namespace std;

int main()
{
	Mat img = imread("E:/opencv/opencv-4.6.0-vc14_vc15/opencv/lenac.png");
	Mat ani = imread("E:/opencv/opencv-4.6.0-vc14_vc15/opencv/ani.jpeg");
	
	if (img.empty() || ani.empty())
	{
		cout << "请确认图像文件名是否正确" << endl;
		return -1;
	}
	Mat ROI1, ROI2 ,ROI2_copy, mask, img2, img_copy;
	resize(ani, mask, Size(200, 200)); //提前将图片尺寸修改
	img2 = img; //浅拷贝,img图像改变后,img2也会改变

	//深拷贝的两种方式
	img.copyTo(img_copy); //因为进行了深拷贝,修改img后,img_copy是不会变的

	//两种在图中截取ROI区域的方式
	Rect rect(206, 206, 200, 200);//定义ROI区域
	ROI1 = img(rect); //截图

	ROI2 = img(Range(300, 500), Range(300, 500)); //第二种截图方式

	img(Range(300, 500), Range(300,500)). copyTo(ROI2_copy); //对ROI2进行深拷贝

	mask.copyTo(ROI1); //在图像中加入部分图像,ROI1是浅拷贝img的,因此img也会改变,img改版后,ROI2也会改变(是在ROI2截取有重叠的情况下),同时浅拷贝的img2也会改变,这里面不会改变的是进行深拷贝的量。

	imshow("加入ani后图像", img);
	imshow("深拷贝的img_copy", img_copy);
	
	imshow("ROI对ROI2的影响", ROI2);
	imshow("深拷贝的ROI2_copy", ROI2_copy);

	circle(img, Point(300, 300), 20, Scalar(0, 0, 255), -1);

	imshow("浅拷贝的iimg2", img2);

	imshow("画圆对ROI1的影响", ROI1);


	waitKey(0);
	return 0;

}

运行后深知浅拷贝与深拷贝的区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值