學習OpenCV範例(五)——改變影象的對比度和亮度
學習到範例五的時候,發覺雖然範例都很簡單,但是做記錄的時候,並且把程式裡面使用過的類或方法都弄明白,也就不簡單了,接下來介紹一下範例五吧。
1、影象處理
一般來說,影象處理運算元是帶有一幅或多幅輸入影象、產生一幅輸出影象的函式。
影象變換可分為以下兩種:
點運算元(畫素變換):影象對比度和亮度,等等
鄰域(基於區域的)運算元:均值濾波,中值濾波,等等,也就是卷積運算
2、亮度和對比度調整
兩種常用的點過程(即點運算元),是用常數對點進行 乘法 和 加法 運算:
兩個引數 和 一般稱作 增益 和 偏置 引數。我們往往用這兩個引數來分別控制 對比度 和 亮度 。
你可以把 看成源影象畫素,把 看成輸出影象畫素。這樣一來,上面的式子就能寫得更清楚些:
其中, 和 表示畫素位於 第i行 和 第j列 。
3、執行程式碼如下:
程式使用三種方式來實現亮度和對比度的調整,並且輸出了各自運算的時間。
#include "stdafx.h" #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> using namespace std; using namespace cv; double alpha; /**< 控制對比度 */ int beta; /**< 控制亮度 */ int main( int argc, char** argv ) { double t; /// 讀入使用者提供的影象 Mat image = imread( "Lena.jpg" ); Mat new_image = Mat::zeros( image.size(), image.type() ); Mat new_image1 = Mat::zeros( image.size(), image.type() ); Mat new_image2 = Mat::zeros( image.size(), image.type() ); /// 初始化 cout << " Basic Linear Transforms " << endl; cout << "-------------------------" << endl; cout << "* Enter the alpha value [1.0-3.0]: "; cin >> alpha; cout << "* Enter the beta value [0-100]: "; cin >> beta; t = (double)getTickCount(); /// 執行運算 new_image(i,j) = alpha*image(i,j) + beta for( int y = 0; y < image.rows; y++ ) { for( int x = 0; x < image.cols; x++ ) { for( int c = 0; c < 3; c++ ) { new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta ); } } } t = 1000*((double)getTickCount() - t)/getTickFrequency(); cout << ".at+[] Times passed in milliseconds: " << t << endl; t = (double)getTickCount(); int nr= image.rows; // number of rows int nc= image.cols * image.channels(); // total number of elements per line for (int y=0; y<nr; y++) { uchar* data= image.ptr<uchar>(y); uchar* data1=new_image1.ptr<uchar>(y); for (int x=0; x<nc; x++) { data1[x]=saturate_cast<uchar>(alpha*data[x]+beta); } } t = 1000*((double)getTickCount() - t)/getTickFrequency(); cout << ".ptr+[] Times passed in milliseconds: " << t << endl; t = (double)getTickCount(); image.convertTo(new_image2, -1, alpha, beta); t = 1000*((double)getTickCount() - t)/getTickFrequency(); cout << "convertTo Times passed in milliseconds: " << t << endl; /// 建立視窗 namedWindow("Original Image", 1); namedWindow("New Image", 1); namedWindow("New Image1", 1); namedWindow("New Image2", 1); /// 顯示影象 imshow("Original Image", image); imshow("New Image", new_image); imshow("New Image1", new_image1); imshow("New Image2", new_image2); /// 等待使用者按鍵 waitKey(); return 0; }
4、執行結果:
圖1、原圖 圖2、.at方法
圖3、.ptr方法 圖4、convertTo方法
圖5、執行時間
5、結論
從執行時間可以看出,使用OpenCV自帶的函式執行效率最高,而使用.ptr方法比.at方法好,這也印證了前面部落格學習OpenCV範例(二)——OpenCV如何掃描影象、利用查詢表和計時所說的。
6、用到的類
convertTo:
功能:通過縮放比例將陣列變換成其他型別
結構:
m:輸出影象void Mat::convertTo(OutputArray m, int rtype, double alpha=1, double beta=0 ) const
rtype:輸出影象的型別
alpha:比例因子α,決定對比度
beta:附加值β,決定亮度
函式原理如下:
saturate_cast:
功能:防止資料溢位
為什麼上面的函式會用到saturate_cast呢,因為無論是加是減,乘除,都會超出一個畫素灰度值的範圍(0~255)所以,所以當運算完之後,結果為負,則轉為0,結果超出255,則為255。