zoukankan      html  css  js  c++  java
  • 通过图像识别技术监控屏幕画面卡死问题

     一、背景需求

    公司视频组最近在录制某款游戏的PVP视频,视频录制好以后再上传到后端存储。但是在录制的过程中,有可能录制视频程序会有视频卡死不动的情况,即:录制程序在运行,但是后台渲染引擎工作异常,也就是游戏画面不变,但是视频程序还是在录制视频中。比如下面2张图片(暂且将新闻页面当做正在录制的视频,不同点我已标出):

     

    二、需求分析

    纵观整个过程,首先想尝试进行如下分析:

      1、从数据层面,抓取数据包异常特征,比如在渲染引擎工作异常时,数据包或者网络流量的大小是否会突升或突降?

      2、从系统层面,监控录制程序的资源占用情况(CPU/内存/IO),录制画面卡住时,录制程序占用资源是否有异常?

      3、从代码层面,需要开发视频录制程序的程序员进行相关日志输出,然后看是否可以看到错误日志?

    针对情况1,从数据层面看,渲染引擎工作异常,但是录制程序还是照常录制,只是录制的画面一直是出现异常时这一刻的屏幕画面,所以数据包不会有变化;

    针对情况2,系统层面,针对录制程序进行了专门的监控,但是后台引擎异常时,录制进行资源基本不会变化,所以这一个尝试也失败了;

    针对情况3,代码层面,录制程序确实有错误日志产生,针对这个情况,开发人员进行了重连渲染引擎的方法,虽然通过这种方法已经基本上解决了问题,但是还是有一部分概率即使在重启渲染引擎进程后,录制的游戏画面还是不变,即一直录制的同一个画面。这时,需要开发人员对整套录制程序进行重启才能彻底解决。

    以上只是交代了监控背景:视频组负责人要求运维这边针对出现一直是同一个画面的情况进行监控,如果有这种情况,及时通知他们,进行线上解决,当然,这也只是临时方法,后期还是要他们程序支持自动检测的,不然,这么老土的办法就算是开发自己,我想也会感到心里不安的。(半夜里电话吵醒来重启进程)

    三、解决方案

    针对画面不动进行监控,我在网上找了一些方法,但是都不能真正解决,比如:使用按键精灵,截取屏幕后通过图片大小进行对比;或者干脆使用截屏软件进行屏幕截取,然后比较文件的md5等等之类的,虽然图片能够截取,但是问题都不能解决,对比下来结果相差甚远。

    脑子里一直想着图片处理、图片处理。。。。。突然,灵光一闪,最近不是机器学习、图片识别不是很火么?既然能够截取屏幕,我们通过截屏的图片进行识别不就可以了么?解决方法找到了,就开始找方案。

    四、OpenCV

    1、OpeCV介绍

    OpenCV (Open Source Computer Vision Library) is an open source computer vision and machine learning software library. OpenCV was built to provide a common infrastructure for computer vision applications and to accelerate the use of machine perception in the commercial products. Being a BSD-licensed product, OpenCV makes it easy for businesses to utilize and modify the code.

    OpenCV--开源可视化计算库。它是一个开源计算可视化和机器学习的库。

    2、OpenCV怎么识别两张照片呢?

    比如怎么从一张大图和一张小图里面识别同一个图像呢?从机器的角度来说是这样的,先识别图像的特征,然后再相比,通过相似度进行判断是否为同一个人。

    实现代码如下:

    #!/usr/bin/env python
    # coding:utf-8
    from PIL import ImageGrab
    import time
    import os
    import cv2
    import numpy as np
    from matplotlib import pyplot as plt
    
    # 抓取当前屏幕
    cur_dir = os.path.dirname(__file__)
    im = ImageGrab.grab()
    im.save(os.path.join(cur_dir,"%s.png" %time.time()))
    
    # 获取当前目录下所有png文件
    def all_path(dirname):
        result = []
        for maindir, subdir, file_name_list in os.walk(dirname):
            for filename in file_name_list:
                if filename.endswith('.png'):
                    apath = os.path.join(maindir, filename)
                    result.append(apath)
        return result
    
    # 获取最新的两个文件
    def get_max_two(file_list):
        rt = []
        for f in file_list:
            rt.append((f,os.path.getctime(f)))
        rt = sorted(rt,key=lambda x:x[1],reverse=True)
        return rt[0][0],rt[1][0]
    
    
    # 计算单通道的直方图的相似值
    def calculate(image1, image2):
        hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
        hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
        # 计算直方图的重合度
        degree = 0
        for i in range(len(hist1)):
            if hist1[i] != hist2[i]:
                degree = degree + (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
            else:
                degree = degree + 1
        degree = degree / len(hist1)
        return degree
    
    
    # 通过得到每个通道的直方图来计算相似度
    def classify_hist_with_split(image1, image2, size=(256, 256)):
        # 将图像resize后,分离为三个通道,再计算每个通道的相似值
        image1 = cv2.resize(image1, size)
        image2 = cv2.resize(image2, size)
        sub_image1 = cv2.split(image1)
        sub_image2 = cv2.split(image2)
        sub_data = 0
        for im1, im2 in zip(sub_image1, sub_image2):
            sub_data += calculate(im1, im2)
        sub_data = sub_data / 3
        return sub_data
    
    
    if __name__ == '__main__':
        # 获取2张图片的相似度
        cur_dir = os.path.dirname(__file__)
        file_list = all_path(cur_dir)
        img1, img2 = get_max_two(file_list)
        # print img1,img2
    
        img1 = cv2.imread(img1)
        # cv2.imshow('img1', img1)
        img2 = cv2.imread(img2)
        # cv2.imshow('img2', img2)
        degree =  classify_hist_with_split(img1, img2)
        if isinstance(degree, int):
            with open(os.path.join(cur_dir, "a.txt"), 'w+') as f:
                f.write(str(degree))
        else:
            with open(os.path.join(cur_dir,"a.txt"),'w+') as f:
                f.write(str(degree[0]))

     解释一下以上脚本的整个过程:

    1、抓取当前屏幕,并以时间为文件名进行保存;

    2、取出当前最新的2张图片;

    3、获取当前2张照片的相似度,并写入文件a.txt;

    4、通过从a.txt读取相似度进行监控,相似度达到某个值,比如99%以上就判断为屏幕卡死了。

    五、实现

    1、设置计划任务

    把上面写好的脚本放入系统的计划任务中运行:

     

    结果如下:

    文件记录的相似度值:

    2、通过zabbix进行监控

    自定义监控项

    UserParameter=get_degree,type d:pycha.txt

    获取监控值

    [root@localhost ~]# zabbix_get  -s 10.20.122.18 -kget_degree

    0.996

    设置触发器

  • 相关阅读:
    -bash: fork: Cannot allocate memory 问题的处理
    Docker top 命令
    docker常见问题修复方法
    The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
    What's the difference between encoding and charset?
    hexcode of é î Latin-1 Supplement
    炉石Advanced rulebook
    炉石bug反馈
    Sidecar pattern
    SQL JOIN
  • 原文地址:https://www.cnblogs.com/skyflask/p/8280922.html
Copyright © 2011-2022 走看看