教程 | 攝影愛好者玩編程:利用Python和OpenCV打造專業級長時曝光攝影圖

 2017-10-08 13:12:00.0

原標題:教程 | 攝影愛好者玩編程:利用Python和OpenCV打造專業級長時曝光攝影圖

選自pyimagesearch

參與:乾樹、蔣思源

在本文中,我們將學習如何使用 OpenCV 和圖像處理技術來模擬長時曝光圖像。爲了模擬長時曝光,我們採用了對一組圖像取平均值的幀平均法。機器之心對該教程進行了簡要的介紹。

長時曝光是攝影師最喜歡的攝影技術之一,運用長時曝光技術可以拍出展示時光流逝的圖片,而這是傳統技術難以企及的。我們經常使用這種技術表達流光夜景或柔順的流水。優秀的長時曝光作品是攝影師對快門速度、光圈大小和 ISO 感光度的完美把控,那麼我們如何使用 Python 和 OpenCV 庫來實現這種長時曝光的效果呢?

使用長時曝光技術後,水流變得如絲般光滑,夜空中的星星也隨着地球的旋轉留下一道光線軌跡,車頭/尾燈成爲了一束光帶。

長時曝光技術效果酷炫,但爲了拍到這種類型的鏡頭,我們需要學習一些系統方法:把相機放在三腳架上,應用各種濾鏡,計算曝光值等。更不用說,我們需要成爲一名熟練的攝影師!

作爲一名計算機視覺研究員和程序員,本文作者知道很多關於圖像處理的知識。雖然他是個菜鳥攝影師,但有一種通過應用多幀圖像平均法來模擬長時曝光效果的方法。通過計算在特定時間內拍攝的圖像的平均值,我們可以(有效)模擬長時間曝光效果。

而且由於視頻實際上是一系列的圖像,我們可以通過計算視頻中的所有幀的平均值來實現長時曝光效果。如此得到的是令人驚歎的長時曝光效果。

用 OpenCV 和 Python 實現長時曝光效果

這篇文章分爲三部分。在本文的第一部分,我們將討論如何通過幀平均法來模擬長時間曝光效果。隨後我們將編寫爲輸入視頻創建長時曝光效果的 Python 和 OpenCV 代碼。最後,我們將在一些樣例視頻上使用我們的代碼,以創建酷炫的長時曝光圖像。

通過多幀圖像平均法模擬長時曝光效果

通過平均數模擬長時曝光的想法由來已久。事實上,如果我們去瀏覽熱門的攝影網站,就會找到有關如何使用相機和三腳架手動實現這類效果的教程。

我們今天的目標是簡單地實現這種方法,所以我們使用 Python 和 OpenCV 自動爲輸入視頻創建長時曝光效果的圖像。給定一個輸入視頻,我們將計算所有幀的平均值(加權平均)以創建長時曝光效果。

注意:我們也可以使用多個連續圖像創建這種長時曝光效果,但是由於視頻的實質是一系列圖像,因此使用視頻演示此技術更容易。在將此技術應用到自定義圖像時,請牢記這一點。我們看到,代碼並不複雜,並且在應用於使用三腳架捕獲的視頻時(不要抖動相機)效果很好。

OpenCV 實現模擬長時曝光效果

我們首先創建一個名爲 long_exposure.py 的新文件,然後插入以下代碼:

# import the necessary packagesimport argparseimport imutilsimport cv2 # construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-v", "--video", required=True, help="path to input video file")ap.add_argument("-o", "--output", required=True, help="path to output'long exposure'")args = vars(ap.parse_args())

2-4 行導入軟件包,因此我們需要預先安裝 Imutils 和 opencv。如果你沒有安裝 imutils 模塊,可以通過 pip 安裝:

$ pip install --upgrade imutils

如果你的電腦沒有安裝配置 OpenCV,那麼請自行搜索 OpenCV 3 的安裝教程,並選擇適合你係統的安裝方式。

我們在 7-12 行解析命令行參數。

  • --video : 視頻文件目錄路徑

  • --output : 輸出「長時曝光」圖像的路徑+文件名

接下來執行一些初始化步驟:

# initialize the Red, Green, and Blue channel averages, along with# the total number of frames read from the file(rAvg, gAvg, bAvg) = (None, None, None)total = 0

# open a pointer to the video fileprint("[INFO] opening video file pointer...")stream = cv2.VideoCapture(args["video"])print("[INFO] computing frame averages (this will take awhile)...")

我們在第 16 行初始化 RGB 通道平均值,稍後會將其合併到最終的長時曝光圖像中。我們還初始化了第 17 行的總幀數。

對於本教程,我們正在使用包含所有幀的視頻文件,因此有必要在 21 行創建一個捕獲視頻流的文件指針。

現在我們進入計算平均值的循環語句中:

# loop over frames from the video file streamwhile True: # grab the frame from the file stream (grabbed, frame) = stream.read() # if the frame was not grabbed, then we have # reached the end of the sfile

if not grabbed:

break # otherwise, split the frmae into its respective channels (B, G, R) = cv2.split(frame.astype("float"))

在循環語句中,我們將從流中捕獲幀(27 行),並將幀各自分解到對應的 BGR 通道變量(35 行)。請注意循環語句退出條件 :如果未從視頻文件流的末尾抓取幀,我們將退出循環(31 行和 32 行)。

我們將在循環語句的其它部分執行平均值計算:

