新聞中心
1. 介紹
openCV 是使用 Mat 進(jìn)行存儲(chǔ)圖片,記錄各種像素信息。那么 Mat 中的像素是如何記錄和獲取的呢?

企業(yè)建站必須是能夠以充分展現(xiàn)企業(yè)形象為主要目的,是企業(yè)文化與產(chǎn)品對(duì)外擴(kuò)展宣傳的重要窗口,一個(gè)合格的網(wǎng)站不僅僅能為公司帶來(lái)巨大的互聯(lián)網(wǎng)上的收集和信息發(fā)布平臺(tái),創(chuàng)新互聯(lián)面向各種領(lǐng)域:成都地磅秤等成都網(wǎng)站設(shè)計(jì)、營(yíng)銷型網(wǎng)站建設(shè)解決方案、網(wǎng)站設(shè)計(jì)等建站排名服務(wù)。
在網(wǎng)上找到有很多是C語(yǔ)言寫的。在這里我想使用java的語(yǔ)法給大家介紹一下。
如何通過(guò)Mat獲取到指定區(qū)域的像素。RGB,BGR,HSV,GRAY等格式數(shù)據(jù)的獲取。
2. channels 通道
當(dāng)我們使用Mat.channels() 方法,能夠得到當(dāng)前 Mat 的通道數(shù)。 通常返回結(jié)果值為:1,2,3,4 這四個(gè)結(jié)果。
那么這個(gè)通道是什么東西呢?
我們知道,所有的圖像都是由一個(gè)個(gè)像素點(diǎn)堆積而成的。而一個(gè)像素點(diǎn),又是由RGB顏色混合而成的。
每一種顏色就是一種通道。每個(gè)像素點(diǎn)是多個(gè)通道顏色的混合結(jié)果。
PS:知識(shí)點(diǎn),RGB三原色可以混淆所有我們?nèi)庋劭梢砸?jiàn)到的顏色。
所以,當(dāng)我們弄明白通道之后就能明白如何獲取Mat中指定坐標(biāo)的顏色值了。
mat.rows() 是Y軸長(zhǎng)度。
mat.cols() 是X軸長(zhǎng)度。
示例:
Mat rgba ;// 假如我有一個(gè) rgba的Mat對(duì)象
int channels = rgba.channels(); // channels 的長(zhǎng)度是4
double[] temp = rgba.get(rgba.rows() / 2, rgba.cols() / 2); //取中間點(diǎn)顏色值
//temp 的數(shù)組的長(zhǎng)度就是通道數(shù),所以它的length=4
當(dāng)我們遍歷一遍temp的結(jié)果會(huì)得到:
StringBuffer stringBuffer = new StringBuffer();
for (double s : temp) {
stringBuffer.append(s).append(",");
}
Log.e("TAG", "顏色值:" + stringBuffer);
//輸出:
顏色值:3.0,0.0,4.0,255.0,
數(shù)據(jù)的結(jié)果實(shí)際情況是:
- r:3.0
- g:0.0
- b:4.0
- a:255 (透明度,0表示透明,255表示不透明)
知識(shí)點(diǎn),OpenCV 中的顏色順序不是 BGR 格式么?這個(gè)順序不針對(duì) Mat 中的顏色,而是我們使用 Scalar 的時(shí)候傳入的顏色順序是 BGR 順序而已。
new Scalar(10,255,255); //顏色順序是 B,G,R
我們?nèi)绻且粋€(gè) BGR 格式的 Mat 對(duì)象那么顏色值會(huì)怎么顯示呢?
還是使用上面的 Mat 我們進(jìn)行轉(zhuǎn)換之后,看看同一個(gè)點(diǎn)輸出的結(jié)果:
Mat bgr=new Mat();
Imgproc.cvtColor(rgba, bgr, Imgproc.COLOR_RGB2BGR);// 將RGB格式轉(zhuǎn)為BGR格式
int channels = bgr.channels(); // channels 的長(zhǎng)度是3
double[] temp1 = bgr.get(bgr.rows() / 2, bgr.cols() / 2); //取中間點(diǎn)顏色值
StringBuffer stringBuffer1 = new StringBuffer();
for (double s : temp1) {
stringBuffer1.append(s).append(",");
}
Log.e("TAG", "顏色值:" + stringBuffer1);
//輸出:
顏色值:4.0,0.0,3.0
數(shù)據(jù)的結(jié)果實(shí)際情況是:
- b:4.0
- g:0.0
- r:3.0
就會(huì)出現(xiàn)顏色的通道數(shù)變化。
不知道注意到了沒(méi)有,我上面是將rbga直接轉(zhuǎn)成了BGR。
在高位轉(zhuǎn)換的情況下,A通道會(huì)被直接丟棄。體現(xiàn)在圖像上就會(huì)沒(méi)有透明效果了。
我們?nèi)绻氪_保A通道也轉(zhuǎn)換,可以使用:
Imgproc.cvtColor(rgba, bgra, Imgproc.COLOR_RGBA2BGRA);
2.1 Gray 灰度圖轉(zhuǎn)換
當(dāng)我們將RGBA或者BGR等彩色圖像轉(zhuǎn)換為GRAY灰色的時(shí)候,Mat的通道數(shù)就會(huì)被壓制為單通道G了。效果如下:
int channels = rgba.channels();
double[] temp = rgba.get(rgba.rows() / 2, rgba.cols() / 2); //取中間點(diǎn)顏色值
// temp的長(zhǎng)度就是 channels的值,所以temp的結(jié)果就是4
StringBuffer stringBuffer = new StringBuffer();
for (double s : temp) {
stringBuffer.append( s).append(",");
}
Log.e("TAG", "通道數(shù):" + channels + " 顏色值:" + stringBuffer);
Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGBA2GRAY); //將RGBA轉(zhuǎn)GRAY
channels = rgba.channels();
temp = rgba.get(rgba.rows() / 2, rgba.cols() / 2); //取中間點(diǎn)顏色值
stringBuffer = new StringBuffer();
for (double s : temp) {
stringBuffer.append(s).append(",");
}
Log.e("TAG", "變換后:通道數(shù):" + channels + " 顏色值:" + stringBuffer);
//輸出結(jié)果:
E/TAG: 通道數(shù):4 顏色值:43.0,48.0,69.0,255.0,
E/TAG: 變換后:通道數(shù):1 顏色值:49.0,
會(huì)發(fā)現(xiàn)灰色圖是只有一個(gè)通道的。
按照Gray = R*0.299 + G*0.587 + B*0.114 公式進(jìn)行的轉(zhuǎn)換。
這個(gè)公式叫做Luminosity(亮度算法)。這個(gè)算法中RGB的各占比例。都是一個(gè)經(jīng)驗(yàn)值。也就是說(shuō)沒(méi)有科學(xué)道理。純粹經(jīng)驗(yàn)出發(fā)調(diào)試出來(lái)的一個(gè)比例。
PS:所以有一個(gè)小常識(shí),RGB轉(zhuǎn)Gray,然后再Gray轉(zhuǎn)換回RGB會(huì)出現(xiàn)色差。因?yàn)樵谵D(zhuǎn)換過(guò)程中避免不了信息丟失。
2.2 小結(jié)
當(dāng)我們弄明白通道數(shù)的概念之后。就能夠弄明白cvtColor中的各種轉(zhuǎn)換了
Luv,Lab,HSV,RGB,BGR,HLS,YUV,GRAY等等的顏色轉(zhuǎn)換其實(shí)都是針對(duì)我們的單像素中的通道值在處理。
- 單通道的,是Gray灰度圖。
- 雙通道的,兩個(gè)通道值一個(gè)為實(shí)數(shù),個(gè)為虛數(shù)。主要是RGB555和RGB565格式的圖像,這個(gè)通道通常用來(lái)計(jì)算。
- 三通道的,圖片就是彩色圖像了,例如RGB,BGR,HSV,HLS等等。
- 四通道的,圖片帶透明度的圖像了。相較于三通道多了一個(gè)alpha通道,也就是表示透明度。
我們?cè)谑褂肙penCV時(shí),新手經(jīng)常出現(xiàn)Mat錯(cuò)誤,就在于通道轉(zhuǎn)換了。因?yàn)镺penCV有些算法是必須單通道的。而我們一不小心傳了3通道的?;蛘撸琈at是三通道的。與另一個(gè)單通道的Mat進(jìn)行比較處理時(shí),出現(xiàn)通道錯(cuò)誤等等。
注意:
我們使用Imgproc.cvtColor?方法進(jìn)行轉(zhuǎn)換的時(shí)候。輸入的Imgproc.COLOR_RGBA2GRAY等等值是很重要的。需要根據(jù)我們的Mat的實(shí)際情況進(jìn)行選擇。
我們?nèi)绻鸐at是BGR格式的,我們卻選擇使用Imgproc.COLOR_RGB2HSV_FULL轉(zhuǎn)換,雖然結(jié)果是轉(zhuǎn)換了。但是實(shí)際情況是不對(duì)的。
因?yàn)镮mgproc會(huì)按照RGB的順序從double[]數(shù)組中提取參數(shù)進(jìn)行計(jì)算處理,而不是按照BGR的格式進(jìn)行提取轉(zhuǎn)換。
2.2.1 Imgproc.COLOR_XXXX解釋
簡(jiǎn)單介紹下ImgProc.COLOR_XXX的信息。其實(shí)說(shuō)破很簡(jiǎn)單:
ImgProc.COLOR_BGR2BGRA;// BGR to BGRA 也就是BGR格式轉(zhuǎn)BGRA格式
ImgProc.COLOR_RGB2RGBA;// RGB to RGBA 也就是RGB格式轉(zhuǎn)RGBA格式
ImgProc.COLOR_BGRA2BGR;// BGRA to BGR 格式
ImgProc.COLOR_RGBA2BGR;// RGBA to BGR 格式
ImgProc.COLOR_BGRA2GRAY;// BGRA to GRAY 格式
ImgProc.COLOR_RGB2HSV;// RGB to HSV格式 H的范圍值是0-180
ImgProc.COLOR_RGB2HSV_FULL;// RGB to HSV_FULL格式 H的范圍值是0-360 (PS:FULL獲取更大的精度,消耗更多的內(nèi)存)
其他的就不介紹了,命名中的2代表to。然后將左邊的顏色格式轉(zhuǎn)為右邊的顏色格式而已。
3. 通道分解和合成
我們?nèi)绻氩僮魍ǖ?。有很多方法,最?jiǎn)單的是我們直接遍歷然后修改通道參數(shù):
Mat det;
double [] temp;
for(int y=0;yfor(int x=0;x temp = det.get(x,y);
//根據(jù)通道情況,修改值
}
}
或者,我們直接修改指定位置的顏色值:mat.put(x,y,temp);
而我們?nèi)绻肱酷槍?duì)通道進(jìn)行操作,可以使用OpenCV提供的算法:
Core.split(); //分解通道
Core.merge(); //合成通道
Core.mixChannels(); //通道拆分復(fù)制 上面兩個(gè)分解和合成是該函數(shù)的一種特例場(chǎng)景。
下面來(lái)介紹這三個(gè)方法的傳值:
Core.split(Mat m, Listmv)
//Mat m :需要進(jìn)行通道分解的源Mat
//Listmv: 將源Mat的每個(gè)通道拆解為單通道的Mat,我們?nèi)绻苯訉⒃揕ist中的Mat進(jìn)行顯示將會(huì)全部是灰色的(因?yàn)槭菃瓮ǖ懒耍?/pre> 使用:
ListdefList=new ArrayList<>();
Core.split(rgba,defList);
for(Mat mat:defList){
//我們得到的都是單通道的Mat。 如果直接轉(zhuǎn)Bitmap顯示 將只會(huì)看到灰度圖
}我們?nèi)绻胫幌肟吹組at中的紅色通道的效果,而不是看灰度圖。該怎么處理?
需要結(jié)合split方法和merge方法一起使用
Core.merge(Listmv, Mat dst)
//Listmv: 需要合并的Mat的集合,會(huì)將全部的mat的通道合并到dst中去 List中的Mat 必須寬高相同,
//dst:輸出的Mat:它的寬高必須和List中的Mat的寬高相同。而通道數(shù)會(huì)是List中所有Mat的通道數(shù)的總和使用:將上面split拆解的Mat進(jìn)行合并
//創(chuàng)建單通道 CvType.CV_8UC1
Mat blackMat = new Mat(rgba.size(), CvType.CV_8UC1, new Scalar(0)); //繪制一個(gè)全黑的Mat
ListmergeList = new ArrayList<>();
//創(chuàng)建一個(gè)3通道的 Mat對(duì)象
Mat dst = new Mat(rgba.size(), CvType.CV_8UC3);
mergeList.add(blackMat); //B 通道黑色
mergeList.add(blackMat); //G 通道黑色
mergeList.add(defList.get(0));// R通道
Core.merge(mergeList, dst);最終我們得到的dst就是一個(gè)三通道的圖像了,只有R通道有值。(圖片是BGR的順序存儲(chǔ)的)
4. 總結(jié)
到這里關(guān)于通道的介紹就結(jié)束了。以上內(nèi)容基于自己的理解和驗(yàn)證。在openCV4.6 SDK版本,java開發(fā)環(huán)境下進(jìn)行的驗(yàn)證。
文章標(biāo)題:一文弄明白OpenCVMat中通道channels的作用
瀏覽地址:http://m.fisionsoft.com.cn/article/dpgjcgj.html


咨詢
建站咨詢
