Python实现视频自动打码功能,避免看到羞羞的画面

Posted sakttylls

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python实现视频自动打码功能,避免看到羞羞的画面相关的知识,希望对你有一定的参考价值。

前言

嗨呀嗨呀,最近重温了一档综艺节目 至于叫什么 这里就不细说了

老是看着看着就会看到一堆马赛克,由于太好奇了就找了一下原因,结果是因为某艺人塌房了…虽然但是 看综艺的时候满影响美观的

咳咳,这里我可不是来教你们如何解码的,我是来教你们如何打码的,嘿嘿

那今天就在这分享一下 视频打码功能如何用python来实现

准备工作

环境咱们还是使用 Python3.8 和 pycharm2021 即可

实现原理

  1. 将视频分为音频和画面
  2. 画面中出现人脸和目标比对,相应人脸进行打码
  3. 处理后的视频添加声音

模块

手动安装一下 cv2 模块 ,pip install opencv-python 安装
安装遇到报错,可以私信我

素材工具

我们需要安装一下 ffmpeg 音视频转码工具

代码解析

导入模块

import cv2  
import face_recognition  # 人脸识别库  99.7%    cmake  dlib  face_recognition
import subprocess

视频转为音频

def video2mp3(file_name):
    """
    :param file_name: 视频文件路径
    :return:
    """
    outfile_name = file_name.split('.')[0] + '.mp3'
    cmd = 'ffmpeg -i ' + file_name + ' -f mp3 ' + outfile_name
    print(cmd)
    subprocess.call(cmd, shell=False)

进行打码

# 源码领取:309488165 ###
def mask_video(input_video, output_video, mask_path='mask.jpg'):
    """
    :param input_video: 需打码的视频
    :param output_video: 打码后的视频
    :param mask_path: 打码图片
    :return:
    """
    # 读取图片
    mask = cv2.imread(mask_path)
    # 读取视频
    cap = cv2.VideoCapture(input_video)
    # 视频  fps  width  height
    v_fps = cap.get(5)
    v_width = cap.get(3)
    v_height = cap.get(4)

设置写入视频参数 格式MP4

画面大小

size = (int(v_width), int(v_height))
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')

输出视频

out = cv2.VideoWriter(output_video, fourcc, v_fps, size)

已知人脸

    known_image = face_recognition.load_image_file('tmr.jpg')
    biden_encoding = face_recognition.face_encodings(known_image)[0]

    cap = cv2.VideoCapture(input_video)

    while (cap.isOpened()):
        ret, frame = cap.read()
        if ret:
            # 检测人脸
            # 人脸区域
            face_locations = face_recognition.face_locations(frame)

            for (top_right_y, top_right_x, left_bottom_y, left_bottom_x) in face_locations:
                print((top_right_y, top_right_x, left_bottom_y, left_bottom_x))
                unknown_image = frame[top_right_y - 50:left_bottom_y + 50, left_bottom_x - 50:top_right_x + 50]
                if face_recognition.face_encodings(unknown_image) != []:
                    unknown_encoding = face_recognition.face_encodings(unknown_image)[0]

                    # 对比人脸
                    results = face_recognition.compare_faces([biden_encoding], unknown_encoding)
                    # [True]
                    # 贴图
                    if results == [True]:
                        mask = cv2.resize(mask, (top_right_x - left_bottom_x, left_bottom_y - top_right_y))
                        frame[top_right_y:left_bottom_y, left_bottom_x:top_right_x] = mask
            out.write(frame)


        else:
            break

音频添加到画面

def video_add_mp3(file_name, mp3_file):
    """
    :param file_name: 视频画面文件
    :param mp3_file:  视频音频文件
    :return:
    """
    outfile_name = file_name.split('.')[0] + '-f.mp4'
    subprocess.call('ffmpeg -i ' + file_name + ' -i ' + mp3_file + ' -strict -2 -f mp4 ' + outfile_name, shell=False)

完整代码

点击文末名片领取即可

用Node.js写爬虫,撸羞羞的图片

 

  说到爬虫,很多人都认为是很高大上的东西。哇塞,是不是可以爬妹纸图啊,是不是可以爬小片片啊。答案就是对的。爬虫可以完成这些东西的操作。但是,作为一个正直的程序员,我们要在法律允许范围内用爬虫来为我们服务,而不是为所欲为。(ps:此处应有掌声,谢谢。)

  今天,我带来一个用Node.js写的爬虫。一说到教程呢,可能大多数人认为比较枯燥无味。那这样好了,我教大家爬妹纸图,上干货:

