OpenCV中影象的淺拷貝與深拷貝 = copy clone區別
下面介紹三種OpenCV複製影象的方法:
方法1、過載運算子=
使用過載運算子“=”進行的拷貝是一種淺拷貝,雖然它們有不同的矩陣頭,但是二者共享相同的記憶體空間,二者內容相互關聯,任何一個變數變化的同時另一個變數也隨之改變。
/*OpenCV v1版本*/
IplImage img_origin = cvLoadImage(".\\picture.jpg", CV_LOAD_IMAGE_COLOR); // 讀取一張彩色圖
IplImage img_copy = img_origin; // 直接賦值,淺拷貝
/*OpenCV v2之後版本*/
Mat img_origin = imread(picture , IMREAD_COLOR); // 讀取一張彩色圖
Mat img_copy = img_origin;
方法2、cvCopy
cvCopy的原型是:
void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask CV_DEFAULT(NULL) );
OpenCV官網關於cvCopy函式的介紹
在使用這個函式之前,必須先用cvCreateImage()一類的函式開闢一段記憶體,然後傳遞給dst。cvCopy會把src中的資料複製到dst的記憶體中。這是一種深拷貝,真正地拷貝了一個新的影象矩陣,此時二者相互之間沒有影響,但是如果設定了ROI、COI,copy只會複製ROI、COI區域的內容。
/*OpenCV v1版本*/
IplImage img_origin = cvLoadImage(".\\picture.jpg", CV_LOAD_IMAGE_COLOR); // 讀取一張彩色圖
IplImage img_copy = cvCreateImage(Size(img_origin->width, img_origin ->height), img_origin ->depth, img_origin ->nChannels);
// 開闢一個新的記憶體空間,影象的大小、深度與顏色通道與原圖保持一致
cvCopy(img_origin, img_copy); // 拷貝影象
/*OpenCV v2之後版本*/
Mat img_origin = imread(picture, IMREAD_COLOR); // 讀取一張彩色圖
Mat img_copy;
img_origin.copyTo(img_copy); //在拷貝資料前會有一步img_copy.create(this->size , this->type)
方法3、cvCloneImage
cvCloneImage的原型是:
IplImage* cvCloneImage( const IplImage* image );
OpenCV官網關於cvCloneImage函式的介紹
在使用函式之前,不用開闢記憶體。該函式會自己開一段記憶體,然後複製好影象裡面的資料,然後返回這段記憶體中的資料。clone是把所有的都複製過來,不論你是否設定了ROI、COI等影響,clone都會原封不動的克隆過來。用clone複製後,如果源影象在記憶體中消失,複製的影象也變了,而用copy複製,源影象消失後,複製的影象不變。
IplImage img_origin = cvLoadImage(<span class="hljs-string">".\\picture.jpg"</span>, CV_LOAD_IMAGE_COLOR); <span class="hljs-comment">// 讀取一張彩色圖 </span>
IplImage img_copy = cvCloneImage(img_origin);
這裡先學習OpenCV中的一個函式
void flip(InputArray src, OutputArray dst, int flipCode)
//影象變換函式,第三個引數為1時,表示水平反轉,0表示垂直反轉,負數表示既有水平又有垂直反轉。
為介紹OpenCV中的淺拷貝,我們還是從cv::Mat說起吧。cv::Mat類是用於儲存影象以及其他矩陣資料的資料結構。當cv::Mat例項化後,分配記憶體;當物件離開作用域後,分配的記憶體自動釋放。cv::Mat實現了引用計數以及淺拷貝。引用計數的作用是隻有當所有引用記憶體資料的物件都被析構後,記憶體才會釋放。淺拷貝是指當影象之間進行賦值時,影象資料並未發生複製,而是兩個物件都指向同一塊記憶體塊。
通過OpenCV中的flip函式驗證淺拷貝,具體做法:
先宣告一個Mat物件img載入本地圖片,並顯示;
然後宣告一個Mat物件img1,將img淺拷貝到img1;
在img1上垂直翻轉圖片,注意是在原地進行操作,不建立新的影象;
顯示img,注意視窗名稱應與之前不相同,觀察img的影象內容是否改變。
程式如下:
#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img1=imread("test.jpg"); //將任意一張名為test.jpg的圖片放置於工程資料夾test中
Mat img2=img1; //拷貝方式為淺拷貝
imshow("First",img1);
if(!img1.data)
{
cout<<"error! The image is not built!"<<endl;
return -1;
}
flip(img2,img2,1); //注意應在原地進行映象變換
imshow("Second",img1);
waitKey();
return 0;
}
執行如下,很顯然,我們修改img1的內容img發生了改變。
深拷貝是指新建立的影象擁有原始影象的嶄新拷貝,即拷貝影象和原始影象在記憶體中存放在不同地方。OpenCV中可以通過下面兩種方式實現深拷貝。
1) img.copyTo(img1)
2) img1=img.clone()
通過OpenCV中的flip函式驗證深拷貝,具體做法與之前相似,將img深拷貝到img1即可。
程式如下:
#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat img1=imread("test.jpg"); //將任意一張名為test.jpg的圖片放置於工程資料夾test中
Mat img2=img1.clone(); //拷貝方式是深拷貝
imshow("First",img1);
if(!img1.data)
{
cout<<"error! The image is not built!"<<endl;
return -1;
}
flip(img2,img2,1);
imshow("Second",img1);
waitKey();
return 0;
}
執行如下,深拷貝之後,任他img1七十二變,img自然不變。
瞭解了影象的深淺拷貝,我們使用時就要注意,尤其涉及到類時,我們應該避免返回類中的影象成員。