Category: Python

关键帧表格绘制
六月 25th, 2017 by lanxinxichen@126.com

一、 使用ffmpeg找出视频插入的关键帧

起因:某天晚上看一个科技评测节目,该节目宣称只要能够在视频中找到视频中插入的某一帧无关内容,就可以获得相应的奖品。我想了想应该是可以用代码实现的:

  1. 拿到该视频的文件

使用python3的一个工具you-get就能够做到。不过稍有曲折,我使用you-get去下载B站和优酷的视频都下载失败了,好在在该测评节目微博上找到了另外一个视频资源链接,使用you-get顺利下载下来,视频是640×360的,十分钟内容一共60M的MP4格式。

  1. 将视频逐帧抽离成为图片。

我先按照原样抽离,即抽离成640×360的图片,一共生成了8,988个文件,大小1.80 GB,不禁感慨视频压缩格式确实厉害啊,这压缩了多少倍啊,另外我考虑到可能更小的缩略图应该也拥有足够的分辨特征,所以也按照64×36的分辨率抽离了更小的缩略图

大图抽帧

640×360逐帧抽离的图片截图

小图抽帧

64×36逐帧抽离的图片截图

  1. 对比任意相邻图片的相似度。

图像相似度算法我没具体研究过,直接用的github上面的项目:https://github.com/MashiMaroLjc/Learn-to-identify-similar-images

一共有有四种算法,具体中文的文章可以参看链接:

https://segmentfault.com/a/1190000004467183 

我使用了不同的算法得到的不同的结果:

由于之前excel的制图删掉了,只能用当时程序计算的文本信息凑合了,计算出来的相似度大致就是如下的数字列表。

照片相似度对比结果

  1. 绘图寻找关键帧

其实就是根据特征去拟合一条折线,能够正确反映出异常的关键帧在哪里。

关键帧表格绘制

其实这一步,我做了两三个小时,为了选择最佳的算法和最佳的效果,只有下图能够直截了当的反映出异常的帧在哪里,后来我想了想,如果加入跳帧的对比,比如第一帧和第三帧的特征,就能够更加准确的找到关键帧的位置。

 

http://mp.weixin.qq.com/s/K2YCm8QwnpI7dNTs048Jbg

 

二、 ffmpeg做音频剪辑命令

叠加两个声音,并按照第一个声音的长度截取音乐,然后输出16k,单声道,声音质量为4的音乐:

ffmpeg -i example1.wav -i example2.wav -filter_complex amix=inputs=2:duration=first -ar 16k -ac 1 -q:a 4 output.wav

 

参考:https://ffmpeg.org/ffmpeg-filters.html

 

重复某个音频文件4次并截取80秒的音频数据

ffmpeg -stream_loop 4 –I example.wav -c copy -t 80 output.wav

 

从00:00:15开始截取音频、视频,截取5s,然后原样输出到文件中

ffmpeg -ss 00:00:15 -t 00:00:05 –I example.mp4 -vcodec copy -acodec copy output.mp4

 

pcm(已知pcm文件格式为16k 16bit 单声道)转换到固定格式的wav文件中

ffmpeg -f s16le -ar 16k -ac 1 -i tts_file_119.pcm -ar 16k -ac 1 tts_file_119.wav

对音频文件增加渐入渐出过滤效果(淡入从0秒开始,持续10秒,淡出从50秒开始,持续10秒,设定音乐音量为2, -y为覆盖已存在文件)

ffmpeg -i input.mp3 -af “afade=t=in:ss=0:d=10,afade=t=out:st=50:d=10,volume=volume=0.2″ -t 60 output.mp3 –y

更多声音过滤器:http://ffmpeg.org/ffmpeg-filters.html

 

设定背景音乐,循环播放并增加淡入淡出效果

ffmpeg -stream_loop 4 -iinput.wav -af “afade=t=in:ss=0:d=10,afade=t=out:st=50:d=10,volume=volume=0.2″ -t 80 output.wav

 

一般来讲 ffmpeg的文件后缀都是自适应的,比如你设置的输出格式是mp3,那么文件就能自动转换成该格式的文件,具体的采样率等参数需要单独去设置调整。

Posted in Coding, Python Tagged with: ,

一月 14th, 2017 by lanxinxichen@126.com

TypeError: not enough arguments for format string

使用Python连接数据库的时候,采用的非常非常轻量级的torndb,甚至于事务都不支持,所以用”select * from table where condition=’%s'” % (condition,)

因为用的比较原生,所以各种问题接连不断,最最恶心的就是字符串转义造成的一些列原因.

先采用

condition = re.escape(condition)

能对特殊字符进行转义,但是还是有问题,又报错TypeError: not enough arguments for format string 直到认真看输入的condition字符串的时候,才发现问题所在之处: condition中有% 需要替换%为%%才能正常执行,

condition= condition.replace('\%', '%%')

其实标题有问题,不只是操作数据库,只不过在操作数据库时候,忽略的字符串本身的内容,一直在错误的寻找解决方案.

