欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV?通過Mat遍歷圖像的方法匯總

 更新時間:2022年02月25日 14:45:01   作者:一杯清酒邀明月  
對圖像中的所有點或特殊點進(jìn)行運(yùn)算,所以遍歷圖像就顯得很重要,如何高效的遍歷圖像是一個很值得探討的問題,本文給大家?guī)砹硕喾N方法操作OpenCV?通過Mat遍歷圖像,感興趣的朋友一起看看吧

我們在實際應(yīng)用中對圖像進(jìn)行的操作,往往并不是將圖像作為一個整體進(jìn)行操作,而是對圖像中的所有點或特殊點進(jìn)行運(yùn)算,所以遍歷圖像就顯得很重要,如何高效的遍歷圖像是一個很值得探討的問題。

Color Reduce
還是使用經(jīng)典的Reduce Color的例子,即對圖像中的像素表達(dá)進(jìn)行量化。如常見的RGB24圖像有256×256×256中顏色,通過Reduce Color將每個通道的像素減少8倍至256/8=32種,則圖像只有32×32×32種顏色。假設(shè)量化減少的倍數(shù)是N,則代碼實現(xiàn)時就是簡單的value/N*N,通常我們會再加上N/2以得到相鄰的N的倍數(shù)的中間值,最后圖像被量化為(256/N)×(256/N)×(256/N)種顏色。

并對圖像降色彩后的彩色直方圖進(jìn)行統(tǒng)計。

方法一、直接對圖像像素修改.at<typename>(i,j)

Mat類提供了一個at的方法用于取得圖像上的點,它是一個模板函數(shù),可以取到任何類型的圖像上的點。

void colorReduce(Mat& image,int div)
{
    for(int i=0;i<image.rows;i++)
    {
        for(int j=0;j<image.cols;j++)
        {
            image.at<Vec3b>(i,j)[0]=image.at<Vec3b>(i,j)[0]/div*div+div/2;
            image.at<Vec3b>(i,j)[1]=image.at<Vec3b>(i,j)[1]/div*div+div/2;
            image.at<Vec3b>(i,j)[2]=image.at<Vec3b>(i,j)[2]/div*div+div/2;
        }
    }
}

通過上面的例子我們可以看出,at方法取圖像中的點的用法:

image.at<uchar>(i,j):取出灰度圖像中i行j列的點。
image.at<Vec3b>(i,j)[k]:取出彩色圖像中i行j列第k通道的顏色點,k=[0,1,2],分別代表B,G,R。

其中uchar,Vec3b都是圖像像素值的類型,不要對Vec3b這種類型感覺害怕,其實在core里它是通過typedef Vec<T,N>來定義的,N代表元素的個數(shù),T代表類型。

更簡單一些的方法:OpenCV定義了一個Mat的模板子類為Mat_,它重載了operator()讓我們可以更方便的取圖像上的點。

Mat_<uchar> im=image;
im(i,j)=im(i,j)/div*div+div/2;

二、用指針.ptr<uchar>(k)來遍歷輸入圖像,數(shù)組[]生成輸出圖像

上面的例程中可以看到,我們實際喜歡把原圖傳進(jìn)函數(shù)內(nèi),但是在函數(shù)內(nèi)我們對原圖像進(jìn)行了修改,而將原圖作為一個結(jié)果輸出,很多時候我們需要保留原圖,這樣我們需要一個原圖的副本。

void colorReduce(const Mat& image,Mat& outImage,int div)
{
    // 創(chuàng)建與原圖像等尺寸的圖像
    outImage.create(image.size(),image.type());
    int nr=image.rows;
    // 將3通道轉(zhuǎn)換為1通道
    int nl=image.cols*image.channels();
    for(int k=0;k<nr;k++)
    {
        // 每一行圖像的指針
        const uchar* inData=image.ptr<uchar>(k);
        uchar* outData=outImage.ptr<uchar>(k);
        for(int i=0;i<nl;i++)
        {
            outData[i]=inData[i]/div*div+div/2;
        }
    }
}

從上面的例子中可以看出,取出圖像中第i行數(shù)據(jù)的指針:image.ptr<uchar>(i)。

值得說明的是:程序中將3通道的數(shù)據(jù)轉(zhuǎn)換為1通道,在建立在每一行數(shù)據(jù)元素之間在內(nèi)存里是連續(xù)存儲的,每個像素三通道像素按順序存儲。也就是一幅圖像數(shù)據(jù)最開始的三個值,是最左上角的那像素的三個通道的值。

