对视频剪辑应用灰度图像变换+Moviepy生成灰度视频处理遇到几个有意思的问题

2023-11-19

一、引言

最近在学习图像处理的《直方图处理》,对直方图均衡处理效果感觉非常有用。

以前学习Moviepy音视频剪辑时,用的卓别林的一个黑白视频片段,感觉视频的噪点比较多,画面也整体偏暗,不禁想看看如果对其进行直方图均衡会怎么样。如是开干,但进展并不很顺利,下面就来谈谈遇到的问题。

二、基础知识介绍

1、Moviepy的视频变换fl_image方法

由于是对视频图像进行灰度处理,因此需要逐帧读取视频帧,每帧应用直方图均衡。该视频变换处理有多种方法实现,老猿使用fl_image。

fl_image方法是对get_frame方法获取的帧进行变换的方法,本质上是Clip的fl方法在内容变换方面的一种变种和应用。

调用语法fl_image(self, image_func, apply_to=None)

参数说明

  • image_func:参数image_func是对剪辑帧进行图像变换的函数,带一个参数,参数就是要处理的帧,这个帧直接通过get_frame去获取,image_func函数的返回值为经过变换后的帧
  • apply_to:apply_to表示变换是否需要同时作用于剪辑的音频和遮罩,其值可以为’mask’、‘audio’、[‘mask’,‘audio’]

对比fl调用方法fl(self, fun, apply_to=None, keep_duration=True):

  • fl_image由于只变换内容,因此不涉及时间的变换,keep_duration就是默认为True
    image_func不带时间参数,这是因为系统默认调用get_frame(t)来获取帧,无需image_func带时间参数

  • fl_image本质上是执行如下语句来完成帧内容的变换:fl(lambda gf, t: image_func(gf(t)),
    apply_to)

更多关于Moviepy视频fl_image变换处理的介绍请参考《moviepy音视频剪辑:视频剪辑基类VideoClip的属性及方法详解》。

2、Moviepy彩色视频转黑白视频变换blackwhite函数

blackwhite函数用于将剪辑变成灰度剪辑,也就是将剪辑中的彩色像素灰度化。

调用语法blackwhite(clip, RGB = None, preserve_luminosity=True)

参数说明

  • clip:要处理的剪辑,通过fx或subfx调用时,会将调用者的实例对象self传入
  • RGB:浮点数三元组,用于设置RGB三种颜色的权重,缺省值为None,如果为None,则为1:1:1,如果设置为‘CRT_phosphor’,则RGB = [0.2125, 0.7154, 0.0721]
  • preserve_luminosity:preserve_luminosity用于控制是否保持亮度,如果保持亮度不变,则最终的RGB三个值相加为1。在这里的亮度luminosity不是lightness,实际上是对明度的度量,也称为灰阶值,是不同权重的R、G、B的组合值。实际上亮度是对颜色的明度(brightness)的一种度量
3、OpenCV的直方图均衡处理equalizeHist函数

OpenCV的直方图均衡处理非常简单,就是对需要处理的黑白图像执行cv2.equalizeHist函数,返回图像即为直方图均衡后的图像。

4、OpenCV的图像色系转换cvtColor

cv2.cvtColor是openCV提供的颜色空间转换函数。

调用语法cvtColor(src, code, dstCn=None)
其中:

  • src:要转换的图像
  • code:转换代码,表示从何种类型的图像转换为何种类型,如cv2.COLOR_BGR2GRAY就是将BGR格式彩色图像转换成灰度图片,具体转换代码请参考官网文档
  • dstCn:目标图像的通道数,如果为0表示根据源图像通道数以及转换代码自动确认

三、实现思路及处理视频内容

总体处理非常简单,就是加载视频剪辑后,对剪辑进行fl_image变换,变换参数中的处理函数就传递直方图均衡处理相关的函数。

原始视频是卓别林的一个黑白视频片段,下面是该段视频的2个截图:
在这里插入图片描述

四、实现过程及遇到的问题

1、直接在fl_image调用直方图均衡的equalizeHist函数

实现代码如下:

from moviepy.editor import *
import cv2

def test():
    clipV = VideoFileClip(r"F:\video\zbl1.mp4")
    newclip = clipV.fl_image(cv2.equalizeHist, apply_to=['mask'])
    newclip.write_videofile(r"F:\video\temp\zbl1.mp4")


test()

结果执行报错(很长的报错信息,仅截取关键部分):

File "C:\Program Files\Python38\lib\site-packages\moviepy\video\VideoClip.py", line 490, in <lambda>
    return self.fl(lambda gf, t: image_func(gf(t)), apply_to)
cv2.error: OpenCV(4.3.0) C:\projects\opencv-python\opencv\modules\imgproc\src\histogram.cpp:3439: error: (-215:Assertion failed) _src.type() == CV_8UC1 in function 'cv::equalizeHist'

