最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

我們在實(shí)際應(yīng)用中對圖像進(jìn)行的操作,往往并不是將圖像作為一個整體進(jìn)行操作,而是對圖像中的所有點(diǎn)或特殊點(diǎ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,則代碼實(shí)現(xiàn)時就是簡單的value/N*N,通常我們會再加上N/2以得到相鄰的N的倍數(shù)的中間值,最后圖像被量化為(256/N)×(256/N)×(256/N)種顏色。

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

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

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

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方法取圖像中的點(diǎn)的用法:

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

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

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

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

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

上面的例程中可以看到,我們實(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ù)最開始的三個值,是最左上角的那像素的三個通道的值。

但是這種用法不能用在行與行之間,因?yàn)閳D像在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++實(shí)現(xiàn)LeetCode(36.驗(yàn)證數(shù)獨(dú))

    C++實(shí)現(xiàn)LeetCode(36.驗(yàn)證數(shù)獨(dú))

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(36.驗(yàn)證數(shù)獨(dú)),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Python繪圖之詳解matplotlib

    Python繪圖之詳解matplotlib

    這篇文章主要介紹了Python繪圖之詳解matplotlib,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言超市管理系統(tǒng)設(shè)計(jì)

    C語言超市管理系統(tǒng)設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C語言超市管理系統(tǒng)設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • C語言數(shù)組快速入門詳細(xì)講解

    C語言數(shù)組快速入門詳細(xì)講解

    數(shù)組是一組有序的數(shù)據(jù)的集合,數(shù)組中元素類型相同,由數(shù)組名和下標(biāo)唯一地確定,數(shù)組中數(shù)據(jù)不僅數(shù)據(jù)類型相同,而且在計(jì)算機(jī)內(nèi)存里連續(xù)存放,地址編號最低的存儲單元存放數(shù)組的起始元素,地址編號最高的存儲單元存放數(shù)組的最后一個元素
    2022-05-05
  • 淺析C++編程當(dāng)中的線程

    淺析C++編程當(dāng)中的線程

    這篇文章主要介紹了淺析C++編程當(dāng)中的線程,線程在每一種編程語言中都是重中之重,需要的朋友可以參考下
    2015-07-07
  • C及C++中typedef的簡單使用介紹

    C及C++中typedef的簡單使用介紹

    C/C++中關(guān)鍵字typedef的理解不是多透徹,今天小編抽空給大家分享下C及C++中typedef的簡單使用介紹,需要的朋友可以參考下
    2016-10-10
  • VS2019+Opencv4.0+Win10配置詳解

    VS2019+Opencv4.0+Win10配置詳解

    這篇文章主要介紹了VS2019+Opencv4.0+Win10配置詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • C語言實(shí)現(xiàn)繪制可愛的橘子鐘表

    C語言實(shí)現(xiàn)繪制可愛的橘子鐘表

    這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)繪制可愛的橘子鐘表,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下
    2022-12-12
  • c語言實(shí)現(xiàn)學(xué)生管理系統(tǒng)詳解

    c語言實(shí)現(xiàn)學(xué)生管理系統(tǒng)詳解

    這篇文章主要為大家介紹了c語言實(shí)現(xiàn)學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助<BR>
    2021-12-12
  • C++函數(shù)模板的使用詳解

    C++函數(shù)模板的使用詳解

    大家好,本篇文章主要講的是C++函數(shù)模板的使用詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01

最新評論

肥乡县| 施甸县| 鲁山县| 全州县| 扎囊县| 仪陇县| 黔南| 迭部县| 云霄县| 苍南县| 崇礼县| 正宁县| 大埔区| 桃源县| 涟水县| 城步| 会理县| 绍兴县| 桐乡市| 江永县| 安图县| 钟祥市| 铜川市| 孝昌县| 新兴县| 贵德县| 青州市| 三穗县| 尼勒克县| 蒙阴县| 双桥区| 赤壁市| 嫩江县| 黎川县| 自治县| 冀州市| 尼勒克县| 台湾省| 四川省| 大名县| 泰兴市|