但是這種用法不能用在行與行之間,因為圖像在OpenCV里的存儲機(jī)制問題,行與行之間可能有空白單元。這些空白單元對圖像來說是沒有意思的,只是為了在某些架構(gòu)上能夠更有效率,比如intel MMX可以更有效的處理那種個數(shù)是4或8倍數(shù)的行。但是我們可以申明一個連續(xù)的空間來存儲圖像,這個話題引入下面最為高效的遍歷圖像的機(jī)制。

三、用指針.ptr<uchar>(k)來遍歷輸入圖像,指針方式生成輸出圖像

與上述方法二遍歷圖像的方法相同,而生成輸出圖像的方式從數(shù)組換成了指針的方式。因此只需改動一句話。

void colorReduce(const Mat& image,Mat& outImage,int div)
{
    // 創(chuàng)建與原圖像等尺寸的圖像
    outImage.create(image.size(),image.type());
    int nr=image.rows;
    // 將3通道轉(zhuǎn)換為1通道
    int nl=image.cols*image.channels();
    for(int k=0;k<nr;k++)
    {
        // 每一行圖像的指針
        const uchar* inData=image.ptr<uchar>(k);
        uchar* outData=outImage.ptr<uchar>(k);
        for(int i=0;i<nl;i++)
        {
            *outData++ = *inData++ / div*div + div / 2;
        }
    }
}

四、用指針.ptr<uchar>(k)來遍歷輸入圖像,指針方式結(jié)合位運(yùn)算生成輸出圖像

與上述方法遍歷圖像的方法相同,而生成輸出圖像的方式從加減乘除基本四則運(yùn)算的方式換成了位運(yùn)算的方式。

這里特別需要注意的是,位運(yùn)算的優(yōu)先級是低于乘除加減的,所以一定要在位運(yùn)算加括號。

void colorReduce(const Mat& image, Mat& outImage, int div)
{
    // 創(chuàng)建與原圖像等尺寸的圖像
    outImage.create(image.size(), image.type());
    int nr = image.rows;
    // 將3通道轉(zhuǎn)換為1通道
    int nl = image.cols*image.channels();
    //對數(shù)換底公式log a(b) = log b/log a
    int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));
    // mask used to round the pixel value  e.g. for div=16, mask= 0xF0
    uchar mask = 0xFF << n;
    for (int k = 0; k<nr; k++)
    {
        // 每一行圖像的指針
        const uchar* inData = image.ptr<uchar>(k);
        uchar* outData = outImage.ptr<uchar>(k);
        for (int i = 0; i<nl; i++)
        {
            //進(jìn)行位運(yùn)算時要注意加括號,位運(yùn)算優(yōu)先級低于+-*/
            *outData++ = (*inData++ & mask)  + div / 2;
        }
    }
}

五、用指針.ptr<uchar>(k)來遍歷輸入圖像,指針方式結(jié)合取模運(yùn)算生成輸出圖像

與上述方法遍歷圖像的方法相同,而生成輸出圖像的方式從位運(yùn)算的方式換成了取模運(yùn)算的方式。

void colorReduce(const Mat& image, Mat& outImage, int div)
{
    // 創(chuàng)建與原圖像等尺寸的圖像
    outImage.create(image.size(), image.type());
    int nr = image.rows;
    // 將3通道轉(zhuǎn)換為1通道
    int nl = image.cols*image.channels();

    int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));
    // mask used to round the pixel value  e.g. for div=16, mask= 0xF0
    uchar mask = 0xFF << n;
    for (int k = 0; k<nr; k++)
    {
        // 每一行圖像的指針
        const uchar* inData = image.ptr<uchar>(k);
        uchar* outData = outImage.ptr<uchar>(k);
        for (int i = 0; i<nl; i++)
        {
            int Data = *inData++;
            *outData++ = Data - Data%div + div / 2;
        }
    }
}

六、連續(xù)圖像isContinuous()函數(shù)方法。

上面已經(jīng)提到過了,一般來說圖像行與行之間往往存儲是不連續(xù)的,但是有些圖像可以是連續(xù)的,Mat提供了一個檢測圖像是否連續(xù)的函數(shù)isContinuous()。當(dāng)圖像連通時,我們就可以把圖像完全展開,看成是一行。

void colorReduce(const Mat& image,Mat& outImage,int div)
{
    int nr=image.rows;
    int nc=image.cols;
    outImage.create(image.size(),image.type());
    if(image.isContinuous()&&outImage.isContinuous())
    {
        nr=1;
        nc=nc*image.rows*image.channels();
    }
    for(int i=0;i<nr;i++)
    {
        const uchar* inData=image.ptr<uchar>(i);
        uchar* outData=outImage.ptr<uchar>(i);
        for(int j=0;j<nc;j++)
        {
            *outData++=*inData++/div*div+div/2;
        }
    }
}

