镜头分割常常被用于视频智能剪辑、视频关键帧提取等场景。

本文给出一种解决镜头分割问题的思路,可分为两个步骤:

1、根据镜头分割算法对视频进行分割标记

核心在于镜头分割算法,这里简单描述一种算法思路:ratio = different(current_frame_histogram, prevous_frame_histogram) / avgvere_different(previous_frame_histogram),通过大量试验找到合适的ratio 阈值,若ratio大于阈值,则从当前帧分割视频,由于版权原因本文省略具体算法及实现。利用cv2的calcHist计算帧RGB三通道histogram的代码如下:

    for id in range(3):
self.current_hist_rgb[id] = cv2.calcHist([frame], [0], None, [256], [0, 255])

2、 根据分割标记进行实际分割

本文使用ffmpeg进行视频分割(需安装ffmpeg),具体命令如下

ffmpeg -ss starttime -i input.mp4 -t duration -codec copy -codec copy output.mp4 -y

命令中参数的顺序不能任意调整,-ss必须是第一个参数,否则分割后的视频可能出现黑屏,-t参数必须在-i参数后面,否则分割后视频可能出现时长不正确的问题。从实际效果来看,分割点并不准确在-ss参数指定的时间点,而是之前最近的关键帧。

最后,本文采用ffmpeg-python(需要用pip安装)来计算视频pts,具体实现见VideoCutEngine的calcPTS方法。

实现代码:

import cv2
import ffmpeg
import numpy as np
import sys
import os class VideoCutEngine():
def __init__(self, input):
self.input = input def calcPTS(self):
try:
probe = ffmpeg.probe(self.input)
except ffmpeg.Error as e:
print(e.stderr, sys.stderr)
return False, 0 video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None)
if video_stream is None:
return False, 1 num_frames = int(video_stream['nb_frames'])
duration = float(video_stream['duration']) return True, num_frames * 1.0 / duration def doCut(self, start, duration, output):
cmd = 'ffmpeg -ss {} -i {} -t {} -codec copy -codec copy {} -y'.format(start, self.input, duration, output)
ret = os.system(cmd)
return ret class SceneSplitEngine():
def __init__(self):
self.frame = None
self.current_hist_rgb = [0, 0, 0]
self.last_hist_rgb = [0, 0, 0]
self.frame_count = 0
self.current_shot_count = 0
self.hist_diff = [] def setFrmae(self,frame):
self.frame = frame
self.frame_count += 1
self.current_shot_count += 1 def doSplit(self):
for id in range(3):
self.current_hist_rgb[id] = cv2.calcHist([frame], [0], None, [256], [0, 255]) 具体算法实现省略。 input = '/data/test.mp4' if __name__ == '__main__':
sceneSpliter = SceneSplitEngine()
videoCutter = VideoCutEngine(input)
videoCapturer = cv2.VideoCapture(input) pts = videoCutter.calcPTS() while True:
ret1, frame = videoCapturer.read()
if ret1 == True:
sceneSpliter.setFrmae(frame)
ret2, start, end = sceneSpliter.doSplit()
if ret2 == True:
duration = max((end -start) / 24, 1)
print(ret2, start / 24, duration)
output = '/data/output{}.mp4'.format(start / 24)
videoCutter.doCut(start / 24, duration, output)
else:
break

  

