OpenCV reshape函数需要注意的细节
OpenCV reshape函數需要注意的細節
【尊重原創,轉載請注明出處】https://blog.csdn.net/guyuealian/article/details/80252853
? ? 本人在使用OpenCV的reshape()函數時,曾經碰到一個大坑,出現一個非常奇葩的問題,先把原始的代碼貼上:
#include <opencv2/opencv.hpp> #include "continuousCapture.h"using namespace cv; using namespace std;template<typename _Tp> cv::Mat convertVector2Mat(vector<_Tp> v, int cn, int rows) {cv::Mat mat = cv::Mat(v);//將vector變成一列的matcv::Mat dest = mat.reshape(cn, rows);cout << "內部dest=\n" << dest << endl;return dest; }int main() {/* char ->CV_8SC* unsigned char,uchar ->CV_8UC* unsigned short int,ushort->CV_16UC* short int->CV_16SC* int ->CV_32SC* float ->CV_32FC* double->CV_64FC*///int arr[4][3] = { { 1, 1,1 },{ 2, 2,2 },{ 3, 3,3 },{ 4,4, 4 } }; uchar arr[12] = { 1, 1,1 ,2, 2,2, 3, 3,3 ,4,4, 4 };vector<uchar> v(arr, arr + 12);//將一維數組轉為vectorcv::Mat dest=convertVector2Mat<uchar>(v,1, 4);//將vector轉為Matcout << "外部dest=\n" << dest << endl;system("pause");waitKey();return 0; }? ? ?上面的程序,聲明一個函數convertVector2Mat()實現將vector轉OpenCV的Mat類型,因此用到了reshape()函數,剛看convertVector2Mat()函數,你是很難發現問題,但運行結果,且出乎意外:
內部dest= [ 1, 1, 1;2, 2, 2;3, 3, 3;4, 4, 4] 外部dest= [221, 221, 221;221, 221, 221;221, 221, 221;221, 221, 221]? ? Why?什么情況,convertVector2Mat()函數里的dest和返回dest的結果為什么不一樣的??為什么在函數計算正確的值,返回結果后卻出現問題了。 這個坑,鄙人弄了好久,一開始以為是類型出現問題,于是統一所有數據的類型為uchar或者int類型;后來,我改為引用的方式獲得dest的值,然而....問題依舊存在!!!
? ?再后來,一條代碼一條代碼的審核,終于定位到reshape()函數,百度搜索的reshape()函數的用法都是坑,沒有一個說清楚,后來還是到OpenCV官網查看最權威的解釋:https://docs.opencv.org/3.2.0/d3/d63/classcv_1_1Mat.html#a4eb96e3251417fa88b78e2abd6cfd7d8
Changes the shape and/or the number of channels of a 2D matrix without copying the data.
The method makes a new matrix header for *this elements. The new matrix may have a different size and/or different number of channels. Any combination is possible if:
- No extra elements are included into the new matrix and no elements are excluded. Consequently, the product rows*cols*channels() must stay the same after the transformation.
- No data is copied. That is, this is an O(1) operation. Consequently, if you change the number of rows, or the operation changes the indices of elements row in some other way, the matrix must be continuous. See?Mat::isContinuous?.
For example, if there is a set of 3D points stored as an STL vector, and you want to represent the points as a 3xN matrix, do the following:
std::vector<Point3f> vec;...Mat pointMat = Mat(vec). // convert vector to Mat, O(1) operation reshape(1). // make Nx3 1-channel matrix out of Nx1 3-channel. // Also, an O(1) operation t(); // finally, transpose the Nx3 matrix. // This involves copying all the elements Parameters| cn | New number of channels. If the parameter is 0, the number of channels remains the same. | 
| rows | New number of rows. If the parameter is 0, the number of rows remains the same. | 
? ? ?看到了吧,(1)由于reshape只是在邏輯上改變矩陣的行列數或者通道數, 但不會進行任何的數據的復制操作,新矩陣中不包含額外元素,也不包含任何元素。 因此,轉換后rows*cols*channels()必須保持不變。(2)沒有數據被復制。 也就是說,這是一個O(1)操作。 因此,如果更改行數,或者操作以其他方式更改元素行的索引,則矩陣必須是連續的。關于OpenCV連續性的使用方法可以參考本人博客:https://blog.csdn.net/guyuealian/article/details/78614662
? ? ?知道這個reshape()的實現機制,鄙人猜測出現這種問題的原因了,應該是convertVector2Mat()函數內部創建的mat和dest變量本質上是同一塊內存空間的,而返回后就已經被釋放掉。dest引用的數據是來自于mat,并沒有拷貝數據,因此在mat沒有釋放的情況下是正常的,但引用的內存就被釋放后就變成野數據。要想解決這個問題也簡單,返回時,clone一份即可。如:
#include <opencv2/opencv.hpp> #include "continuousCapture.h"using namespace cv; using namespace std;template<typename _Tp> cv::Mat convertVector2Mat(vector<_Tp> v, int cn, int rows) {cv::Mat mat = cv::Mat(v);//將vector變成一列的matcv::Mat dest = mat.reshape(cn, rows).clone();//clone一份再返回cout << "內部dest=\n" << dest << endl;return dest; }int main() {/* char ->CV_8SC* unsigned char,uchar ->CV_8UC* unsigned short int,ushort->CV_16UC* short int->CV_16SC* int ->CV_32SC* float ->CV_32FC* double->CV_64FC*///int arr[4][3] = { { 1, 1,1 },{ 2, 2,2 },{ 3, 3,3 },{ 4,4, 4 } }; uchar arr[12] = { 1, 1,1 ,2, 2,2, 3, 3,3 ,4,4, 4 };vector<uchar> v(arr, arr + 12);//將一維數組轉為vectorcv::Mat dest;dest=convertVector2Mat<uchar>(v, 1, 4);//將vector轉為Matcout << "外部dest=\n" << dest << endl;system("pause");waitKey();return 0; }超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生
總結
以上是生活随笔為你收集整理的OpenCV reshape函数需要注意的细节的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: OpenCV实现最大最小距离聚类算法
- 下一篇: OpenCV实现Mat与vector,M
