官术网_书友最值得收藏!

1.2 圖像的基本操作

1.2.1 數字圖像的表示

我們在電子設備上看到的圖像都可以稱為數字圖像,例如圖1-2所示的Lena圖像。

圖1-2 Lena的數字圖像

對計算機來說,這幅圖像只是一些亮度不同的點。一幅尺寸為M×N的圖像可以用M×N的矩陣(即M×N個點)表示,如圖1-3所示。每個矩陣元素代表一個像素,元素的值表示這個位置圖像的亮度,一般來說,值越大該點就越亮。放大圖1-3(a)中白色方框區域可得到圖1-3(b)所示效果,對應的像素的值為圖1-3(c)中的值。通常,灰度圖像用2維矩陣M×N表示,彩色(多通道)圖像用3維矩陣M×N×3表示。對于圖像顯示來說,一般用無符號8位整數來表示像素亮度,取值范圍為[0, 255]。

      (a)                        (b)                        (c)

圖1-3 數字圖像的表示

圖像數據按照自左向右、自上向下的順序存儲在計算機內存中,即以圖像的左上角為原點(也有自左向右、自下向上的順序,即以圖像的左下角為原點)。圖1-4表示的是單通道灰度圖像數據在計算機中的存儲順序,Iij代表第i行第j列的像素值。圖1-5表示的是3通道BGR彩色圖像數據在計算機中的存儲順序,每個像素用3個值表示,即。需要說明一下,OpenCV中RGB彩色圖像的通道順序為BGR。

圖1-4 單通道灰度圖像數據在計算機中的存儲順序

圖1-5 3通道BGR彩色圖像數據在計算機中的存儲順序

1.2.2 圖像文件的讀寫與顯示

OpenCV提供了函數cv.imread()、cv.imshow()和cv.imwrite()來處理圖像文件的讀取、顯示和寫入。

1. 圖像文件的讀取

使用cv.imread()函數將圖像文件讀入內存:

retval = cv.imread(filename[, flags])

其中的主要參數介紹如下。

filename:要讀取的圖像文件的文件名。

flags:控制如何讀入圖像文件的標志。flags的取值和含義如表1-1所示。

retval:讀入的圖像數據。

表1-1 參數flags的取值和含義

flags的默認值為cv.IMREAD_COLOR,即將讀入的圖像轉換為3通道BGR圖像數據。假如圖像文件為單通道的灰度圖像,讀入后會被強制轉換為3通道。cv.IMREAD_GRAYSCALE則返回單通道圖像數據,假如圖像文件為多通道圖像,讀入后會被強制轉換為單通道圖像。

cv.imread()支持多種格式圖像文件的讀取,OpenCV支持讀取的圖像文件格式如表1-2所示。

表1-2 OpenCV支持讀取的圖像文件格式

注意:想要OpenCV支持某種圖像文件格式,需要有對應的文件格式庫。只有在編譯OpenCV時添加了相應的庫,安裝后OpenCV才能支持此格式。

2. 圖像文件的顯示

成功讀取圖像文件后,可以使用OpenCV提供的GUI(Graphical User Interface,圖形用戶界面)用cv.imshow()將圖像在窗口中顯示出來,如圖1-6所示。

圖1-6 OpenCV圖像在窗口顯示

cv.imshow(winname, mat)

其中的主要參數介紹如下。

winname:圖像顯示窗口的名稱。

mat:要顯示的圖像數據。

前面提到對于圖像顯示來說,一般用無符號8位整數,取值范圍為[0, 255]。根據mat的數據類型,cv.imshow()顯示圖像時會進行以下操作。

如果mat是8位無符號整數,則直接顯示。

如果mat是16位無符號整數,則像素值域會做[0, 255*256]到[0, 255]的映射。

如果mat是32位或64位浮點數,則像素值域會做[0, 1]到[0, 255]的映射。

如果mat是32位整數,則需要用戶根據應用上下文預先進行將像素值域映射到[0, 255]的處理。

通過函數cv.imshow()生成的窗口會根據顯示的圖像自動調整大小,用戶不能手動改變窗口大小。如果想改變窗口大小,可以使用OpenCV提供的另一個函數cv.namedWindow()來生成窗口。

cv.namedWindow(winname[, flags])

其中的主要參數介紹如下。

winname:窗口名稱。

flags:窗口的屬性。flags值對應的窗口屬性如表1-3所示。

表1-3 flags值對應的窗口屬性

 flags的默認值為 cv.WINDOW_AUTOSIZE|cv.WINDOW_KEEPRATIO|cv.WINDOW_GUI_EXPANDED。

調用函數cv.imshow()后還需要緊接著調用函數cv.waitKey()來執行GUI的housekeeping任務,這樣才能實際顯示圖像和響應鼠標、鍵盤事件,否則不會顯示圖像且窗口可能被鎖住。函數cv.waitKey()的功能是等待鍵盤按鍵按下。

