什么是图像
圖像,尤其是數(shù)字圖像的定義,在岡薩雷斯的書中是一個二維函數(shù)f(x,y),x,y是空間平面坐標,幅值f是圖像在該點處的灰度或者強度。下面通過OpenCV中最常用的圖像表示方法Mat來看一下在計算機中是怎么定義圖像的。
Mat的定義
OpenCV在2.0之后改用C++實現(xiàn)了Mat類,從而代替了IplImage,不用再手動分配和釋放內(nèi)存。Mat其實是原來存放數(shù)組的,數(shù)組可以是單通道的也可以是多通道的。通過Mat我們可以存儲矢量、張量、點云、矩陣、灰度圖、彩色圖等。
Mat包含兩個部分:矩陣頭和指向矩陣元素數(shù)據(jù)的指針。
當我們定義一個Mat類型的變量,Mat a,這個a只是一個矩陣頭,它的大小是固定的,不隨矩陣(圖像)大小的變化而變化,它包含了矩陣的基本信息,矩陣多大,存放在哪里,怎么存放,還有引用的次數(shù)。
關(guān)于這個引用次數(shù),其實也是矩陣頭存在原因。因為矩陣可能很大,在復(fù)制和傳遞的過程中會占據(jù)很大的成本,所以我們其實只需要復(fù)制矩陣頭和指針,矩陣頭中的引用次數(shù)會根據(jù)復(fù)制或者銷毀而變化。cv::Mat b = a其實這種拷貝方式就是淺拷貝,兩個指向相同矩陣的變量,其中一個的變化會影響另外一個。如果想進行深拷貝,可以使用cv::Mat c = a.clone();或者a.copyTo(d);
Mat的使用
Mat的初始化
cv::Mat img(2,2,CV_8UC3,cv::Scalar(0,0,255));行列數(shù),元素類型和初始值。8UC3是最熟悉的,8bit的無符號三通道類型,0~255
Mat的輸入
cv::Mat imread(const string& filename,int flags=1)注意第二個參數(shù)ImreadModes,有13種枚舉類型,常用的是-1,0,1,對應(yīng)IMREAD_UNCHANGED? ,IMREAD_GRAYSCALE,IMREAD_COLOR
Mat的保存
Cv:: imwrite( const String& filename, InputArray img,const std::vector<int>& params = std::vector<int>());這里的filename和imread中的一樣。保存路徑中的filename的后綴名,即圖像的格式,和第三個參數(shù)有關(guān)。第三個參數(shù)是圖像格式的具體參數(shù),以int型的動態(tài)數(shù)組的形式給出,每兩個為一對,分別是參數(shù)名和參數(shù)值。(paramId_1, paramValue_1, paramId_2, paramValue_2, ... .)。For JPEG, it can be a quality from 0 to 100 (the higher is the better). Default value is 95.當格式是PNG時,參數(shù)決定壓縮級別(0到9),壓縮級別越高圖像占用的空間越小,默認是IMWRITE_PNG_STRATEGY_DEFAULT,當圖像數(shù)據(jù)由濾波預(yù)測得到,數(shù)據(jù)由small values構(gòu)成,使用IMWRITE_PNG_STRATEGY_FILTERED得到更好的效果;IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY使用Haffman編碼。
只有8bit單通道或者三通道的可以通過這個函數(shù)保存,三通道時顏色順序是BGR。Only 8-bit (or 16-bit unsigned (CV_16U) in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with 'BGR' channel order) images can be saved using this function.
當圖像格式是PNG(Portable Network Graphics),JPEG2000或者TIFF時可以是CV_16UC的。帶有透明度通道的PNG圖像也可以使用這個函數(shù)保存,通道順序是BGRA,完全透明Fully transparent pixels時,A=0,完全不透明fully opaque pixels時,A=255/65535
Mat的屬性:type depth step
img(3*4)的type是CV_16UC4,
Mat img(3, 4, CV_16UC4, Scalar_<uchar>(1, 2, 3, 4));cout << img << endl;cout << "dims:" << img.dims << endl;cout << "rows:" << img.rows << endl;cout << "cols:" << img.cols << endl;cout << "channels:" << img.channels() << endl;cout << "type:" << img.type() << endl;cout << "depth:" << img.depth() << endl;cout << "elemSize:" << img.elemSize() << endl;cout << "elemSize1:" << img.elemSize1() << endl;cout << "Step[0]:" << img.step[0] << endl;cout << "Step[1]:" << img.step[1] << endl;?圖像的維度,行列數(shù)很好理解。但是在多通道時需要注意,列數(shù)指的是元素的個數(shù),而元素可能有三通道,而在計算時很多地方習慣把通道展開,這樣得到一個通道數(shù)和列數(shù)的乘積,如int colNumber = outputimage.cols*outputimage.channels()。
Mat類型的type()返回一個int型的值,通過查表可以知道數(shù)據(jù)類型和通道數(shù)。depth和type類似,相比于type缺少了通道信息。
step[0]是其一行所占的數(shù)據(jù)字節(jié)數(shù)4 *4 * 16 / 8? = 32.Step得到的和step[0]是一樣的
step[1] 是一個元素所占的字節(jié)數(shù),img的一個元素具有4個通道,故:4 * 16 / 8 = 8
step返回的是一個MatStep類型的變量,MatStep通過重載運算符[]返回了size_t, size_t則是無符號int型的unsigned int。MatStep初始化后得到一個int型的數(shù)組,p = buf; p[0] = p[1] = 0;
Mat中一個uchar* data指向矩陣數(shù)據(jù)的首地址,而現(xiàn)在又知道了每一行和每一個元素的數(shù)據(jù)大小,就可以快速的訪問Mat中的任意元素了。
Add(M_{I,j})=M.data+M.step[0]*i+M.step[1]*j
如果將一層for循環(huán)變成列數(shù)乘通道數(shù),那么也可以寫為
Add(M_{I,j})=M.data+M.step[0]*i+ j
上面分析step是一個size_t[2],實際不是很正確,正確的來說step應(yīng)該是size_t[dims],dims是Mat的維度,所以對于上面的二維的Mat來說,step是size_t[2]也是正確的。
下面就對三維的Mat數(shù)據(jù)布局以及step
圖像格式和屏幕接口
三通道時差分之后占用357KB,使用單通道時126KB,但是還是大于原來的120KB,為什么呢,雖然做了差分,但是編碼都是8bit編碼,圖像大小沒有變化,圖像占用空間大小應(yīng)該也是一樣的。于是把原圖讀取進來之后直接保存,發(fā)現(xiàn)這樣子得到的是126KB。但是為什么把png圖像讀進來再保存成png,占用空間大小就變了呢?
首先來看一下PNG這種格式,它是一種無損壓縮的形式,無損壓縮即沒有丟失原始信息,可以完全恢復(fù)原來的格式。壓縮的原理是利用特殊的編碼將重復(fù)的數(shù)據(jù)進行了標記,同時不再是記錄每一個像素的彩色信息,而是進行索引,將顏色對應(yīng)到各個位置。PNG最為熟悉的地方是它支持透明效果,消除鋸齒邊緣?這在平面設(shè)計中是常用的。另外,PNG的英文名Portable Network Graphics表明它對于網(wǎng)絡(luò)傳輸做了優(yōu)化,什么優(yōu)化呢?在2G時代,看一張圖像往往是一行一行加載出來的,而在現(xiàn)在4G時代網(wǎng)速已經(jīng)快了很多,但是有時候還是不能馬上加載出一幅圖像,于是,借助PNG,可以得到更好的體驗:先顯示出一個基本的圖像的模糊版本,之后逐漸清晰起來。
與PNG聯(lián)系較密切的是GIF格式。因為GIF 中使用了LZW壓縮算法,所以GIF的使用需要向Unisys公司繳納專利費,這才有了PNG的推廣。GIF被人熟知主要是因為一些動態(tài)表情包,其實GIF也是一種無損壓縮算法,只不過GIF可以存放多張圖像,人們在顯示時將多張圖像依次讀取并顯示,就可以得到動畫效果。
之前提到的CV_8UC3就是標準的24位(BGR一共24bit)真彩色,可以表達2^24=1677萬種顏色,而人眼只能識別一千萬種。真彩色圖通常是指RGB 8:8:8,但在顯示器上顯示的顏色就不一定是真彩色,要得到真彩色圖像需要有真彩色顯示適配器,現(xiàn)在在PC上用的VGA適配器是很難得到真彩色圖像的。VGA(Video Graphics Adapter)接口,又叫D-sub接口,是D-subminiature的簡稱。顯卡所處理的信息最終都要輸出到顯示器上,而液晶顯示器如LCD之前的CRT顯示器只能接收模擬信號,所以就有了VGA標準,輸出模擬信號。VGA物理接口是梯形的,共3行15個針孔。VGA接口豎置的說明是集成顯卡,VGA接口橫置說明是獨立顯卡。
與VGA對應(yīng)的就是HDMI了,這是High Definition Multimedia Interface,高清多媒體接口,可以傳輸視頻和音頻數(shù)字信號。對比之下VGA只能傳輸視頻信號,音頻信號需要另外的連線。因為是HDMi設(shè)備可以接收數(shù)字信號,這樣就無需進行A/D、D/A轉(zhuǎn)換了,
說到接口就順便看一下日常使用的手機接口。
?
TypeA:即我們常見的標準USB大口,主流的可以分為USB2.0速度(幾十M/S)和USB3.0速度(上百M/S)
TypeB:常見于打印機以及帶觸摸和USB接口的顯示器,日常使用頻率低。但是Type-B的分支Micro B接口和Mini B是大多數(shù)舊款手機、學(xué)習機、數(shù)碼相機等的的接口格式。
MircoB分為MicroB 2.0和MicroB 3.0,MicroB 3.0更寬,所以可以兼容MicroB 2.0,一般用于移動硬盤,我也見過三星一款手機的耳機以此為接口。該接口過于扁長,多次插拔后故障率較高
?
Type-C:目前絕大多數(shù)手機的充電/數(shù)據(jù)接口,有些還同時是手機的耳機接口。
這里可以看到通過USB Type-C集成了HDMI的功能,既然HDMI可以同時傳輸視頻音頻,所以有些手機廠商取消了耳機接口,通過USB Type-C連接耳機。
后記:
OpenCV的官方文檔是值得仔細看的,不僅有代碼樣例還有很詳細的解讀,通過一些很具體而形象的例子可以快速理解圖像處理的知識。
Reference:
1.http://www.cnblogs.com/wangguchangqing/p/4016179.html
2.https://baijiahao.baidu.com/s?id=1611944986325018535&wfr=spider&for=pc
3.http://www.cnblogs.com/wangguchangqing/p/3841271.html
4.https://docs.opencv.org/3.4.0/d3/d63/classcv_1_1Mat.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
- 上一篇: 简单的线性回归实现模型的存储和读取
- 下一篇: Android之IPC机制