如何将电脑文字复制到模拟器_如何将视频的字幕单独识别成文字

前言

在之前的文章中我们分别介绍了:

如果自己做一个OCR的工具:

PIC2WORD:一个很简单的在线的图片转文字(OCR)工具

如何将视频转成图片:

在视频本地化过程中使用ffmpeg提升效率

在视频本地化过程中使用ffmpeg提升效率(二)视频转文字

了解完以上内容后,我们在实践中遇到一个新的问题:

ab5ada44696075df8c25492cfe4aeff6.png

视频来源:

https://www.weibo.com/u/6060307497?tabtype=video&layerid=4579407136031075

【睡前消息203:长租公寓、打工人,爷的青春回来了】5:05

在上面这个视频截图中,我们不仅看到了字幕,同时也看到了许多其他的文字,如果将上面这个图送到百度的文字识别API中,会得到以下结果:

  • 序号 内容

  • 1 微博

  • 2 B站2020年度弹幕

  • 3 @观视频工作室

  • 4 no爷青回

  • 5 No2.武汉加油

  • 6 No3.有内味了

  • 7 No4.双厨狂喜

  • 8 No5.禁止套娃

  • 9 2020年网络年度关键词

  • 10 B站刚刚公布了2020年的年度弹幕

  • 11 观视频

虽然我们看到了被识别出来的字幕,但是非字幕也识别了出来,所以我们必须要想办法将字幕那部分的文字单独提取出来。

这就是今天这篇帖子要分享的主要内容。

正文

一、百度通用文字识别API

访问地址来源:

https://ai.baidu.com/tech/ocr/general

这次我们依然使用的是免费的百度API。百度提供的通用文字识别API可以识别20种语言,每天有好几万次的免费调用,所以足够我们这种小体量的使用场景。

它目前包括四种版本:

2deb791f394e5ff11e73920d83a9e780.png


对比起来,标准版是最初级的,支持10多种语言,而高精度版则支持更多语种,字库也更大,能识别生僻字。

不过,无论是标准版还是高精度版,都只能返回识别结果,这个还不能满足我们的需求,因为我们只想要截图中的字幕部分对应的文字。

所以我们可以考虑标准含位置版或高精度含位置版。

现在我们可以打开点击上述链接中的“立即使用”:

978d8c223dc4ab747ace64dbeda33af3.png

然后使用百度账号登录,并创建一个“应用”:

44c41188fce6822673c9d7506629bc15.png

创建之后会得到API Key和Secret Key:

76a1201552bfd93e3eebb6dcaef08cea.png

接下来就是去看技术文档和下载SDK:

3ff5f8b9c12cde876ce1cd3faddc944d.png

05f52013f95307fb8f41c983b260289d.png

我还是一如既往的使用PHP来做演示。

PHP的SDK可以在下面这个链接下载:

https://ai.baidu.com/sdk#ocr

bee76f3eecaeb14b9b127fa346f02aff.png

下载前可以在开发环境的根目录下创建一个空白的文件夹,然后把SDK放到这个SDK里:

ee9bab3a328ee28bd37f740a7fbc07cc.png

我们只需要lib文件夹和AipOcr.php文件即可:

eb0d3536a92b3dc8fe66e7c777f7eb98.png

这个操作在官方文档中也有介绍:

906ff3c9b28188498543485138e31f04.png

来源:

https://cloud.baidu.com/doc/OCR/s/hkibizxhx

我把这个截图放过来的主要目的是:其实我写的这些人家官方在文档里写得很清楚了。

二、引入百度OCR API并识别图片中的内容

1)引入API

有了API之后,就是引入API,引入的方法是创建一个index.php文件:

25be60fbb5ae3d7768f2b5bbf54fc670.png

并将官方文档中的代码贴进去:

792a9eb99433e24e79a839ca73ff10b1.png

以下是代码:

index.php

<?php require_once 'AipOcr.php';// 你的 APPID AK SKconst APP_ID = '你的 App ID';const API_KEY = '你的 Api Key';const SECRET_KEY = '你的 Secret Key';$client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);?>

然后把之前创建应用时获得的APP ID、APP Key和Secret Key都贴进去。

这样就算成功引入百度的OCR API了。

接下来是继续看文档,尤其是看通用文字识别(含位置信息版)部分的代码:

6049c7e3c117b3753b7af62773e98c13.png

来源:

https://cloud.baidu.com/doc/OCR/s/gkibizxd5

这段内容看着很霸气,但操作起来很简单。

首先,我们把图片放到根目录下我们刚刚创建的文件夹中:

65f596453bda1c9a3a89933659fe854d.png