基于opencv+ffmpeg的镜头分割的更多相关文章

  1. Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

    Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图 分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报   原文链接  ht ...

  2. Java基于opencv实现图像数字识别(五)—投影法分割字符

    Java基于opencv实现图像数字识别(五)-投影法分割字符 水平投影法 1.水平投影法就是先用一个数组统计出图像每行黑色像素点的个数(二值化的图像): 2.选出一个最优的阀值,根据比这个阀值大或小 ...

  3. 语义分割:基于openCV和深度学习(二)

    语义分割:基于openCV和深度学习(二) Semantic segmentation in images with OpenCV 开始吧-打开segment.py归档并插入以下代码: Semanti ...

  4. 语义分割:基于openCV和深度学习(一)

    语义分割:基于openCV和深度学习(一) Semantic segmentation with OpenCV and deep learning 介绍如何使用OpenCV.深度学习和ENet架构执行 ...

  5. 基于OpenCV制作道路车辆计数应用程序

    基于OpenCV制作道路车辆计数应用程序 发展前景 随着科学技术的进步和工业的发展,城市中交通量激增,原始的交通方式已不能满足要求:同时,由于工业发展为城市交通提供的各种交通工具越来越多,从而加速了城 ...

  6. Java基于opencv实现图像数字识别(二)—基本流程

    Java基于opencv实现图像数字识别(二)-基本流程 做一个项目之前呢,我们应该有一个总体把握,或者是进度条:来一步步的督促着我们来完成这个项目,在我们正式开始前呢,我们先讨论下流程. 我做的主要 ...

  7. 基于OpenCv和swing的图片/视频展示Java实现

    基于OpenCv和swing实现图片/视频的展示 图片的展示 swing展示图片,多为操作BufferedImage,这里要关注的核心是将Mat转为BufferedImage. 代码如下: publi ...

  8. Java基于opencv实现图像数字识别(一)

    Java基于opencv实现图像数字识别(一) 最近分到了一个任务,要做数字识别,我分配到的任务是把数字一个个的分开:当时一脸懵逼,直接百度java如何分割图片中的数字,然后就百度到了用Buffere ...

  9. c++开发ocx入门实践三--基于opencv的简易视频播发器ocx

    原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/51404649  利用opencv做了个简易的视频播放器的ocx,可以在c++/c#/web ...

随机推荐

  1. easyui控件使用例子

    1.easyui之dataGrid分页加载数据例子 注意:1)分页表格通过url获得数据会提交page,rows两个参数:后台需要获取这两个参数并且由此得到 int pageSize=rows/pag ...

  2. 织梦dedecms 自带采集的缩略图地址后面有“/”斜杠的解决方法

    本来想偷懒在网上找一些文档去解决织梦采集缩略图地址带“/”的问题的,可是找了找发现没有人写出解决方法,只好自己动手了. 过程很复杂,找了问题的原因也是找了半天,自己一点一点的测试.最后找到了问题所在. ...

  3. 【转】jQuery对象与DOM对象之间的转换方法

    刚开始学习jquery,可能一时会分不清楚哪些是jQuery对象,哪些是DOM对象.至于DOM对象不多解释,我们接触的太多了,下面重点介绍一下jQuery,以及两者相互间的转换. 什么是jQuery对 ...

  4. 美化tp5.1跳转提示

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  5. Oracle创建表空间和增加表空间

    1.创建表空间 create tablespace fgq datafile 'E:\app\Administrator\oradata\fms\fgq01.dbf' size 1000M autoe ...

  6. js的事件处理与闭包:

    var i = 0; for(i=0;i<5;i++){ (function(i){ setTimeout(function(){alert(i)},3000); })(i) } // 上面打印 ...

  7. rehash过程

    步骤 1) 首先创建一个比现有哈希表更大的新哈希表(expand)2) 然后将旧哈希表的所有元素都迁移到新哈希表去(rehash)   dictAdd 对字典添加元素的时候, _dictExpandI ...

  8. SSIS的控制流之For循环容器

    SSIS包由一个控制流以及一个或多个数据流(可选)组成.下面的关系图显示具有一个容器和六项任务的控制流. 这些任务中有五项定义于包级别,还有一项定义于容器级别.任务位于容器内.在控制流中的工具箱.我们 ...

  9. python 各种装饰器示例(python3)

    参考网址: Python中的各种装饰器详解_python_脚本之家http://www.jb51.net/article/63892.htm 一.函数式装饰器: 1.装饰器无参数,被装饰对象无参数 d ...

  10. lucene搜索之facet查询原理和facet查询实例——TODO

    转自:http://www.lai18.com/content/7084969.html Facet说明 我们在浏览网站的时候,经常会遇到按某一类条件查询的情况,这种情况尤以电商网站最多,以天猫商城为 ...