retval = cv.waitKey([delay])

其中的主要參數介紹如下。

delay:等待鍵盤事件的時間,單位為ms;如果值小于或等于0,則窗口會一直等待鍵盤按鍵按下。默認值為0。

retval:如果指定的時間內沒有按鍵按下,則返回-1,否則返回被按下按鍵的ASCII(American Standard Code for Information Interchange,美國信息交換標準代碼)。

函數cv.destroyWindow(winname)和cv.destroyAllWindows()用于銷毀生成的窗口。

3. 圖像文件的寫入

將圖像數據寫入文件,可使用cv.imwrite()函數:

retval = cv.imwrite(filename, img[, params])

其中的主要參數介紹如下。

filename:文件名。

img:待寫入的圖像數據。

params:指定文件格式。OpenCV可保存的文件格式如表1-4所示。

表1-4 OpenCV可保存的文件格式

存儲的圖像格式根據filename中的擴展名來決定,同時并不是所有的img都可以存為圖像文件,目前只支持8位單通道和3通道(顏色順序為BGR)矩陣。如果img為16位無符號整數類型,則需要存儲為PNG、JPEG 2000或TIFF格式;若為32位浮點數類型,則需要存儲為PFM、TIFF、OpenEXR或Radiance HDR格式。如果某格式的圖像矩陣不支持保存為圖像文件,可以先用cv.convertTo()函數或者cv.cvtColor()函數將矩陣轉為可以保存的格式,再保存。另外需要注意的是,在保存文件時如果文件名已經存在,cv.imwrite()函數不會進行提醒,將直接覆蓋以前的文件。

下面的例子展示了如何讀入一幅彩色圖像,讀入的同時將原始圖像轉換為灰度圖像,在窗口顯示灰度圖像,并將灰度圖像保存到文件中。

import cv2 as cv
 
def main():
 
    # 讀入圖像, 同時轉換為灰度圖像
    im_grey = cv.imread("lena.jpg", cv.IMREAD_GRAYSCALE)
    
    # 將灰度圖像寫入文件
    cv.imwrite("lena_grey.jpg", im_grey)
 
    # 顯示灰度圖像
    cv.imshow("Lena", im_grey)
    cv.waitKey()
    # 銷毀窗口
    cv.destroyAllWindows()
 
 
if __name__  == '__main__':
    main()

將lena.jpg放在與例子相同的目錄下,運行該例子的代碼后,lena_grey.jpg將會出現在此目錄。讀入的原始圖像如圖1-2所示,轉為灰度圖像的顯示窗口如圖1-7所示。

圖1-7 灰度圖像顯示窗口

1.2.3 視頻文件的讀寫與顯示

在介紹OpenCV如何讀寫與顯示視頻文件之前,先介紹一下編解碼器(codec)。如果是圖像文件,我們可以根據文件擴展名得知圖像的格式,但是此經驗并不能推廣到視頻文件中,因為視頻文件的格式主要由壓縮算法決定。壓縮算法稱為編碼器(coder),解壓算法稱為解碼器(decoder),編解碼算法統稱為編解碼器(codec)。視頻文件能否讀寫,關鍵看是否有相應的編解碼器。編解碼器的種類非常多,常用的有MJPG、XVID、DIVX等。視頻文件的擴展名(如avi等)往往只能表示這是一個視頻文件,我們并不能由其得知實際的編解碼器。

OpenCV提供了兩個類來處理視頻文件的讀寫。讀視頻文件的類是VideoCapture,寫視頻文件的類是VideoWriter。

VideoCapture類既可以從視頻文件讀取圖像,也可以從攝像頭讀取圖像,可以使用該類的構造函數打開視頻文件或者攝像頭。如果VideoCapture類對象已經創建,可以使用cv.VideoCapture.open()函數打開,該函數會自動調用cv.VideoCapture.release()函數,先釋放已經打開的視頻文件,再打開新視頻文件。如果要讀取一幀圖像,可以使用cv.Video Capture.read()函數。

打開攝像頭:

cv.VideoCapture(index[, apiPreference])

其中的主要參數介紹如下。

index:視頻捕獲設備的ID,0表示用默認后端打開默認攝像頭。

apiPreference:在有多個視頻捕獲后端時指定一個后端,如cv.CAP_DSHOW、cv.CAP_MSMF、cv.CAP_V4L等。默認值為cv.CAP_ANY。

打開視頻文件:

cv.VideoCapture(filename[, apiPreference])

其中的主要參數介紹如下。

filename:視頻文件,它可以是以下類別。

視頻文件名,如video.avi。

圖像序列,如img_%02.jpg,會逐一讀取圖像文件img_00.jpg、img_01.jpg、img_ 02.jpg……

視頻流的URL(Uniform Resource Locator,統一資源定位符)。

gst-launch格式的GStreamer pipeline字符串。