然后把以下代码粘贴到index.php中:

<?php require_once 'AipOcr.php';// 你的 APPID AK SKconst APP_ID = '你的 App ID';const API_KEY = '你的 Api Key';const SECRET_KEY = '你的 Secret Key';$client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);$image = file_get_contents('example.jpg');// 如果有可选参数$options = array();$options["recognize_granularity"] = "big";$options["language_type"] = "CHN_ENG";$options["detect_direction"] = "true";$options["detect_language"] = "true";$options["vertexes_location"] = "true";$options["probability"] = "true";// 带参数调用通用文字识别(含位置信息版), 图片参数为本地图片$result = $client->general($image, $options);?>

仔细一对比会发现,官方文档提供的代码是针对好几种场景的,比如你的图片是来自网络的图片还是来自本地的图片。我们这里因为用的本地图片,所以就使用前面几行代码就可以了。

2)获取图片内容

在上面的代码中我们其实看不出来图片内容获取之后放在了哪里,那是因为我们没有创建变量来获取图片内容。因此,我们要修改一下第24行代码,变成:

$result = $client->general($image);

并且加一行:

print_r($result);

来显示获取到的结果。

代码如下:

<?php require_once 'AipOcr.php';// 你的 APPID AK SKconst APP_ID = '你的 App ID';const API_KEY = '你的 Api Key';const SECRET_KEY = '你的 Secret Key';$client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);$image = file_get_contents('example.jpg');// 如果有可选参数$options = array();$options["recognize_granularity"] = "big";$options["language_type"] = "CHN_ENG";$options["detect_direction"] = "true";$options["detect_language"] = "true";$options["vertexes_location"] = "true";$options["probability"] = "true";// 带参数调用通用文字识别(含位置信息版), 图片参数为本地图片$result = $client->general($image, $options);print_r($result);?>

这个时候去浏览器里访问这个index.php文件:

2369ee53aecec5a949e36beb5f0c84f8.png

(注:

请务必要启动你的编程环境;务必将你的应用信息填写到代码中;务必在浏览器中输入正确的访问地址,本文不再介绍这些步骤的完成方法。)

这个时候你会看到密密麻麻的内容,并且决定关掉浏览器,回到自己正常的生活中去。

对于编程初学者来说,其实很怕看到这样的场景,因为许多初学者对数组的认识还不是那么深刻,不知道自己才能从数组中读取数据。

最简单的方法就是右键点击浏览器,选择查看网页源代码,这个时候看到的就是另外一种风景了:

f9623ac40c9359d6e0e442729e2f43f7.png

我们此时要去看一下文档,看看返回的结果中都包含了哪些信息:

b242d8e47a38210afce70c46f3e4da42.png

这里面详细介绍了所有返回的参数。