用指針除了用上面的方法外,還可以用指針來索引固定位置的像素:

image.step返回圖像一行像素元素的個數(shù)(包括空白元素),image.elemSize()返回一個圖像像素的大小。

image.at<uchar>(i,j)=image.data+i*image.step+j*image.elemSize();

七、迭代器Mat_iterator方法。

下面的方法可以讓我們來為圖像中的像素聲明一個迭代器:

MatIterator_<Vec3b> it;
 Mat_<Vec3b>::iterator it;

如果迭代器指向一個const圖像,則可以用下面的聲明:

MatConstIterator<Vec3b> it;
或者
Mat_<Vec3b>::const_iterator it;

下面我們用迭代器來簡化上面的colorReduce程序:

void colorReduce(const Mat& image,Mat& outImage,int div)
{
    outImage.create(image.size(),image.type());
    MatConstIterator_<Vec3b> it_in=image.begin<Vec3b>();
    MatConstIterator_<Vec3b> itend_in=image.end<Vec3b>();
    MatIterator_<Vec3b> it_out=outImage.begin<Vec3b>();
    MatIterator_<Vec3b> itend_out=outImage.end<Vec3b>();
    while(it_in!=itend_in)
    {
        (*it_out)[0]=(*it_in)[0]/div*div+div/2;
        (*it_out)[1]=(*it_in)[1]/div*div+div/2;
        (*it_out)[2]=(*it_in)[2]/div*div+div/2;
        it_in++;
        it_out++;
    }
}

如果你想從第二行開始,則可以從

image.begin<Vec3b>()+image.rows

開始。

上面7種方法中,第4種方法的效率最高!

到此這篇關(guān)于OpenCV 通過Mat遍歷圖像的幾種方法的文章就介紹到這了,更多相關(guān)OpenCV遍歷圖像內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:

相關(guān)文章

  • c++利用vector創(chuàng)建二維數(shù)組的幾種方法總結(jié)

    c++利用vector創(chuàng)建二維數(shù)組的幾種方法總結(jié)

    這篇文章主要介紹了c++利用vector創(chuàng)建二維數(shù)組的幾種方法總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語言實現(xiàn)打印星號圖案

    C語言實現(xiàn)打印星號圖案

    這篇文章主要介紹了C語言實現(xiàn)打印星號圖案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • VS2019如何添加頭文件路徑的方法步驟

    VS2019如何添加頭文件路徑的方法步驟

    這篇文章主要介紹了VS2019如何添加頭文件路徑的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • C語言字符串原地壓縮實現(xiàn)方法

    C語言字符串原地壓縮實現(xiàn)方法

    這篇文章主要介紹了C語言字符串原地壓縮實現(xiàn)方法,包含了字符串的遍歷與轉(zhuǎn)換等操作,是很實用的操作技巧,需要的朋友可以參考下
    2014-09-09
  • 詳解MFC/C++調(diào)用易語言的整數(shù)型和文本型與VS2010互動

    詳解MFC/C++調(diào)用易語言的整數(shù)型和文本型與VS2010互動

    在本篇文章里我們給大家分享了MFC/C++調(diào)用易語言的整數(shù)型和文本型與VS2010互動相關(guān)知識點內(nèi)容,有興趣的朋友們可以參考下。
    2018-11-11
  • C語言職工信息管理系統(tǒng)源碼

    C語言職工信息管理系統(tǒng)源碼

    這篇文章主要為大家詳細(xì)介紹了C語言職工信息管理系統(tǒng)源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C語言的多級指針你了解嗎

    C語言的多級指針你了解嗎

    這篇文章主要介紹了C語言中的多級指針,本文給大家介紹的非常詳細(xì),具有參考借鑒價值,需要的朋友可以參考下,希望能給你帶來幫助
    2021-08-08
  • C語言中回調(diào)函數(shù)的使用詳情

    C語言中回調(diào)函數(shù)的使用詳情

    這篇文章主要介紹了C語言中回調(diào)函數(shù)的使用詳情,閱讀下文我們將學(xué)習(xí)到架構(gòu)的核心理念和需、回調(diào)函數(shù)的作用、回調(diào)函數(shù)的程序編寫等內(nèi)容,需要的小伙伴可以參考一下
    2022-03-03
  • C語言實現(xiàn)簡單貪吃蛇小游戲

    C語言實現(xiàn)簡單貪吃蛇小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)簡單貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • C語言 數(shù)據(jù)結(jié)構(gòu)之中序二叉樹實例詳解

    C語言 數(shù)據(jù)結(jié)構(gòu)之中序二叉樹實例詳解

    這篇文章主要介紹了C語言 數(shù)據(jù)結(jié)構(gòu)之中序二叉樹實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-01-01

最新評論