这些信息说明直方图均衡处理的图像数据类型不对,因为涉及到了OpenCV的函数,在OpenCv-Python中无法深入分析,因此也没办法看出具体原因。

2、将equalizeHist函数再次封装后给fl_image调用

代码如下:

from moviepy.editor import *
import cv2
def flImg(img):
    imgNew = cv2.equalizeHist(img)
    return imgNew

def test():
    clipV = VideoFileClip(r"F:\video\zbl1.mp4")
    newclip = clipV.fl_image(cv2.equalizeHist, apply_to=['mask'])
    newclip.write_videofile(r"F:\video\temp\zbl1.mp4")

报错信息依旧,由于用flImg封装了cv2.equalizeHist,此时可以通过Debug跟踪flImg看到内部数据,居然发现img是三维数组,也即图像像素值是RGB格式,而不是灰度图格式。看样子虽然是个黑白视频,但格式是彩色视频格式?

3、将视频剪辑加载之后转成黑白视频再处理

好吧,黑白视频存放的是彩色格式,也许是因为视频保存格式控制的,那就把其先转成黑白视频,Moviepy有个这样变换函数blackwhite。

代码如下:

from moviepy.editor import *
import cv2

def flImg(img):
    imgNew = cv2.equalizeHist(img)
  
    return imgNew

def test():
    clipV = blackwhite(VideoFileClip(r"F:\video\zbl1.mp4"))
    newclip = clipV.fl_image(flImg, apply_to=['mask'])
    newclip.write_videofile(r"F:\video\temp\zbl1.mp4")


test()

结果还是报同样错,观察flImg参数img,居然还是RGB格式。黑白视频的帧是二维还是三维?让人一脸蒙圈!

4、强制图像转换为灰度图

好吧,老猿承认在黑白视频的帧数据认知上出问题了,黑白视频也是RGB格式,那只有对图像强制格式转换了,用OpenCV的cvtColor将RGB格式强制转换为灰度图。

代码如下:

from moviepy.editor import *
import cv2

def flImg(img):
    imgNew = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    imgNew = cv2.equalizeHist(imgNew)

    return imgNew

def test():
    clipV = blackwhite(VideoFileClip(r"F:\video\zbl1.mp4"))
    newclip = clipV.fl_image(flImg, apply_to=['mask'])
    newclip.write_videofile(r"F:\video\temp\zbl1_11.mp4")
    newclip.write_gif(r"F:\video\temp\zbl1.gif")


test()

这样处理后,执行没报错,但处理完的视频存在如下两个问题:
1、视频图像整体大小没变,但内容变成了同屏九窗播放模式:

在这里插入图片描述
2、视频播放速度是原视频的3倍左右,音频没变,导致视频的播放到1/3时长视频内容已经播放完成,然后视频就固定在最后一帧图像,音频还按原有节凑在播放。

总体来看,就是视频内容没有按照预定计划生成。为了查找问题,老猿做了如下处理:

  1. 将视频直接生成gif,gif是正常的;
  2. 去掉直方图均衡处理,只保留图像格式变换处理,还是存在问题;
  3. 去掉图像格式变换处理,flImg直接返回原图像,视频生成后是正常的。

考虑上述处理可以得出结论,问题出现与视频帧图像RGB转灰度图处理有关,结合前面彩色视频使用blackwhite转黑白视频后图像像素仍然是RGB格式的情况,老猿感觉是黑白视频的帧图像格式不是我理解的灰度图,而是RGB格式的图像。那这个过程到底该怎么处理呢?为此老猿查看了Moviepy的blackwhite的源代码:

def blackwhite(clip, RGB=None, preserve_luminosity=True):
    """ Desaturates the picture, makes it black and white.
    Parameter RGB allows to set weights for the different color
    channels.
    If RBG is 'CRT_phosphor' a special set of values is used.
    preserve_luminosity maintains the sum of RGB to 1."""
    if RGB is None:
        RGB = [1, 1, 1]

    if RGB == 'CRT_phosphor':
        RGB = [0.2125, 0.7154, 0.0721]

    R, G, B = 1.0 * np.array(RGB) / (sum(RGB) if preserve_luminosity else 1)

    def fl(im):
        im = (R * im[:, :, 0] + G * im[:, :, 1] + B * im[:, :, 2])
        a = np.dstack(3 * [im]).astype('uint8')
        return a

    return clip.fl_image(fl)

可以看到,该源代码是先将RGB像素值按照参数指定要求转换成灰度值,最后最将该灰度值复制3份作为返回图像的RGB值,因此这个处理实际上图像最终格式是RGB格式,但RGB的值都是对应的原RGB映射到的灰度值。

