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;
}
运行后深知浅拷贝与深拷贝的区别