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

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


咨詢
建站咨詢