Posted in Coding, Python, 数据库 Tagged with: ,

十一月 26th, 2015 by lanxinxichen@126.com

python以其强大和简洁的语言让人折服,那么究竟有多强大,多简洁呢?在今天学习python的过程中,我来举个例子。

in:将以下列表转化成{‘a’:1,’b':2}的形式

var = [('a','A',1),
       ('b','B',2),
       ('c','C',3)]

方法1:

tmp1 = []
tmp2 = []
for i in range(3):
 val1 = var[i][0]
 val2 = var[i][2]
 tmp1.append(val1)
 tmp2.append(val2)

tmpdict = {}.formatkeys(tmp1,0)
for i in range(3)
 tmpdict[tmpdict.keys()[i]] = tmp2[i]

当然我有意的拉长了代码。

方法2:

tmp1 = []
tmp2 = []
for i in range(3):
 tmp1.append(var[i][0])
 tmp2.append(var[i][2])
tmpdict = dict(zip(tmp1,tmp2))

采用zip压缩数组,然后转换成dict

方法3:

 tmpdict = {i[0]:i[2] for i in var}

一句话循环并组成字典。

同样的还有很多地方用到,比如lambda,reduced,filter,cmp等这类函数的应用。能大大减少代码量。更有意思的可以查看:一行 Python 能实现什么丧心病狂的功能?

 

 

Posted in Python Tagged with:

十一月 25th, 2015 by lanxinxichen@126.com

目标:在不删除python环境的情况下,安装一些常用的python库到windows中。

安装

VCForPython27 :windows下面vc库的安装软件。

Numpy : numpy windows下面的exe文件

scipy : scipy 的exe文件

matplotlib : pip 环境下的 whl 安装包,需要使用pip install 这个文件.whl 安装

 

下面工具还不熟悉,先不写描述了。

setuptools

python_dateutil

pyparsing

 

 

 

Posted in Python, 机器学习 Tagged with: ,

十一月 24th, 2015 by lanxinxichen@126.com

最近做项目使用scrapy,采用的是script的形式去写爬虫的,使用crawlspider去定义爬虫规则。
我先从数据库里面把我要读取的规则拿出来,采用的是单个频道写规则的形式,对每个列表页写一套规则,所以有next_page的规则。

sql = """SELECT id, weburl_id, name, allow_domains, start_urls, next_page,
      allow_url, extract_from, title_xpath, body_xpath, publish_time_xpath, source_site_xpath, enable
      FROM leiju_rules WHERE enable > 0"""

next_page分析形式是xpath提取链接,使用Rule不跟随(follow = False)。我的需求是我应该采集所有的页面,但是由于我想做成定时任务,就需要下次还使用这一套规则来运行爬虫,做到增量爬。这样的话就涉及到了内容的去重。开发的最开始,我才用的是pipline 通道去重,也就是当我产生一个request之后才开始判断这个内容我需要不需要,这样是很浪费服务器资源的。

if self.Redis.exists('url:%s' % item['url']):
    raise DropItem("Duplicate item found: %s" % item['url'])
else:
    self.Redis.set('url:%s' % item['url'], 1)
    return item

然后我修改成采用downloadMiddleware下载中间件去控制访问,因为downloadMiddleware是可以控制在request访问之前的,加上Redis的过滤。

if Redis.exists('url:%s' % response.url):
    raise IgnoreRequest("IgnoreRequest : %s" % response.url)
else:
    Redis.set('url:%s' % response.url, 1)
    return response

这时候又有一个问题了,就是我会把所有的访问都给记录下来,下次我连我写的起始start_urls都进不去了。本来寄托于从以下代码入手:

rule_list.append(Rule(LinkExtractor(restrict_xpaths=rule['next_page'])))

即希望通过next_page拿到下一页的链接,然后把这些链接排除掉,已经准备好了一个Redis库去存储这些url。

Filter = redis.StrictRedis(host='127.0.0.1', port=6379, db=2, password='pass123456')

然而实际在使用的时候发现我通过:

rule_list.append(Rule(LinkExtractor(restrict_xpaths=rule['next_page'])))

拿到的根本不是URL列表,而是一个Rule对象,里面包括了LinkExtarctor的Xpath规则。我甚至想通过response和xpath拿到链接之后在用redis存起来进行排除。
 
解决方法:
配合使用pipline和downloadMiddleware来轻松完成以上功能。
我先定义一个downloadMiddleware,用来拦截url,防止重复访问。

class IngoreHttpRequestMiddleware(object):
    """ 从下载器处开始拦截/过滤URL """
    def process_response(self, request, response, spider):
        if Redis.exists('url:%s' % response.url):
            raise IgnoreRequest("IgnoreRequest : %s" % response.url)
        else:
            # Redis.set('url:%s' % response.url, 1)
            return response

然后定义一个pipline,用来保存最终流入pipline的item URL。

class FilterUrlPipline(object):
    """ use redis to fileter url """
    def __init__(self):
        self.Redis = config.Redis

    def process_item(self, item, spider):
        self.Redis.set('url:%s' % item['url'], 1)
        return item

这样一来,我的一个列表页面的所有链接都进入到了downloadMiddleware中,但是通过pipline拿到了最终我要的终极页面,通过pipline保存item URL,然后下次的时候redis里面有了数据,就可以排除所有的符合的终极页面访问请求,这样就解决了。
 
已开源在github上面:https://github.com/fengxiaochuang/ScrapyDemo

Posted in Python Tagged with: , , ,

十一月 9th, 2015 by lanxinxichen@126.com

最近做项目使用了whoosh+flask,因为flask使用的是jinjia2 模板引擎,所以就此遇到的html转义的问题做一个解释.

以上为背景.

 

使用whoosh+falsk搜索的时候,我采用的是关键词高亮显示,但是在实际操作的过程中,生成的html是带<b></b>标签的字符串,无论怎样,这个标签字符串总是显示在html页面中.

开始我以为是因为在输出的过程中转义有问题,所以搜索python的html转义方法.无论正转义还是反转义,结果都不行.

QQ截图20151109123714

 

开始后来渐渐怀疑到jinjia2模板引擎上面,我从一开始已未需要加参数 “|e” 调试仍然不行,后来继续搜close escape html 才发现有一个safe参数,能够保证原始的 string 就不会被escape,修改后

{{ row.hit_title|safe }}

QQ截图20151109125754

终于,html标签不再显示为字符串了

Posted in Python Tagged with: , ,

十一月 4th, 2015 by lanxinxichen@126.com

从whoosh的坑里爬出来了,简单介绍一下实用搜索方面的内容,之前绕路了,希望以后学习的人不会绕远路.既然讲的话,就从我的一路的坑细细数来吧.

首先是受到whoosh官方demo的影响,我以为只能使用关键词的搜索,所以我用的如下方法:

for keyword in ("水果世博园", "你", "first", "中文", "交换机", "交换"):
    print("result of ", keyword)
    q = parser.parse(keyword)
    results = searcher.search(q)
    for hit in results:
        # print(hit.highlights("content"))
        print(hit)

当然这样的话搜索出来的结果都是每个关键词对应的一个搜索列表.这时候我甚至一度怀疑whoosh不支持短语的搜索,因为害怕自己去写搜索算法,于是此事搁置.

今天早上忽然有想到这个问题了,继续搜相关内容,无意中看到csdn上面有一篇文章提到Or Term And这种关键词,终于又回到whoosh手册上面了…真的是想要学一门技术就去读它的手册,上次吃亏在scrapy的logging上面…

然后开始进行程序改造,搜索短语,比如搜索:”中国国际物流节开幕”,采用结巴分词,先把这句话分解成一个个的关键词.

inputstring = "中国国际物流节开幕"
keywords = []
for t in analyzer(inputstring):
    keywords.append(t.text)

拆开的关键词是:中国 国际 物流 国际物流节(我自己添加到jieba字典里面的) 开幕

然后采用各种手册上面的iter_all_terms terms方法,不行,然后继续看手册,发现其实parse默认的标准是采用的And,而且我搜索的字段是body,而这句话是我从title里面复制出来的,自然返回为空了.

知道了基本原理就先通过修改Term进行测试:

And([Term("title", "中国"), Term("title", "国际"), Term("title", "物流"), Term("title", "国际物流节"), Term("title", "开幕")])

通过该And和Or来调解Trem去测试搜索结果,总体来看基本思路是对的.

Or([Term("title", "中国"), Term("title", "国际"), Term("title", "物流"), Term("title", "国际物流节"), Term("title", "开幕")])

通过上面的querystring 终于搜索出来结果了…

那么既然结果出来了,下一步就是继续给搜索添加条件了,类似谷歌的搜索是如何做到的呢?于是我再google上面搜索”whoosh like search google”

然后在stackoverflow上面搜索出来答案了,给出的几个选择pyl,pyprasing等…然后继续搜索whoosh和pyprasing,搜索出来的代码都是在whoosh,support.pyprasing下面调用的,我import没有啊,继续看搜索结果,,,看到whoosh里面有这么一句话:(In previous versions of Whoosh, the query parser was based on pyparsing. The new hand-written parser is less brittle and more flexible.)

你说什么!whoosh原本就是基于pyparsing构造语法的?往下看手册,,,真的是必须硬着头皮看手册啊….

发现whoosh本身支持通过” “(空格)来分割关键词搜索的.也是支持and or 这种直接的搜索语法的,还可以自己定义这些逻辑符号.

再往下就顺利多了,随便贴一点我用到的关键代码把:

inputstring = "中国and(国际or物流)and开幕"
qp = MultifieldParser(["title", "body"], schema=ix.schema)
    querystring = qp.parse(inputstring)
    results = searcher.search(querystring, terms=True, limit=100, collapse_limit=1)
    for hit in results:
        print(hit['title'].encode('gbk'))

RTFM!

RTFM!

RTFM!

Posted in Python Tagged with: ,