OpenCV2.4.13中同一函式不同形參的理解,vector,list區別,findContours理解
阿新 • • 發佈:2019-01-05
OpenCV手冊中的函式通常有不止一個定義,其中的形參可以有各種不同的形式,這裡以 split 和 merge 兩個函式舉例進行解釋。
每個函式都有兩個版本,一個版本利用陣列作為形參,一個版本利用 vector 作為形參。
以split 為例,解釋一下兩個版本中形參的含義
void split(const Mat& src, Mat* mvbegin)
- 第一個形參:const 表示 src 不能修改;Mat& 表示使用 引用傳遞
- 第二個形參:分割之後的影象用一個Mat陣列來存放,因此,對應的形參是 Mat*
void split(InputArray m, OutputArrayOfArrays mv)
- 第一個形參:InputArray 表示輸入是“陣列”
- 第二個形參:OutputArrayOfArrays 表示輸出是 “陣列的陣列”
下面給出測試程式碼:
int m = 300;
Mat img = 255*Mat::eye(m,m,CV_8UC3);
// 利用陣列作為形參
Mat mv[3];
split(img,mv);
for (int i = 0; i < 3; i++)
imshow("array channel " + to_string(i),mv[i]);
Mat mergeimg;
merge(mv,3 ,mergeimg);
imshow("merge image",mergeimg);
// 利用 vector 作為形參
vector<Mat> mv2;
split(img,mv2);
for (int i = 0; i < 3; i++)
imshow("vector channel " + to_string(i),mv2.at(i));
merge(mv2,mergeimg);
問題:為什麼 可以用 vector 代替 陣列呢?
這裡的 vector 和 list 看起來長得很像,它們之間有什麼關係呢?
名稱 | vector | list |
---|---|---|
實現方式 | 與陣列類似 | 利用連結串列實現 |
儲存空間 | 連續 | 不連續 |
隨機儲存時間複雜度 | O(1) | O(n) |
插入與刪除時間複雜度 | O(n) | O(1) |
問題:那麼如何使用 vector 與 list 呢?如何遍歷它們呢?
下面借用這裡的程式碼展示如何使用 vector 與 list
vector<int> v; // 這裡 vector 中存放的元素都為 int 型
list<int> l;
for(int i=0;i<8;i++) ////往v和l中分別新增元素
{
v.push_back(i);
l.push_back(i*i);
}
// 遍歷 vector 有兩種方法,一種是與陣列一樣
cout <<"v is: "<<endl;
for (int i = 0; i<v.size(); i++ )
cout << v[i] << " ";
cout <<endl;
// 第二種是使用迭代器
// 定義迭代器,分別遍歷 vector
vector<int>::iterator itv;
cout <<"v is: "<<endl;
for (itv = v.begin(); itv != v.end(); itv++ )
cout << *itv << " ";
cout <<endl;
// 遍歷 list 只能使用迭代器 進行遍歷
//cout << l[0]; 編譯錯誤,list 沒有過載 []
list<int>::iterator itl;
cout <<"l is: "<<endl;
for (itl = l.begin(); itl != l.end(); itl++ )
cout << *itl << " ";
cout <<endl;
問題:說了這麼多有什麼用呢?為甚麼會寫這篇部落格呢?
- 因為樓主在使用 OpenCV 找影象的邊界的時候遇到了一句這樣的程式碼
vector<vector<Point>> contours;
我的天啊,這是一個什麼鬼?
經過逐步搜尋,才找到了答案,也就是上面描述的這些東東。
那如何找邊界呢?
貼出程式碼如下:
// 將第一層的左上部分變成非零
for (int i = 0; i < img.rows/2; i++)
for (int j = 0; j < img.cols/2; j++)
mv[0].at<uchar>(i,j) = 255;
imshow("mv[0]",mv[0]);
// 效果如下:
// 找影象的邊界
// 有好多個邊界(對應最外面的vector),
//每一個邊界是一系列點的集合(對應裡面的vector<Point>)
vector<vector<Point>> contours;
findContours(mv[0],contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
Scalar color = Scalar(0,0,255);
drawContours(img,contours,-1,color);
imshow("img with contours",img);
// 效果如下:
整體程式碼如下:
// csdn_code.cpp : 定義控制檯應用程式的入口點。
//
#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
int m = 300;
Mat img = 255*Mat::eye(m,m,CV_8UC3);
// 利用陣列作為形參
Mat mv[3];
split(img,mv);
for (int i = 0; i < 3; i++)
imshow("array channel " + to_string(i),mv[i]);
Mat mergeimg;
merge(mv,3,mergeimg);
imshow("merge image",mergeimg);
// 利用 vector 作為形參
vector<Mat> mv2;
split(img,mv2);
for (int i = 0; i < 3; i++)
imshow("vector channel " + to_string(i),mv2.at(i));
merge(mv2,mergeimg);
vector<int> v; // 這裡 vector 中存放的元素都為 int 型
list<int> l;
for(int i=0;i<8;i++) ////往v和l中分別新增元素
{
v.push_back(i);
l.push_back(i*i);
}
// 遍歷 vector 有兩種方法,一種是與陣列一樣
cout <<"v is: "<<endl;
for (int i = 0; i<v.size(); i++ )
cout << v[i] << " ";
cout <<endl;
// 第二種是使用迭代器
// 定義迭代器,分別遍歷 vector
vector<int>::iterator itv;
cout <<"v is: "<<endl;
for (itv = v.begin(); itv != v.end(); itv++ )
cout << *itv << " ";
cout <<endl;
// 遍歷 list 只能使用迭代器 進行遍歷
//cout << l[0]; 編譯錯誤,list 沒有過載 []
list<int>::iterator itl;
cout <<"l is: "<<endl;
for (itl = l.begin(); itl != l.end(); itl++ )
cout << *itl << " ";
cout <<endl;
// 將第一層的左上部分變成非零
for (int i = 0; i < img.rows/2; i++)
for (int j = 0; j < img.cols/2; j++)
mv[0].at<uchar>(i,j) = 255;
imshow("mv[0]",mv[0]);
// 效果如下:
// 找影象的邊界
vector<vector<Point>> contours; findContours(mv[0],contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
Scalar color = Scalar(0,0,255);
drawContours(img,contours,-1,color);
imshow("img with contours",img);
// 效果如下:
waitKey();
system("pause");
return 0;
}