## OpenCV 學習(圖像的基本運算)
圖像的基本運算有很多種,比如兩幅圖像可以相加、相減、甚至可以相乘、相除。圖像可以放大、縮小、旋轉,還可以截取中間的一副子圖,各個顏色通道還可以分別提取。總之,對于圖像可以進行的基本運算非常的多,這里不可能全部都寫出來,只是挑了些特別常用的簡單的寫寫。
### 圖像間的加減乘除
OpenCV 中提供了如下的一些函數,用來進行圖像的加減乘除。
~~~
void add(InputArray src1, InputArray src2, OutputArray dst,
InputArray mask=noArray(), int dtype=-1);
void subtract(InputArray src1, InputArray src2, OutputArray dst,
InputArray mask=noArray(), int dtype=-1);
void multiply(InputArray src1, InputArray src2,
OutputArray dst, double scale=1, int dtype=-1);
void divide(InputArray src1, InputArray src2, OutputArray dst,
double scale=1, int dtype=-1);
void divide(double scale, InputArray src2,
OutputArray dst, int dtype=-1);
void scaleAdd(InputArray src1, double alpha, InputArray src2, OutputArray dst);
void addWeighted(InputArray src1, double alpha, InputArray src2,
double beta, double gamma, OutputArray dst, int dtype=-1);
~~~
這些函數都要求相加的兩幅圖像具有相同的尺寸,并且像素類型是相同的。
比如我們有兩幅尺寸相同的圖像,分別如下:


執行下面的操作后:
~~~
cv::addWeighted(image, 0.5, image2, 0.5, 0., result);
~~~
得到的輸出圖像如下:

實際上,上面的代碼還可以寫為:
~~~
result= 0.5 * image1 + 0.5 * image2;
~~~
與此類似的還有位運算函數:
~~~
void bitwise_and(InputArray src1, InputArray src2,
OutputArray dst, InputArray mask=noArray());
void bitwise_or(InputArray src1, InputArray src2,
OutputArray dst, InputArray mask=noArray());
void bitwise_xor(InputArray src1, InputArray src2,
OutputArray dst, InputArray mask=noArray());
void bitwise_not(InputArray src, OutputArray dst,
InputArray mask=noArray());
~~~
用法很簡單,就不多介紹了。
另外一個比較常用的運算是求兩幅圖像像素的差的絕對值。
~~~
void absdiff(InputArray src1, InputArray src2, OutputArray dst);
~~~
還有些函數是對單幅圖像進行操作的,比如對每個像素的值取平方、平方根、對數等。
~~~
void sqrt(InputArray src, OutputArray dst);
void pow(InputArray src, double power, OutputArray dst);
void exp(InputArray src, OutputArray dst);
void log(InputArray src, OutputArray dst);
~~~
這里給出的函數很有限。但是,基本上我們能想到的各種操作,OpenCV 的作者都替我們實現了,需要時可以現查。
上面的操作都假定兩幅圖像是相同大小的。當圖像大小不同時,我們可以在較大的圖像中挖取出一塊小區域。
### 取圖像中的子區域(ROI)
下面的代碼在一副圖像中加入個 logo。 logo 圖像如下:

~~~
cv::Mat imageROI;
imageROI= image(cv::Rect(385,270,logo.cols, logo.rows));
// add logo to image
cv::addWeighted(imageROI, 1.0, logo, 0.3,0., imageROI);
~~~

如果我們的 ROI 由圖像中的一些連續行或連續列組成。可以用下面的方式來定義:
~~~
cv::Mat imageROI= image.rowRange(start,end);
cv::Mat imageROI= image.colRange(start,end) ;
~~~
### 分離圖像的通道
有時,我們需要單獨處理圖像的某一個通道,這時可以可以用 split函數來分離圖像的通道。
~~~
void split(const Mat& src, vector<Mat_<_Tp> >& mv);
~~~
這個函數將一副圖像的各個通道,分離成多個矩陣。
~~~
std::vector<cv::Mat> planes;
cv::split(image1, planes);
~~~
對某個通道處理完成后,可以用 merge 函數組合回彩色圖像。
~~~
void merge(const vector<Mat>& mv, OutputArray dst );
~~~