OpenCV2 訪問各個像素點的方法(圖像遍歷)

轉載於此文

內容來自《OpenCV 2 Computer Vision Application Programming Cookbook》

OpenCV2 訪問圖像的各個像素有各種方法

我們來用各種方法來實現減少圖像的顏色數量

color = color/div*div +div/2;

若div爲8,則原來RGB每個通道的256種顏色減少爲32種。

若div爲64,則原來RGB每個通道的256種顏色減少爲4種,此時三通道所有能表示的顏色有4×4×4 = 64 種

以上運算請參考我的博客減少圖像顏色數量的運算
首先,我們來看一個函數

C++: uchar* Mat::ptr(int i=0)
i 是行號,返回的是該行數據的指針。
在OpenCV中,一張3通道圖像的一個像素點是按BGR的順序存儲的。
先來看看第一種訪問方案

void colorReduce1(cv::Mat& image, cv::Mat& result, int div=64){
    int nrow = image.rows;
    int ncol = image.cols * image.channels();
    for(int i=0; i<nrow; i++){
        uchar* data = image.ptr<uchar>(i);
        uchar* data_out = result.ptr<uchar>(i);
        for(int j=0; j<ncol; j++){
            data_out[j] = data[j]/div*div +div/2;
        }
    }
}

複製代碼
第二種方案:

先來看如下函數:

C++: bool Mat::isContinuous() const

C++: Mat Mat::reshape(int cn, int rows=0) const

出於性能方面的考慮,在圖像每一行的最後可能會填充一些像素,這樣圖像的數據就不是連續的了

我們可以用函數isContinuous()來判斷圖像的數據是否連續

reshape函數的作用如下:

Changes the shape and/or the number of channels of a 2D matrix without copying the data.

這樣,我們就提出了對第一種方法的改進

void colorReduce2(cv::Mat& image, cv::Mat& result, int div){
    if(image.isContinuous()){
        image.reshape(1,image.cols*image.rows);
    }
    int nrow = image.rows;
    int ncol = image.cols * image.channels();
    for(int i=0; i<nrow; i++){
        uchar* data = image.ptr<uchar>(i);
        uchar* data_out = result.ptr<uchar>(i);
        for(int j=0; j<ncol; j++){
            data_out[j] = data[j]/div*div +div/2;
        }
    }
}

第三種方案:
先來看看下面的函數
C++: template T& Mat::at(int i, int j)
其作用是Returns a reference to the specified array element.

void colorReduce3(cv::Mat& image, cv::Mat& result, int div){
    int nrow = image.rows;
    int ncol = image.cols * image.channels();
    for(int i=0; i<nrow; i++){
        for(int j=0; j<ncol; j++){
            image.at<cv::Vec3b>(j,i)[0]= image.at<cv::Vec3b>(j,i)[0]/div*div + div/2;
            image.at<cv::Vec3b>(j,i)[1]= image.at<cv::Vec3b>(j,i)[1]/div*div + div/2;
            image.at<cv::Vec3b>(j,i)[2]= image.at<cv::Vec3b>(j,i)[2]/div*div + div/2;
        }
    }
}

第四種方案是使用迭代器
會使用到如下函數:
C++: template MatIterator_<_Tp> Mat::begin()
C++: MatIterator_<_Tp> Mat::end()

關於迭代器的使用,可參考我的博客:迭代器:訪問string對象和vector對象

void colorReduce4(cv::Mat& image, cv::Mat& result, int div){
    cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
    cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();
    cv::Mat_<cv::Vec3b>::iterator itout = result.begin<cv::Vec3b>();
    for(; it!=itend; ++it,++itout){
        (*itout)[0] = (*it)[0]/div*div + div/2;
        (*itout)[1] = (*it)[1]/div*div + div/2;
        (*itout)[2] = (*it)[2]/div*div + div/2;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章