對於OpenCV的開發團隊來講,不斷提高OpenCV庫是很是重要的。咱們不斷考慮那些能夠減輕你工做過程的方法,同時還要保障庫的靈活性。新的C++接口就是咱們爲了這個而開發出來的東西。然而,向後兼容性仍然是很重要的。咱們不想打碎那些你使用更早的OpenCV庫寫下的代碼。所以,咱們爲了保障這個事情從而加上了一些函數。在下面的教程中,你會學習到:ios
一、相比於一樣使用的初版本的OpenCV庫,第二版本中有了什麼變化。算法
二、如何在圖像中添加一些高斯噪點。安全
三、什麼是查找表,爲何要用他們。數據結構
你作出改變的第一步就是學習關於圖像的一些新的數據結構:Mat-The Basic Image Container這裏代替了老舊的CvMat 和ImpImage。使用新的方程看起來更爲容易一些。你只須要記住一下幾件新的事情。app
OpenCV 2 接受改編。再也不將全部的函數都塞進單一庫中。咱們有許多模塊,其中每個都包括數據結構和函數相關的某些任務。經過這個方法,若是你只須要OpenCV的一部分,你就不用調用這個庫。這就意味着你須要引入那些你須要的頭文件。例如:ide
#Include<opencv2/core/core.hpp>函數
#include<opencv3/imgproc/imgproc.hpp>學習
#include<opencv2/highgui/highgui.hpp>ui
全部和OpenCV相關的東西都北方到了cv名字空間(namespace)中從而防止和其餘庫的數據結構和函數發生名字衝突。所以你須要再任何來自於OpenCV庫的東西前面添加cv::關鍵字或者直接添加這一行代碼直接包含全部:spa
using namespace cv;
由於函數已經在命名空間中了,也就不須要在名字前面添加cv前綴。全部的新的可兼容函數不具備這一點,他們遵循駝峯命名法。這就意味名字的第一個字母是小寫字母(除非它自己就是一個名字(人名等)像Canny)接下來的單詞使用大寫字母開頭(像copyMakeBorder)。
如今,要記住你須要將你用的全部模塊鏈接到你的應用程序中。在Windows環境下,你須要將使用了的DLL再次添加進全部的二進制的路徑中。更多深層次的信息,若是你使用Windows,請閱讀 How to build applications with OpenCV inside the Microsoft Visual Studio對於Linux的使用案例,在Using OpenCV with Eclipse(添加CDT)中有所解釋。
如今,爲了轉換Mat 對象,你可使用IplImage或者CvMat操做符。然而在C接口中一般使用的指針,在這裏不復存在了。在C++接口中,咱們更多使用Mat 對象。這種對象能夠不花費任何代價只須要簡單的賦值就能夠轉換爲IplImage和CvMat類型。例如:
Mat I;
IplImager PI=I;
CvMat mI=I;
如今若是你想轉換到指針的,就會有一點麻煩。編譯器再也不自動決定你想要什麼而是你須要明確指定你的目的。也就是調用IplImage和CvMat 操做符而且獲得他們的指針。爲了的到指針,咱們使用&標記:
Mat I;
IplImage *pI=&I,operator IplImage();
CvMat *mI= &I.opeartor CvMat();
C接口的最大的弊端就是讓你本身進行內存管理。你須要知道何時你析構一個再也不用到的內存是安全的而且確保你在程序運行完成後進行,不然你可能就會有內存泄漏的麻煩了。爲了解決OpenCV中的這個問題,這裏引入了一系列的智能指針。當對象再也不使用時,就會被自動析構掉。使用這個被特殊聲明的指針Ptr:
Ptr<IplImage> piI=&I.operator IplImage();
從C的數據結構轉換到Mat 是經過將它們傳入內部的構造函數完成的。例如:
Mat K(piL),L;
L=Mat(pI);
如今你已經基本完成了混合使用C接口和C++接口的例子。你也將會在OpenCV的實例文件夾中找到源代碼。爲了幫助你看到二者的不一樣:一個是C和C++的混合,另一個則是純C++。若是你定義DEMO_MIXED_API_USE你就再也不使用第一個。程序將色彩平面分離,而後在上面作一些改動,最後將它們融合到一塊兒。
#include<stdio.h>
#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
Using namespace cv;
Using namespace std;
#define DEMO_MIXED_API_USE
int main(int argc,char**argv)
{
Const char* imagename=argc>1?argv[1]:」lena.jpg」;
}
#ifdef DEMO_MIXED_API_USE
Ptr<Iplimage> IplI=cvLoadImage(imagename);
If(IplI.empty())
{
Cerr<<」an not load image」<<imagename<<endl;
Return -1;
}
Mat I(IplI);
#else
Mat I=imread(imagename);
If(I.empty())
{
Cerr<<」can not load image」<<imagename<<endl;
Return -1;
}
#endif
在這裏你能看到使用了新的結構,咱們再也不有指針問題,儘管使用了老舊的函數,可是最終仍是將結果轉換爲Mat 對象
Mat I_YUV;
cvtColor(I,I_YUV,COLOR_BGR2YCrCb);
Vector<Mat> planes;
Split(I_YUV,planes);
由於咱們想要將圖像中的亮度成分混合,咱們首先將默認RGB色彩系統轉換爲YUV色域而後將它分離爲不一樣的色彩平面。這裏的程序分離:在第一個示例中使用三個(C語言中的[]操做符,迭代器,讀取獨立元素)主要的圖像遍歷算法中的一個來處理每個平面。第二個變化就是咱們在圖像中加入高斯噪聲而且根據某些方程將它們的通道融合。
MatIterator_<uchar> it=planes[0].begin<uchar>(),it_end=planes[0].end<uchar>();
For(;it!=it_end;++it)
{
Double v=*it*1.7+rand()%21-10;
*it=saturate_case<uchar>(v*v/255);
}
For(int y=0;y<I_YUV.rows;y++)
{
Uchar* Uptr=planes[1].ptr<ujchar>(y);
For(int x=0;x<I_YUV.cols;x++)
{
Uptr[x]=saturate_cast<uchar>((Uptr[x]-128/2)+128);
Uchar&Vxy=planes[2].at<uchar>(y,x);
Vxy=saturate_cast<uchar>((Vxy-128)/2+128);
}
}
在這裏你可以看到咱們經過三種方式(迭代器,C指針以及獨立元素進入方式)來遍歷整個圖像中的像素。你能夠從How to scan images,lookup tables and time measurement with OpenCV教程來得到更多的深層次的描述。很容易轉換老舊的函數名稱。僅僅把cv前綴去掉而後使用新的Mat 數據結構。下面就是經過使用增長權重的函數的使用案例:
Mat noisyI(I.size(),.CV_8U);
Randn(noisyI,Scalar::all(128),Scalar::all(20));
GaussianBlur(noisyI,noisyI,Size(3,3),0.5,0.5);
Const double brightness_gain=0;
Const double contrast_gain=1.7;
#ifdef DEMO_MIXED_API_USE
IplImage cv_planes_0=planes[0],cv_noise=noisyI;
cvAddWeighted(&cv_lanes_0,contrast_gain,&cv_noise,1,-128+brightness_gain,&cv_planes_0);
#else
addWeighted(planes[0],contrast_gain,noisyI,1,-128+brightness_gain,planes[0]);
#endif
Const double color_scale=0.5;
Planes[1].convertTo(planes[1],planes[1].type(),color_scale,128*(1-color_scale));
Planes[2]=Mat_<uchar>(planes[2]*color_scale+128*(1-color_scale));
Planes[0]=planes[0].mul(planes[0],1./255);
你可能看到平面變量的類型是Mat。然而從Mat 轉換到IplImage容易並且使用一個賦值操做就能夠自動完成。
Merge(planes,I_YUV);
cvColor(I_YUV,I,CV_YCrCb2BGR);
namedWindow(「image with grain」,WINDOW_AUTOSIZE);
#ifdef DEMO_MIXED_API_USE
cvShowImage(「image with grain」.IplI);
#else
Imshow(「image with grain」,I);
新的imshow highgui函數接受Mat和IplImage兩種數據結構。編譯和運行程序,若是下面第一幅圖像是你的輸入圖像,你可能的到第二章或者第三章圖像做爲輸出。