5、在帧图像变换时增加将灰度图变成RGB格式的灰度图处理

为了确保最终的黑白视频格式满足像素值为RGB格式要求,对灰度变换后的图像增加了将灰度值扩展成RGB格式的处理,在此用到了numpy的dstack函数。代码如下:

from moviepy.editor import *
import cv2
import numpy as np

def flImg(img):
    imgNew = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    imgNew = cv2.equalizeHist(imgNew)
    imgNew = np.dstack(3 * [imgNew]).astype('uint8')

    return imgNew


def test():
    clipV = VideoFileClip(r"F:\video\zbl1.mp4")

    newclip = clipV.fl_image(flImg, apply_to=['mask'])
    newclip.write_videofile(r"F:\video\temp\zbl1.mp4")


test()

经验证,这样处理后的视频输出文件变成了正常播放的视频,但说实话直方图均衡处理的效果并不很好,虽然视频总体变亮了,但不同帧之间图像的差异变大了,导致视频的画面连续变化较大。

五、小结

本文通过介绍将视频帧转换为灰度图像,再构建黑白视频的处理过程所遇到的问题及解决办法,确认了无论是从输入黑白视频的像素值还是将黑白视频输出到视频文件的处理过程来看,黑白视频的帧图像不是二维的灰度图,而是对应三维的彩色图像格式,其像素值为RGB三元组格式,只是R、G、B三个分量的值都是为对应灰度图的灰度值。

更多关于 Moviepy 的介绍请大家参考《Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载》。

如对文章内容存在疑问或需要相关资料,可在博客评论区留言,或关注:老猿Python 微信公号发消息咨询,可通过扫二维码加微信公众号。
在这里插入图片描述

写博不易,敬请支持:

如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!

关于老猿的付费专栏

  1. 付费专栏《https://blog.csdn.net/laoyuanpython/category_9607725.html 使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,对应文章目录为《 https://blog.csdn.net/LaoYuanPython/article/details/107580932 使用PyQt开发图形界面Python应用专栏目录》;
  2. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10232926.html moviepy音视频开发专栏 )详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/107574583 moviepy音视频开发专栏文章目录》;
  3. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初学者疑难问题集》为《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的伴生专栏,是笔者对OpenCV-Python图形图像处理学习中遇到的一些问题个人感悟的整合,相关资料基本上都是老猿反复研究的成果,有助于OpenCV-Python初学者比较深入地理解OpenCV,对应文章目录为《https://blog.csdn.net/LaoYuanPython/article/details/109713407 OpenCV-Python初学者疑难问题集专栏目录
  4. 付费专栏《https://blog.csdn.net/laoyuanpython/category_10762553.html Python爬虫入门 》站在一个互联网前端开发小白的角度介绍爬虫开发应知应会内容,包括爬虫入门的基础知识,以及爬取CSDN文章信息、博主信息、给文章点赞、评论等实战内容。

前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。

对于缺乏Python基础的同仁,可以通过老猿的免费专栏《https://blog.csdn.net/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习Python。

如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

老猿Python,跟老猿学Python!

☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对视频剪辑应用灰度图像变换+Moviepy生成灰度视频处理遇到几个有意思的问题 的相关文章