我们以计划提取的字幕部分的文字所在的代码为例:

            [9] => Array                (                    [vertexes_location] => Array                        (                            [0] => Array                                (                                    [x] => 178                                    [y] => 704                                )                            [1] => Array                                (                                    [x] => 908                                    [y] => 704                                )                            [2] => Array                                (                                    [x] => 908                                    [y] => 765                                )                            [3] => Array                                (                                    [x] => 178                                    [y] => 765                                )                        )                    [probability] => Array                        (                            [average] => 0.995323                            [min] => 0.938568                            [variance] => 0.000209                        )                    [words] => B站刚刚公布了2020年的年度弹幕                    [min_finegrained_vertexes_location] => Array                        (                            [0] => Array                                (                                    [x] => 178                                    [y] => 703                                )                            [1] => Array                                (                                    [x] => 907                                    [y] => 703                                )                            [2] => Array                                (                                    [x] => 907                                    [y] => 764                                )                            [3] => Array                                (                                    [x] => 178                                    [y] => 764                                )                        )                    [location] => Array                        (                            [top] => 704                            [left] => 178                            [width] => 733                            [height] => 63                         )

在这段代码中,我们其实主要看两个部分:

[words] => B站刚刚公布了2020年的年度弹幕

 [location] => Array                        (                            [top] => 704                            [left] => 178                            [width] => 733                            [height] => 63                         )

这个就是这张截图中字幕部分的文字内容和位置信息。

在官方文档中还有这样一段描述:

+locationarray位置数组(坐标0点为左上角)
++leftnumber表示定位位置的长方形左上顶点的水平坐标
++topnumber表示定位位置的长方形左上顶点的垂直坐标
++widthnumber表示定位位置的长方形的宽度
++heightnumber表示定位位置的长方形的高度

可见,我们是这样来标记字幕位置的:

0933c1587ecb05043a8534fccf49e729.png

以字幕区域左上角的XY轴坐标来定位这个区域,Left就是X轴的值,Top就是Y轴的值。

根据上面的返回结果我们知道,上面这个截图中字幕区域的XY值分别是:178和704。

但如果你仔细去观察,你会发现:明明这个“B站”的位置在左下角,Y轴的值不可能那么大呀?

这是因为:百度的OCR API定义的原点为左上角:

4e8cf8a4d3de21157eb94a627b8deae6.png

这样是不是就说得通了?

知道了Left和Top后,我们再来看Width和Height,这两个值就比较好用了,我们如果知道了字幕的最大宽度和高度,就能准确定位出字幕的区域。即便我们的字幕是中英双语的,也能分别定位中文字幕和英文字幕。

下面,我们写一段代码,通过循环和判断来将字幕定位出来,如下:

<?php require_once 'AipOcr.php';// 你的 APPID AK SKconst APP_ID = '你的 App ID';const API_KEY = '你的 Api Key';const SECRET_KEY = '你的 Secret Key';$client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);$image = file_get_contents('example.jpg');// 如果有可选参数$options = array();$options["recognize_granularity"] = "big";$options["language_type"] = "CHN_ENG";$options["detect_direction"] = "true";$options["detect_language"] = "true";$options["vertexes_location"] = "true";$options["probability"] = "true";// 带参数调用通用文字识别(含位置信息版), 图片参数为本地图片$result = $client->general($image, $options);//print_r($result);foreach($result["words_result"] as $words){    if($words["location"]["left"] >= 178 and $words["location"]["top"] >= 704)    {        echo $words["words"];    }}?>

此时再去访问index.php页面:

443402b3f4eb0076f0a94cabcf69efc3.png

我们会看到原截图字幕部分的内容展示了出来(先忽略最后的那个“频”字儿),其他内容则没有。

仔细看上面的代码,会发现:

所有被识别出来的文字及其相关信息实际上都在$result["words_result"]这个数组里面,我们使用foreach循环来遍历这个数组,并将数组中的每一个元素看作是变量$words,然后根据location中的left和top的值来决定要选取哪一个元素,并将这个元素中words对应的文字展示出来。

为了测试这段代码的有效性,我们我们再次从原视频中截取一个图:

bbdde31d2bc7a72e68444eefb2180e3a.png

然后再次运行index.php,得到下面这个结果:

84b19ca325a4498ddeba6f1444aa076b.png

我们发现,不光“人民至上生命至上”显示出来了,后面的“观视频”也显示出来了,这就表明:我们不能仅用字幕的左上角来确定位置,还得把字幕的右上角的位置拿来,而这个右上角则是根据左上角的值以及字幕的宽度来决定的,我们需要在X轴上加上字幕的宽度来获得右上角坐标的X值。

而这里的宽度设为多少合适呢?

这个就要根据整个视频中最长的那个位置。

不过,在上面这个视频截图中,我们知道“观视频”其实是固定的logo,所以我们用它的左上角的XY坐标也可以做一个判断。

28c65eb5c128b7f6f946362fca284414.png

我们发现这个logo的左上角的值是1236,所以可以这样修改一下代码:

foreach($result["words_result"] as $words){    if($words["location"]["left"] >= 178 and $words["location"]["left"] < 1236 and $words["location"]["top"] >= 704)    {        echo $words["words"];    }}

即:$words["location"]["left"] >= 178 and $words["location"]["left"] < 1236

在设置条件的时候设置一个范围即可。

现在再运行index.php:

860251bfdd6dbb97637ddf9544586052.png

就只有字幕中的内容显示出来了。

我们再试一下前面那副图:

443402b3f4eb0076f0a94cabcf69efc3.png

我们会发现“频”字儿还在,这个时候是需要调整一下1236那个值,将其再缩小一点就可以了,如:1100。

再次访问index.php:

03a5aa645f4d67b13cc96fe1b8b67eb7.png

后面的“频”字就没有了。

三、思考

以上就是将视频的字幕单独识别成文字的过程。需要特别注意的是:

1)我在本文中展示的两幅截图都是我自己手动截图的,所以截出来的图中的字幕的具体位置会有变化,如果你自己亲自测试,需要根据所用的截图中实际字幕的XY值来调整代码,不要直接参考上述代码中的XY值。

2)请结合ffmpeg来获得截图,不要手动截图。

3)有时候我们在使用ffmpeg截图时会看一次截取很多帧出来,因此会出现重复的字幕内容,如何将他们合并呢?

希望大家可以自己去尝试一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值