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