随机推荐

  • 《学习篇》学会这18个常用ROS命令集合就能入门ROS了

    常用ROS命令概述 ROS常用命令可以按照其使用场景分为ROSshell命令 ROS执行命令 ROS信息命令 ROS catkin命令与ROS功能包命令 虽然很难从一开始就很熟练地使用所有的命令 但是随着使用的次数增多 你会发现常用的几个R
  • rabbitmq queue_declare arguments参数注释

    说明 官方文档 在创建queue时可以指定很多参数 可以限制队列的大小 消息的死信时间 优先级等等 queue消息条数限制 x max length 该参数是非负整数值 官方文档 限制加入queue中消息的条数 先进先出原则 超过10条后面
  • JavaScript重写Symbol(Symbol.iterator)实现迭代器(1)

    iterator迭代 做的跟java集合迭代差不多就行了 示例图 h1 对象遍历重写iterator接口1 h1
  • HTML5无刷新修改URL:利用 History API 无刷新更改地址栏

    为什么80 的码农都做不了架构师 gt gt gt HTML5 新增的历史记录 API 可以实现无刷新更改地址栏链接 配合 AJAX 可以做到无刷新跳转 简单来说 假设当前页面为renfei org 那么执行下面的 JavaScript 语
  • 前端权限控制(一):前端权限管理及动态路由配置方案

    权限控制 在项目中 尤其是在后台管理系统中 不同人员登陆 看到的页面菜单是不一样的 比如 一个公司的办公系统 超级管理员登陆可以看到所有的页面 而普通员工账号登录可能无法看到人员管理等页面 比如公司的员工个人资料页面只有人力资源部门有权利看
  • 软件测试面试题:软件测试的风险主要体现在哪里?

    软件测试的风险主要体现在哪里 我们没有对软件进行完全测试 实际就是选择了风险 因为缺陷极有可能存在没有进行测试的部分 举个例子 程序员为了方便 在调试程序时会弹出一些提示信息框 而这些提示只在某种条件下会弹出 碰巧程序发布前这些代码中的一些
  • 【MySQL】MySQL存储过程从一张表查数据插入另一张表

    测试表 CREATE TABLE demo test ID varchar 64 NOT NULL name varchar 64 DEFAULT NULL age varchar 64 DEFAULT NULL PRIMARY KEY I
  • 四种常见函数式接口

    消费型函数式接口 Consumer
  • jmeter分布式压测

    1 什么是分布式压测 由一台控制机 Master 发出命令 控制多个压力机 Slaves 执行操作 2 为什么要做分布式压测 一台压力机的 Jmeter 默认最大支持 1000 左右的并发用户数 线程数 再大的话 容易造成卡顿 无响应等情况
  • Tomcat安装与配置(详细步骤)

    本篇博文记录了Tomcat环境安装与配置的详细步骤 旨在为将来再次配置Tomcat时提供指导方法 一 下载Tomcat Tomcat官网为 https tomcat apache org 1 按照下图根据JDK版本选择对应的 Tomcat
  • Chromium多进程架构,你知道多少?

    一 前言 国内外主流的浏览器 大多采用的是谷歌的Chromium 浏览器内核 Chromium是一个多进程多线程架构的Web引擎 很多应用和底层开发者希望了解Chromium中的进程和线程的种类和用途 以便能利用相关信息提升应用的性能 为此
  • 解决Eclipse,MyEclipse出现An error has occurred,See error log for more details的错误

    src http blog sina com cn s blog 4ba5b45e0102eam8 html 现把找到的解决方法整理提供给大家 如下 方法1 在 开始 gt 运行 gt 打入 cmd 进入命令提示行后 再进入eclipse的
  • iOS编程基础-OC(八)-运行时系统的结构(续)

    该系列文章系个人读书笔记及总结性内容 任何组织和个人不得转载进行商业活动 第八章 运行时系统的结构 8 1 2 运行时系统库 苹果公司提供的OC运行时系统库实现了OC的面向对象特性和动态属性 多数情况下 运行时系统库是在后台起作用 但也拥有
  • 如何使用Vue开发Electron桌面程序

    目录 一 Electron介绍 二 项目搭建 1 使用 vue cli 创建vue项目 2 安装插件 vue cli plugin electron builder 编辑 三 开发总结 1 配置项目图标 2 在Mac系统下的几个问题 3 项
  • 重要的环境变量&通配符&转义字符

    重要的环境变量 变量是系统用于可变值的数据类型 在linux中环境有几百个 都是系统运行环境的一些参数 例如 用户家目录等 输入 env 可输出所有环境变量 几个比较常见的环境变量 PATH 定义当前用户解释器搜索路径 HOME 当前用户的
  • Mac os下通过Anaconda在远程服务器配置python虚拟环境

    一 SSH管理软件 这里推荐一款本人正在使用的软件 Termius Termius是一款非常好用而且漂亮的SSH客户端 能快速远程控制服务器 可以定制自己喜欢的主题 Termius不仅涵盖了Windows Linux OSX 还变态得支持A
  • POI及EasyExcel-读写示例

    POI
  • 嵌入式杂谈之中断向量表

    虽说接触了好久的单片机或者说嵌入式开发 不过对于有些概念还是比较模糊 因此此系列将会从一些零碎的小知识点出发 慢慢的遍历整张嵌入式开发的地图 这次先来看一下中断向量表 至于为什么会提到中断向量表 主要是因为我自己在学习嵌入式Linux开发的
  • 基于51单片机的8x8x8LED光立方设计

    1 简介 本设计是以STC89C52单片机的8x8x8的LED光立方 本设计将LED光立方分成8层 分别由单片机的P1 8个IO口来控制每一层 由于采用的是共阴极所以当层电位为高电平有效 由P0口和P2的总共16个IO口来控制每层的64盏灯
  • 对视频剪辑应用灰度图像变换+Moviepy生成灰度视频处理遇到几个有意思的问题

    一 引言 最近在学习图像处理的 直方图处理 对直方图均衡处理效果感觉非常有用 以前学习Moviepy音视频剪辑时 用的卓别林的一个黑白视频片段 感觉视频的噪点比较多 画面也整体偏暗 不禁想看看如果对其进行直方图均衡会怎么样 如是开干 但进展