用OpenCV合成PNG和JPG图片

用OpenCV合成PNG和JPG图片_第1张图片
open-cv

最近产品有了一个天才的想法,做一个影集类似的功能,前面用图片制作影像、合成音频的操作都还挺顺利,但是到了给视频添加特效的时候就遇到了困难。

以前使用Pr或绘声绘影的时候就在想,这些软件背后的代码是什么样的呢?看来这一次我自己也可以亲手体验一番了。

这次主要遇到了两个问题:

  • 在图片间插入过场动画 (这一篇将不会讲到这个)
  • 在视频开头添加一个半透明的几何图案

图片合成

Google了一大票答案,很容易得出答案,OpenCV提供了addWeighted接口来做图片合成的事情。遂从手机上扒下来两张图来试试。

图一 ( 4032 x 1884 )


用OpenCV合成PNG和JPG图片_第2张图片
在这里插入图片描述

图二 ( 1126 x 1122 )


用OpenCV合成PNG和JPG图片_第3张图片
在这里插入图片描述
    # 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 
    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 )


用OpenCV合成PNG和JPG图片_第4张图片
在这里插入图片描述

带Alpha通道的图片和普通照片的合成

合成完图片后,产品站在我身后,推了推眼镜,发现事情并不简单。

“给你一个框,给我放到图片里去”

背景实际上是透明的,这个黑色是在CSS中添加的,方便显示


用OpenCV合成PNG和JPG图片_第5张图片
在这里插入图片描述

我琢磨着,两张图的尺寸相同应该就能合成成一张图了吧!但是正如上文所提到的,图片中的通道数和也必须要一致才能调用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)

成品


用OpenCV合成PNG和JPG图片_第6张图片
在这里插入图片描述

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

你可能感兴趣的:(用OpenCV合成PNG和JPG图片)