技术分享图片

  是不是瞬间有了动力了?

  说到爬虫呢,其实从客观上来说,“所有网站皆可爬”。互联网的内容都是人写出来的,而且都是偷懒写出来的(不会第一页是a,下一页是8),所以肯定有规律,这就给人有了爬取的可能,可以说,天下没有不能爬的网站。而且即使网站不同,但是原理都类似,大部分爬虫都是从 发送请求——>获得页面——>解析页面——>下载内容——>储存内容 这样的流程来进行,只是用的工具不同,可能你用python,我用Node,他用PHP,但是思路也是与上面相同。

  既然是用node完成爬虫,那么我们就要用到node环境,如果不会配的话,请参考我的第一篇博客。

  好的,我们从爬虫流程开始分析我们需要的一些模块。

  首先,我们需要发送请求获得页面,在这里呢,我们用到了request-promise模块。

技术分享图片
const rp = require("request-promise"), //进入request-promise模块
async getPage(URL) {
    const data = {
        url, 
        res: await rp({
            url: URL
        }) 
    }; 
    return data //这样,我们返回了一个对象,就是这个页面的url和页面内容。
}
技术分享图片

  其次,解析页面,我们使用一个叫做Cheerio的模块将上面返回的对象中的res解析成类似JQ的调用模式。Cheerio使用一个非常简单,一致的DOM模型。因此解析,操作和渲染非常高效。初步的端到端基准测试表明cheerio 比JSDOM快大约8倍。

const cheerio = require("cheerio");//引入Cheerio模块
const $ = cheerio.load(data.res); //将html转换为可操作的节点

  此时,我们要对我们即将进行爬取的页面进行分析。“www.mzitu.com/125685”,这是我们进行爬取的网址,F12查看DOM结构:

技术分享图片

  根据这个结构我们可以使用$(".main-image").find("img")[0].attribs.src来爬取这张图片的地址(如果不知道为什么是attribs.src的话可以一步一步console.log()一下看看)。

  最后,到了最关键的时候,我们使用fs模块进行创建文件夹以及下载文件。这里用到了fs模块的几个指令:

    1.fs.mkdirSync(downloadPath):查看是否存在这个文件夹。

    2.fs.mkdirSync(downloadPath):创建文件夹。

    3.fs.createWriteStream(`${downloadPath}/${index}.jpg`):写入文件,这里需要注意的是fs.createWriteStream 似乎不会自己创建不存在的文件夹,所以在使用之前需要注意,保存文件的文件夹一定要提前创建。

  好的,大体的方法就是以上的几个模块和步骤。

  在这里,我针对这个网站的一些情况进行一下分析:

    1.这个网站一个页面只有一张图片,但是每个页面的网址都是有根据的。“http://www.mzitu.com/125685”(当你输入“http://www.mzitu.com/125685/1”时也会跳转此页面),“http://www.mzitu.com/125685/2”等等。那么我们可以根据这个规律去爬取,并且我们需要在页面的下方的页码栏中获得这一组图图片的页码:

  技术分享图片

    2.我们一般不会只爬取一组图片,但是这个网站的图片的标题也就是最后的六位数基本没有规律可言,那么我们只能从最开始的首页入手。具体方法不多做描述,与获取图片的URL方式相同。

技术分享图片

    3.同理,我们爬取完一页的目录之后会进行对第二个目录的爬取,“http://www.mzitu.com/page/2/”,其原理和第一条相同。

    4.但是,有的网站存在防盗链的情况,面对这种措施,我们需要伪造一个请求头来避开这个情况。这个可以从F12的Network中查到,看到这里的朋友我想也会明白。

技术分享图片
let headers = {
          Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
          "Accept-Encoding": "gzip, deflate",
          "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
          "Cache-Control": "no-cache",
          Host: "i.meizitu.net",
          Pragma: "no-cache",
          "Proxy-Connection": "keep-alive",
          Referer: data.url,//根据爬取的网址跟换
          "Upgrade-Insecure-Requests": 1,
          "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.19 Safari/537.36"
        };
技术分享图片

  以上就是我的全部思路。

  代码:

    业务代码:

技术分享图片
const rp = require("request-promise"), //进入request-promise模块
  fs = require("fs"), //进入fs模块
  cheerio = require("cheerio"), //进入cheerio模块
  depositPath = "D:/blog/reptile/meizi/"; //存放照片的地址
