攝影愛好者玩編程:利用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 file
print("[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 disk
avg = cv2.merge([bAvg, gAvg, rAvg]).astype("uint8")
cv2.imwrite(args["output"], avg)
# do a bit of cleanup on the file pointer
stream.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.710s
user 0m50.959s
sys 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.881s
user 0m27.207s
sys 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.212s
user 1m11.826s
sys 0m56.707s
圖 6:通過使用 Python 和 OpenCV 創建的夢幻般的長時曝光效果圖。
才外,我們還可以考慮通過有規律的間隔從輸入,從視頻中對幀進行採樣而不是對所有幀取平均值來構造不同的輸出。
總結
在本文中,我們學習了如何使用 OpenCV 和圖像處理技術來模擬長時曝光圖像。為了模擬長時曝光,我們採用了對一組圖像取平均值的幀平均法。我們假設輸入圖像/視頻是使用固定的相機拍攝的(否則產生的輸出圖像會失真)。雖然這並非真正的「長時曝光」,但是效果上是極其(視覺上)相似的。更重要的是,這允許你應用長時曝光效果,而不需要成為專家攝影師或購買昂貴的相機、鏡頭和濾鏡。
※從大間隔分類器到核函數:全面理解支持向量機
※自動駕駛貨車「賽道」擁擠,這家年輕公司如何讓卡車穿越美國?
※AI 學習的未來更多取決於先天還是後天?
※利用達爾文的理論學習遺傳演算法
TAG:機器之心 |