用OpenCV合成PNG和JPG圖片

open-cv

最近產品有了一個天才的想法,做一個影集類似的功能,前面用圖片製作影像、合成音頻的操作都還挺順利,但是到了給視頻添加特效的時候就遇到了困難。

以前使用Pr或繪聲繪影的時候就在想,這些軟件背後的代碼是什麼樣的呢?看來這一次我自己也可以親手體驗一番了。

這次主要遇到了兩個問題:

  • 在圖片間插入過場動畫 (這一篇將不會講到這個)
  • 在視頻開頭添加一個半透明的幾何圖案

圖片合成

Google了一大票答案,很容易得出答案,OpenCV提供了addWeighted接口來做圖片合成的事情。遂從手機上扒下來兩張圖來試試。

圖一 ( 4032 x 1884 )
在這裏插入圖片描述
圖二 ( 1126 x 1122 )
在這裏插入圖片描述

    # video.py
    import cv2

    view1 = cv2.imread('view1.jpg')
    view2 = cv2.imread('view2.jpg')
    # addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=None)
    # alpha/beta 對應兩張圖片的透明度, 0是完全透明 1是完全不透明
    view = cv2.addWeighted(view1, 0.7, view2, 0.5, 0)
    cv2.imwrite('view.jpg', view)

運行一下,呀,報錯了

Traceback (most recent call last):
  File "video.py", line 270, in <module>
    view = cv2.addWeighted(view1, 0.7, view2, 1, 0)
cv2.error: OpenCV(3.4.2) /io/opencv/modules/core/src/arithm.cpp:659: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function 'arithm_op'

通過報錯信息,得知待合成圖片的尺寸和通道必須要相等,這個尺寸好理解,通道是啥意思呢?

修改圖片尺寸

修改一下上面的代碼,使它變成

    # video.py
    import cv2

    view1 = cv2.imread('view1.jpg')
    width = int((4032 - 1126) / 2)
    height = int((1884 - 1122) / 2)
    # 暴力裁剪
    # TODO: 這裏有更好的裁剪方案
    view1 = view1[height:height + 1122, width:width + 1126]
    view2 = cv2.imread('view2.jpg')

    view = cv2.addWeighted(view1, 0.7, view2, 0.5, 0)
    cv2.imwrite('view.jpg', view)

成品

view.jpg ( 1126 x 1122 )
在這裏插入圖片描述

帶Alpha通道的圖片和普通照片的合成

合成完圖片後,產品站在我身後,推了推眼鏡,發現事情並不簡單。

“給你一個框,給我放到圖片裏去”

背景實際上是透明的,這個黑色是在CSS中添加的,方便顯示
在這裏插入圖片描述

我琢磨着,兩張圖的尺寸相同應該就能合成成一張圖了吧!但是正如上文所提到的,圖片中的通道數和也必須要一致才能調用addWeighted方法進行合成。

    # video.py
    import cv2

    # 使用cv2.IMREAD_UNCHANGED 將會保留 PNG的Alpha通道
    # 而直接讀取PNG也可以進行圖像混合,不過這種情況不在本次的討論中
    blank = cv2.imread('blank.png', cv2.IMREAD_UNCHANGED)
    print(blank.shape) # (756, 567, 4)

    view1 = cv2.imread('view1.jpg')
    width = int((4032 - 756) / 2)
    height = int((1884 - 567) / 2)
    # 合適的裁剪
    view1 = view1[height:height + 756, width:width + 567]
    print(view1.shape) # (756, 567, 3)

由於通道不相等,兩張圖片並不能合成爲一張圖片,我們可以

  • 去掉blank的alpha通道
  • 爲view1增加一條alpha通道

這裏,我選擇的是第二種方法

    # video.py
    import cv2
    import numpy

    # 實現細節
    b_channel, g_channel, r_channel = cv2.split(view1)
    # 添加alpha通道
    alpha_channel = numpy.ones(b_channel.shape, dtype=b_channel.dtype) * 50
    view1 = cv2.merge((b_channel, g_channel, r_channel, alpha_channel))

    print(view1) # (756, 567, 4)

成品
在這裏插入圖片描述


原文地址 >> https://code.evink.me/2018/11/post/mix-png-and-jpg-use-OpenCV/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章