生活随笔
收集整理的這篇文章主要介紹了
访问Mat中每个像素的值
小編覺得挺不錯的,現(xià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)種顏色。
方法零:.ptr和[]操作符
Mat最直接的訪問方法是通過.ptr<>函數(shù)得到一行的指針,并用[]操作符訪問某一列的像素值。
[cpp]?view plaincopy
?? void?colorReduce0(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?*?image.channels();??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ??????????????????data[i]=?data[i]/div*div?+?div/2;?? ????????????}???????????????????? ??????}?? }??
方法一:.ptr和指針操作
除了[]操作符,我們可以移動指針*++的組合方法訪問某一行中所有像素的值。
[cpp]?view plaincopy
?? void?colorReduce1(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?*?image.channels();??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ?????????????????*data++=?*data/div*div?+?div/2;?? ????????????}??? ??????}?? }??
方法二:.ptr、指針操作和取模運(yùn)算
方法二和方法一的訪問方式相同,不同的是color reduce用模運(yùn)算代替整數(shù)除法
[cpp]?view plaincopy
?? void?colorReduce2(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?*?image.channels();??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ??????????????????int?v=?*data;?? ??????????????????*data++=?v?-?v%div?+?div/2;?? ????????????}??? ??????}?? }??
方法三:.ptr、指針運(yùn)算和位運(yùn)算
由于進(jìn)行量化的單元div通常是2的整次方,因此所有的乘法和除法都可以用位運(yùn)算表示。
[cpp]?view plaincopy
?? void?colorReduce3(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?*?image.channels();??? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ???????? ??????uchar?mask=?0xFF<<n;??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ????????????*data++=?*data&mask?+?div/2;?? ????????????}??? ??????}?? }??
方法四:指針運(yùn)算
方法四和方法三量化處理的方法相同,不同的是用指針運(yùn)算代替*++操作。
[cpp]?view plaincopy
?? void?colorReduce4(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?*?image.channels();??? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ??????int?step=?image.step;??? ???????? ??????uchar?mask=?0xFF<<n;??? ???????? ??????uchar?*data=?image.data;?? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ????????????*(data+i)=?*data&mask?+?div/2;?? ????????????}??? ????????????data+=?step;???? ??????}?? }??
方法五:.ptr、*++、位運(yùn)算以及image.cols * image.channels()
這種方法就是沒有計(jì)算nc,基本是個充數(shù)的方法。
[cpp]?view plaincopy
?? void?colorReduce5(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ???????? ??????uchar?mask=?0xFF<<n;??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<image.cols?*?image.channels();?i++)?{?? ????????????*data++=?*data&mask?+?div/2;?? ????????????}??? ??????}?? }??
?
方法六:連續(xù)圖像
Mat提供了isContinuous()函數(shù)用來查看Mat在內(nèi)存中是不是連續(xù)存儲,如果是則圖片被存儲在一行中。
[cpp]?view plaincopy
?? void?colorReduce6(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?*?image.channels();??? ??????if?(image.isContinuous())??{?? ???????????? ??????????nc=?nc*nr;??? ??????????nr=?1;???? ???????}?? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ???????? ??????uchar?mask=?0xFF<<n;??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ????????????*data++=?*data&mask?+?div/2;?? ????????????}??? ??????}?? }??
方法七:continuous+channels
與方法六基本相同,也是充數(shù)的。
[cpp]?view plaincopy
?? void?colorReduce7(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?;??? ??????if?(image.isContinuous())??{?? ???????????? ??????????nc=?nc*nr;??? ??????????nr=?1;???? ???????}?? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ???????? ??????uchar?mask=?0xFF<<n;??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ????????????*data++=?*data&mask?+?div/2;?? ????????????*data++=?*data&mask?+?div/2;?? ????????????*data++=?*data&mask?+?div/2;?? ????????????}??? ??????}?? }??
方法八:Mat _iterator
真正有區(qū)別的方法來啦,用Mat提供的迭代器代替前面的[]操作符或指針,血統(tǒng)純正的官方方法~
[cpp]?view plaincopy
?? void?colorReduce8(cv::Mat?&image,?int?div=64)?{?? ???????? ??????cv::Mat_<cv::Vec3b>::iterator?it=?image.begin<cv::Vec3b>();?? ??????cv::Mat_<cv::Vec3b>::iterator?itend=?image.end<cv::Vec3b>();?? ??????for?(?;?it!=?itend;?++it)?{?? ????????(*it)[0]=?(*it)[0]/div*div?+?div/2;?? ????????(*it)[1]=?(*it)[1]/div*div?+?div/2;?? ????????(*it)[2]=?(*it)[2]/div*div?+?div/2;?? ??????}?? }??
?
方法九:Mat_ iterator 和位運(yùn)算
把方法八中的乘除法換成位運(yùn)算。
[cpp]?view plaincopy
?? void?colorReduce9(cv::Mat?&image,?int?div=64)?{?? ???????? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ???????? ??????uchar?mask=?0xFF<<n;??? ???????? ??????cv::Mat_<cv::Vec3b>::iterator?it=?image.begin<cv::Vec3b>();?? ??????cv::Mat_<cv::Vec3b>::iterator?itend=?image.end<cv::Vec3b>();?? ??????for?(?;?it!=?itend;?++it)?{?? ????????(*it)[0]=?(*it)[0]&mask?+?div/2;?? ????????(*it)[1]=?(*it)[1]&mask?+?div/2;?? ????????(*it)[2]=?(*it)[2]&mask?+?div/2;?? ??????}?? }??
方法十:MatIterator_
和方法八基本相同。
[cpp]?view plaincopy
?? void?colorReduce10(cv::Mat?&image,?int?div=64)?{?? ??????cv::Mat_<cv::Vec3b>?cimage=?image;?? ??????cv::Mat_<cv::Vec3b>::iterator?it=cimage.begin();?? ??????cv::Mat_<cv::Vec3b>::iterator?itend=cimage.end();?? ??????for?(?;?it!=?itend;?it++)?{??? ????????(*it)[0]=?(*it)[0]/div*div?+?div/2;?? ????????(*it)[1]=?(*it)[1]/div*div?+?div/2;?? ????????(*it)[2]=?(*it)[2]/div*div?+?div/2;?? ??????}?? }??
?
方法十一:圖像坐標(biāo)
[cpp]?view plaincopy
?? void?colorReduce11(cv::Mat?&image,?int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols;??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ??????????????????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;?? ????????????}??? ??????}?? }??
方法十二:創(chuàng)建輸出圖像
之前的方法都是直接修改原圖,方法十二新建了輸出圖像,主要用于后面的時間對比。
[cpp]?view plaincopy
?? void?colorReduce12(const?cv::Mat?&image,??? ?????????????????cv::Mat?&result,???????? ?????????????????int?div=64)?{?? ??????int?nr=?image.rows;??? ??????int?nc=?image.cols?;??? ???????? ??????result.create(image.rows,image.cols,image.type());?? ???????? ??????nc=?nc*nr;??? ??????nr=?1;???? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ???????? ??????uchar?mask=?0xFF<<n;??? ??????for?(int?j=0;?j<nr;?j++)?{?? ??????????uchar*?data=?result.ptr<uchar>(j);?? ??????????const?uchar*?idata=?image.ptr<uchar>(j);?? ??????????for?(int?i=0;?i<nc;?i++)?{?? ????????????*data++=?(*idata++)&mask?+?div/2;?? ????????????*data++=?(*idata++)&mask?+?div/2;?? ????????????*data++=?(*idata++)&mask?+?div/2;?? ??????????}??? ??????}?? }??
方法十三:重載操作符
Mat重載了+&等操作符,可以直接將兩個Scalar(B,G,R)數(shù)據(jù)進(jìn)行位運(yùn)算和數(shù)學(xué)運(yùn)算。
[cpp]?view plaincopy
?? void?colorReduce13(cv::Mat?&image,?int?div=64)?{?? ??????int?n=?static_cast<int>(log(static_cast<double>(div))/log(2.0));?? ???????? ??????uchar?mask=?0xFF<<n;??? ???????? ??????image=(image&cv::Scalar(mask,mask,mask))+cv::Scalar(div/2,div/2,div/2);?? }??
時間對比
通過迭代二十次取平均時間,得到每種方法是運(yùn)算時間如下。
可以看到,指針*++訪問和位運(yùn)算是最快的方法;而不斷的計(jì)算image.cols*image.channles()花費(fèi)了大量重復(fù)的時間;另外迭代器訪問雖然安全,但性能遠(yuǎn)低于指針運(yùn)算;通過圖像坐標(biāo)(j,i)訪問時最慢的,使用重載操作符直接運(yùn)算效率最高。
總結(jié)
以上是生活随笔為你收集整理的访问Mat中每个像素的值的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。