# if the frame averages are None, initialize them

if rAvg is None: rAvg = R bAvg = B gAvg = G # otherwise, compute the weighted average between the history of # frames and the current frames

else: rAvg = ((total * rAvg) + (1 * R)) / (total + 1.0) gAvg = ((total * gAvg) + (1 * G)) / (total + 1.0) bAvg = ((total * bAvg) + (1 * B)) / (total + 1.0) # increment the total number of frames read thus far total += 1

如果這是第一次迭代,我們在第 38-41 行上將 RGB 的初始平均值設置爲抓取的第一幀的通道值(if 語句僅在第一次迭代時執行此操作)。

否則,我們將計算 45-48 行上抓取的圖像每個通道的平均值。平均值計算非常簡單,我們將總幀數乘以通道平均值,加上相應的通道,然後將該結果除以浮點型總幀數(我們將分母總數加一,因爲生成的是一個新幀)。我們將計算結果存儲在相應的 RGB 通道平均值數組中。

最後,我們增加總幀數,以便能夠保持運行時平均值(第 51 行)。一旦我們遍歷完視頻文件中的所有幀,我們就可以將(平均)通道值合併成一個新圖像並將其寫入磁盤:

# merge the RGB averages together and write the output image to diskavg = cv2.merge([bAvg, gAvg, rAvg]).astype("uint8")cv2.imwrite(args["output"], avg) # do a bit of cleanup on the file pointerstream.release()

在 54 行,我們使用 cv2.merge 函數,同時指定了列表中的每個圖像的通道平均值。因爲這些數組包含浮點數(它們是所有幀的平均值),所以我們需要使用 astype("uint8") 函數將像素值轉換爲 [0-255] 的整數。

我們使用命令行參數 path + filename 在隨後的第 55 行中將 avg 圖像寫入磁盤。我們也可以通過 cv2.imshow 函數將圖像顯示在屏幕上,但是由於這會花費大量的 CPU 資源來處理視頻文件,所以我們只是將圖像保存到磁盤以便進一步查看。

該腳本的最後一步是通過釋放視頻流指針(58 行)來清空內存。

長時曝光效果與 OpenCV 實現對比

我們通過處理三個示例視頻來測試腳本效果。請注意,每個視頻均由安裝在穩定性良好的三腳架上的相機拍攝。

請注意所用視頻非作者本人拍攝,但都得到原作者的授權許可; 因此,本文作者並不能提供除源代碼之外的視頻資源下載。不過,如果你想重現作者的實驗結果,請參考我提供的原始視頻的鏈接。

我們的第一個示例是 15 秒鐘的水衝石頭的視頻,下面的視頻中包含了一個樣本幀:

視頻地址:https://videohive.net/item/mountain-river-water-and-stones-01/16602591

圖 1 :河水衝擊石頭的樣本幀

我們只需執行以下命令以實現長時曝光效果。

$ time python long_exposure.py --video videos/river_01.mov --output river_01.png [INFO] opening video file pointer...[INFO] computing frame averages (this will take awhile)... real 2m1.710suser 0m50.959ssys 0m40.207s

圖2:通過 Python 和 OpenCV 運用平均幀法實現的 15 秒的河水長時曝光效果圖。

注意水是如何由平均法處理而得到絲滑的效果。我們繼續河流的第二個例子,再次得到一幅蒙太奇效果圖如下:

圖 3: 另一條河流的樣本幀

以下命令用於生成長時曝光效果圖:

$ time python long_exposure.py --video videos/river_02.mov --output river_02.png [INFO] opening video file pointer...[INFO] computing frame averages (this will take awhile)... real 0m57.881suser 0m27.207ssys 0m21.792s

圖 4:第二條河流的絲滑的長時曝光效果圖(由 OpenCV 創建)

注意靜止的岩石是如何保持原狀,但是湍急的河水被平均化爲連續的圖片,從而模擬出長時曝光效果。

最後一個例子是我最喜歡的,因爲水的顏色令人讚歎,它使水和森林交相輝映:

圖 5:激流穿越森林的樣本幀

當用 OpenCV 產生長時曝光效果時,它會給你一種超現實的夢幻般的感覺:

$ time python long_exposure.py --video videos/river_03.mov --output river_03.png [INFO] opening video file pointer...[INFO] computing frame averages (this will take awhile)... real 3m17.212suser 1m11.826ssys 0m56.707s

圖 6:通過使用 Python 和 OpenCV 創建的夢幻般的長時曝光效果圖。

才外,我們還可以考慮通過有規律的間隔從輸入,從視頻中對幀進行採樣而不是對所有幀取平均值來構造不同的輸出。

總結

在本文中,我們學習瞭如何使用 OpenCV 和圖像處理技術來模擬長時曝光圖像。爲了模擬長時曝光,我們採用了對一組圖像取平均值的幀平均法。我們假設輸入圖像/視頻是使用固定的相機拍攝的(否則產生的輸出圖像會失真)。雖然這並非真正的「長時曝光」,但是效果上是極其(視覺上)相似的。更重要的是,這允許你應用長時曝光效果,而不需要成爲專家攝影師或購買昂貴的相機、鏡頭和濾鏡。

原文鏈接:https://www.pyimagesearch.com/2017/08/14/long-exposure-with-opencv-and-python/

本文爲機器之心編譯,轉載請聯繫本公衆號獲得授權。

責任編輯:

文章來源:機器之心