apiPreference:在有多個視頻捕獲后端時指定一個后端,如cv::CAP_FFMPEG、cv::CAP_IMAGES、cv::CAP_DSHOW。默認值為cv.CAP_ANY。

下面的例子演示了使用VideoCapture類讀視頻文件。

import sys
import cv2 as cv
 
 
def main():
    # 打開第一個攝像頭
    #cap = cv.VideoCapture(0)
    # 打開視頻文件
    cap = cv.VideoCapture("slow_traffic_small.mp4")
 
    # 檢查是否打開成功
    if cap.isOpened() == False:
        print('Error opening the video source. ')
        sys.exit()
 
    while True:
        # 讀取1幀視頻,存放到im
        ret, im = cap.read()
        if not ret:
            print('No image read. ')
            break
 
        # 顯示視頻幀
        cv.imshow('Live', im)
        # 等待30ms,如果有按鍵按下則退出循環
        if cv.waitKey(30) >= 0:
            break
 
    # 銷毀窗口
    cv.destroyAllWindows()
    # 釋放cap
    cap.release()
 
if __name__ == '__main__':
main()

圖1-8為讀取1幀視頻后窗口顯示的效果。

圖1-8 讀取1幀視頻后窗口顯示的效果

OpenCV提供了VideoWriter類來創建視頻文件(寫視頻),在Linux系統中使用FFMPEG來寫視頻文件,Windows系統中使用FFMPEG、MSWF或者DSHOW,macOS系統中使用AVFoundation。與讀視頻文件不同的是,寫視頻文件需要在創建視頻時設置一系列參數,包括文件名、編解碼器、視頻幀率、視頻幀寬度和高度等。

首先創建VideoWriter類對象:

writer=cv.VideoWriter(filename, fourcc, fps, framesize[, iscolor])

其中的主要參數介紹如下。

filename:創建的視頻文件名。

fourcc:使用4個字符表示的編解碼器,可以是cv.VideoWriter_fourcc ('M', 'J', 'P','G')、cv.VideoWriter_fourcc('X','V',' I','D')、cv.VideoWriter_fourcc ('D',' I','V','X')等。編解碼器列表可以在MSDN[1](微軟的一個期刊產品)查詢。如果使用某種編解碼器無法創建視頻文件,請嘗試其他的編解碼器。


[1] 網址為https://docs.microsoft.com/en-us/windows/win32/medfound/video-fourccs

fps:視頻幀率。

framesize:視頻幀寬度和高度。

iscolor:如果值非0,編碼器將按彩色幀進行編碼;否則按灰度幀進行編碼。

writer:創建的VideoWriter對象。

然后使用函數cv.VideoWriter.writer()將視頻幀寫入文件:

cv.VideoWriter.write(image)

其中,image 表示待寫入的視頻幀數據,通常是BGR格式的彩色圖像。需要注意,image的尺寸必須與前面的framesize一致。

下面的例子演示了如何寫視頻文件。本示例將生成一個視頻文件,視頻的第0幀是一個白色的“0”,第1幀是個白色的“1”,以此類推,共100幀。生成視頻文件的播放效果如圖1-9所示。

import sys
import numpy as np
import cv2 as cv
 
def main():
    # 設置視頻幀的寬度和高度
    frame_size = (320, 240)
 
    # 設置視頻幀率
    fps = 25
 
    # 視頻編解碼格式
    fourcc = cv.VideoWriter_fourcc('M', 'J', 'P', 'G')
 
    # 創建writer
    writer = cv.VideoWriter("myvideo.avi", fourcc, fps, frame_size)
    # 檢查是否創建成功
    if writer.isOpened() == False:
        print("Error creating video writer.")
        sys.exit()
 
    for i in range(0, 100):
 
        # 設置視頻幀畫面
        im = np.zeros((frame_size[1], frame_size[0], 3), dtype=np.uint8)
 
        # 將數字繪制到畫面上
        cv.putText(im, str(i), (int(frame_size[0]/3), int(frame_size[1]*2/3)),                                 cv.FONT_HERSHEY_SIMPLEX, 3.0, (255, 255, 255), 3)
 
        # 保存視頻幀到文件myvideo.avi
        writer.write(im)
 
    # 釋放writer
    writer.release()
 
 
if __name__  == '__main__':
    main()

圖1-9 生成視頻文件的播放效果

主站蜘蛛池模板: 皋兰县| 白银市| 五大连池市| 长武县| 沾化县| 阳曲县| 北流市| 南江县| 江源县| 三原县| 无极县| 资中县| 灵台县| 榕江县| 谷城县| 乌鲁木齐市| 垦利县| 东乌珠穆沁旗| 白朗县| 观塘区| 湟中县| 七台河市| 独山县| 台东县| 临江市| 黎川县| 辽源市| 西盟| 文成县| 阿克苏市| 曲阜市| 姚安县| 高碑店市| 原阳县| 登封市| 和平县| 内江市| 永善县| 义乌市| 香港| 辽宁省|