再更一發好久沒更過的OpenCV,不過其實寫到這個部分對計算機視覺算法有所了解的應該可以做到用什么查什么了,所以后面可能會更的慢一點吧,既然開了新坑,還是機器學習更有研究價值吧。。。
圖像在內存中的存儲方式
灰度圖像

RGB圖像,矩陣的列會包含多個子列

因為內存足夠大,可以實現連續存儲,因此,圖像中的各行就能一行一行地連接起來,形成一個長行。連續存儲,有助於提高圖像掃面速度,可以使用isContinuous()來判斷矩陣是否是連續存儲。
顏色空間縮減
對於三通道圖像,一個像素對應的顏色有一千六百多萬種,用如此多的顏色可能會影響算法性能。顏色空間縮減即用顏色中具有代表性的一部分表示相近顏色,做法是:將現有顏色空間值除以某個輸入值,以獲得較少的顏色數。對每個像素進行乘除操作也需要浪費一定的時間(加,減,賦值等代價較低),對於較大的圖像,可以預先計算所有可能的值,建立 look up table,
int divideWidth = 10; uchar table[256]; for (int i = 0; i < 256; ++i) table[i] = divideWidth * (i/divideWidth);
然后遍歷圖像矩陣的每個像素,對像素應用公式:
p[j] = table[p[j]];
OpenCV官方提供了函數進行圖像元素查找、掃描與操作圖像
void cv::LUT ( InputArray src, InputArray lut, OutputArray dst )
進行look-up table轉換操作,輸出矩陣將被賦值為
dst(I)<-lut(src(I)+d)
其中,當src為CV_8U時,d=0,src為CV_8S時,d=128(用於把look up table輸入轉換到0~255)
- src:矩陣輸入,矩陣元素為8-bit色彩值。
- lut:256個色彩值的look-up table,如果src為多通道函數,lut可為單通道(src每通道的處理方式相同)或與src的通道數相同。
- dst:與輸入矩陣大小、通道數相同的輸出矩陣src, 類型與lut相同(CV_8U或CV_8S)
用法示例如下,
Mat lookUpTable(1, 256, CV_8U); uchar* p = lookUpTable.data; for(int i = 0; i < 256; ++i) p[i] = table[i]; for(int i=0; i < times; ++i) LUT(Input,lookUpTable, Output);
計時函數
int64 getTickCount()
返回CPU自某個事件(如啟動電腦)以來走過的時鍾周期
double getTickFrequency()
返回CPU一秒鍾所走過的時鍾周期數,這樣我們就可以以秒為單位對某運算計時
double time0 = stactic_cast<double>(getTickCount()); time0 = ((double) getTickCount() - time0) / getTickFrequency(); cout << "Runing time: " << time0 << "s" << endl;
訪問圖像中像素的三類方法
用指針訪問像素
利用C中的操作符[]或*,這種方法最快,但比較抽象。
用迭代器操作像素
類似於STL中的用法,只需獲取圖像矩陣的begin和end,然后迭代從begin直至end。比前一種方法安全,不會越界,但速度慢。
動態地址計算
簡單明了,直接用at(y,x)找到像素點,但是速度最慢。
上述三種方法的事例程序如下:
#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> // function void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div); // main int main( int argc, char** argv ) { // Load image cv::Mat srcImage = cv::imread("1.jpg"); imshow("orginal image", srcImage); // alocate space for output image cv::Mat dstImage; dstImage.create(srcImage.rows, srcImage.cols, srcImage.type()); // get the starting time double time0 = static_cast<double>(cv::getTickCount()); // call color space reduction function colorReduce(srcImage, dstImage, 32); // estimate runing time time0 = ((double)cv::getTickCount() - time0)/cv::getTickFrequency(); std::cout << "Running time for this method: " << time0 << "s." << std::endl; imshow("Lab Space", dstImage); cv::waitKey(0); return 0; } #define USESUBS #ifdef USEPOINTER void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div) { // set parameters outputImage = inputImage.clone(); int rowNumber = outputImage.rows; int colNumber = outputImage.cols*outputImage.channels(); for(int i = 0;i < rowNumber;i++) { uchar* data = outputImage.ptr<uchar>(i); // get the address of the ith row for(int j=0; j<colNumber; j++) { data[j] = data[j]/div*div + div/2; } } } #endif #ifdef USEITERATOR void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div) { // set parameters outputImage = inputImage.clone(); // get the iterator cv::Mat_<cv::Vec3b>::iterator it = outputImage.begin<cv::Vec3b>(); cv::Mat_<cv::Vec3b>::iterator itend = outputImage.end<cv::Vec3b>(); // save new pixel colors for(;it != itend; ++it) { (*it)[0] = (*it)[0]/div*div + div/2; // B (*it)[1] = (*it)[1]/div*div + div/2; // G (*it)[2] = (*it)[2]/div*div + div/2; // R } } #endif #ifdef USESUBS void colorReduce(cv::Mat& inputImage, cv::Mat& outputImage, int div) { // set parameters outputImage = inputImage.clone(); int rowNumber = outputImage.rows; int colNumber = outputImage.cols; // save new pixel colors for(int i=0; i<rowNumber; i++) { for(int j=0; j<colNumber; j++) { outputImage.at<cv::Vec3b>(i,j)[0] = outputImage.at<cv::Vec3b>(i,j)[0]/div*div + div/2; // B outputImage.at<cv::Vec3b>(i,j)[1] = outputImage.at<cv::Vec3b>(i,j)[1]/div*div + div/2; // G outputImage.at<cv::Vec3b>(i,j)[2] = outputImage.at<cv::Vec3b>(i,j)[2]/div*div + div/2; // R } } } #endif /* Outputs: USEPOINTER Running time for this method: 0.0162628s. USEITERATOR Running time for this method: 0.0362183s. USESUBS Running time for this method: 0.0518141s. */