let downloadPath; //下载图片的文件夹地址
module.exports = {
  async getPage(url) {
    const data = {
      url,
      res: await rp({
        url: url
      })
    };
    return data;
  },
  getUrl(data) {
    let list = [];
    const $ = cheerio.load(data.res); //将html转换为可操作的节点
    $("#pins li a")
      .children()
      .each(async (i, e) => {
        let obj = {
          name: e.attribs.alt, //图片网页的名字,后面作为文件夹名字
          url: e.parent.attribs.href //图片网页的url
        };
        list.push(obj); //输出目录页查询出来的所有链接地址
      });
    return list;
  },
  getTitle(obj) {
    downloadPath = depositPath + obj.name;
    if (!fs.existsSync(downloadPath)) {//查看是否存在这个文件夹
      fs.mkdirSync(downloadPath);//不存在就建文件夹
      console.log(`${obj.name}文件夹创建成功`);
      return true;
    } else {
      console.log(`${obj.name}文件夹已经存在`);
      return false;
    }
  },
  getImagesNum(res, name) {
    if (res) {
      let $ = cheerio.load(res);
      let len = $(".pagenavi")
        .find("a")
        .find("span").length;
      if (len == 0) {
        fs.rmdirSync(`${depositPath}${name}`);//删除无法下载的文件夹
        return 0;
      }
      let pageIndex = $(".pagenavi")
        .find("a")
        .find("span")[len - 2].children[0].data;
      return pageIndex;//返回图片总数
    }
  },
  //下载相册照片
  async downloadImage(data, index) {
    if (data.res) {
      var $ = cheerio.load(data.res);
      if ($(".main-image").find("img")[0]) {
        let imgSrc = $(".main-image").find("img")[0].attribs.src;//图片地址
        let headers = {
          Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
          "Accept-Encoding": "gzip, deflate",
          "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
          "Cache-Control": "no-cache",
          Host: "i.meizitu.net",
          Pragma: "no-cache",
          "Proxy-Connection": "keep-alive",
          Referer: data.url,
          "Upgrade-Insecure-Requests": 1,
          "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.19 Safari/537.36"
        };//反防盗链
        await rp({
          url: imgSrc,
          resolveWithFullResponse: true,
          headers
        }).pipe(fs.createWriteStream(`${downloadPath}/${index}.jpg`));//下载
        console.log(`${downloadPath}/${index}.jpg下载成功`);
      } else {
        console.log(`${downloadPath}/${index}.jpg加载失败`);
      }
    }
  }
};
技术分享图片

    主体逻辑代码:

技术分享图片
const model = require("./model"),
  basicPath = "http://www.mzitu.com/page/";
let start = 1,
  end = 10;
const main = async url => {
  let list = [],
    index = 0;
  const data = await model.getPage(url);
  list = model.getUrl(data);
  downLoadImages(list, index);//下载
};
const downLoadImages = async (list, index) => {
  if (index == list.length) {
    start++;
    if (start < end) {
      main(basicPath + start);//进行下一页图片组的爬取。
    }
    return false;
  }
  if (model.getTitle(list[index])) {
    let item = await model.getPage(list[index].url),//获取图片所在网页的url
      imageNum = model.getImagesNum(item.res,list[index].name);//获取这组图片的数量
    for (var i = 1; i <= imageNum; i++) {
      let page = await model.getPage(list[index].url + `/${i}`);//遍历获取这组图片每一张所在的网页
      await model.downloadImage(page, i);//下载
    }
    index++;
    downLoadImages(list, index);//循环完成下载下一组
  } else {
    index++;
    downLoadImages(list, index);//下载下一组
  }
};
main(basicPath + start);
技术分享图片

  此次项目已上传我的Github仓库https://github.com/lunlunshiwo/NodeJs-crawler,求star,谢谢。

 

  总结:

  至于后续操作,比如存到分类保存到本地和MongoDB数据库这样的操作,我下次再写,请关注我。

  郑重提升,爬虫虽好,一定不能触犯法律。

  如果本本文触犯您的利益,请留言。

  如果觉得本文不错,不要吝啬您的点赞和关注。谢谢。

 

 

  

以上是关于Python实现视频自动打码功能,避免看到羞羞的画面的主要内容,如果未能解决你的问题,请参考以下文章

用Node.js写爬虫,撸羞羞的图片

Bashfulness|你有一份羞羞的口红试色清单 请注意查收(ฅ´ω`ฅ)

Python实现视频自动打码,不用担心透露隐私了

Python实现让视频自动打码,再也不怕出现少儿不宜的画面了

python你实现视频自动打码,了解妨碍你观看精彩的马赛克是怎么精准形成的

新手的node爬虫初体验