openh264 场景变化检测算法源码分析

文件位置

  • openh264/codec/processing/scenechangedetection/SceneChangeDetection.cpp
  • openh264/codec/processing/scenechangedetection/SceneChangeDetection.h

代码流程

在这里插入图片描述

  • 说明
    通过代码流程分析,当METHOD_SCENE_CHANGE_DETECTION_SCREEN场景类型为时候,创建CSceneChangeDetectorScreen子类进行场景变化检测;当METHOD_SCENE_CHANGE_DETECTION_VIDEO场景类型为时,创建CSceneChangeDetectorVideo子类进行场景变化检测。

原理

  • 开关控制参数:(bool)bEnableSceneChangeDetect

CSceneChangeDetectorVideo 类

  1. 功能:通过CSceneChangeDetection类模板调用CSceneChangeDetectorVideo类中方法实现摄像视频场景变化检测功能类
  2. 过程
  • 第一步:CSceneChangeDetection类中process 函数;
    • 初始化变量、参数设置;
    • 场景变化阈值iSceneChangeThresholdLarge、iSceneChangeThresholdMedium计算;
    • 设置eSceneChangeIdc类型为SIMILAR_SCENE;
    • 调用一个名为m_cDetector的对象的重载运算符(),传入m_sLocalParam作为参数,调用指向CSceneChangeDetectorVideo类中场景变化检测算法;
    • 场景变化判断;
      • 如果,iMotionBlockNum 大于等于iSceneChangeThresholdLarge,则设置eSceneChangeIdc类型为LARGE_CHANGED_SCENE;
      • 否则,iMotionBlockNum 大于等于iSceneChangeThresholdMedium,则设置eSceneChangeIdc类型为MEDIUM_CHANGED_SCENE;
  • 第二步:CSceneChangeDetectorVideo类中operator重载;
    • 双层嵌套 for 循环处理以 8x8 为单位的图像块,即处理每个 8x8 块;
      • 调用m_pfSad函数(指向具体的WelsSampleSad8x8_c函数)计算 iSad 值;
      • 比较 iSad 与HIGH_MOTION_BLOCK_THRESHOLD的大小,将结果累加到iMotionBlockNum中;
      • 指针更新,下一个 8x8 块以及下一行图像;
  1. 原理图
    在这里插入图片描述
  2. 相关源码
  • CSceneChangeDetection模板类
template<typename T>
class CSceneChangeDetection : public IStrategy {
 public:
  CSceneChangeDetection (EMethods eMethod, int32_t iCpuFlag): m_cDetector (m_sSceneChangeParam, iCpuFlag) {
    m_eMethod   = eMethod;
    WelsMemset (&m_sSceneChangeParam, 0, sizeof (m_sSceneChangeParam));
  }

  ~CSceneChangeDetection() {
  }

  EResult Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
    EResult eReturn = RET_INVALIDPARAM;

    m_sLocalParam.iWidth = pSrcPixMap->sRect.iRectWidth;
    m_sLocalParam.iHeight = pSrcPixMap->sRect.iRectHeight;
    m_sLocalParam.iBlock8x8Width = m_sLocalParam.iWidth >> 3;
    m_sLocalParam.iBlock8x8Height = m_sLocalParam.iHeight >> 3;
    m_sLocalParam.pRefY = (uint8_t*)pRefPixMap->pPixel[0];
    m_sLocalParam.pCurY = (uint8_t*)pSrcPixMap->pPixel[0];
    m_sLocalParam.iRefStride = pRefPixMap->iStride[0];
    m_sLocalParam.iCurStride = pSrcPixMap->iStride[0];
    m_sLocalParam.pStaticBlockIdc = m_sSceneChangeParam.pStaticBlockIdc;

    int32_t iBlock8x8Num = m_sLocalParam.iBlock8x8Width * m_sLocalParam.iBlock8x8Height;
    int32_t iSceneChangeThresholdLarge = WelsStaticCast (int32_t,
                                         m_cDetector.GetSceneChangeMotionRatioLarge() * iBlock8x8Num + 0.5f + PESN);
    int32_t iSceneChangeThresholdMedium = WelsStaticCast (int32_t,
                                          m_cDetector.GetSceneChangeMotionRatioMedium() * iBlock8x8Num + 0.5f + PESN);

    m_sSceneChangeParam.iMotionBlockNum = 0;
    m_sSceneChangeParam.iFrameComplexity = 0;
    m_sSceneChangeParam.eSceneChangeIdc = SIMILAR_SCENE;

    m_cDetector (m_sLocalParam);

    if (m_sSceneChangeParam.iMotionBlockNum >= iSceneChangeThresholdLarge) {
      m_sSceneChangeParam.eSceneChangeIdc = LARGE_CHANGED_SCENE;
    } else if (m_sSceneChangeParam.iMotionBlockNum >= iSceneChangeThresholdMedium) {
      m_sSceneChangeParam.eSceneChangeIdc = MEDIUM_CHANGED_SCENE;
    }

    eReturn = RET_SUCCESS;

    return eReturn;
  }

  EResult Get (int32_t iType, void* pParam) {
    if (pParam == NULL) {
      return RET_INVALIDPARAM;
    }
    * (SSceneChangeResult*)pParam = m_sSceneChangeParam;
    return RET_SUCCESS;
  }

  EResult Set (int32_t iType, void* pParam) {
    if (pParam == NULL) {
      return RET_INVALIDPARAM;
    }
    m_sSceneChangeParam = * (SSceneChangeResult*)pParam;
    return RET_SUCCESS;
  }
 private:
  SSceneChangeResult m_sSceneChangeParam;
  SLocalParam m_sLocalParam;
  T          m_cDetector;
};
  • CSceneChangeDetectorVideo
class CSceneChangeDetectorVideo {
 public:
  CSceneChangeDetectorVideo (SSceneChangeResult& sParam, int32_t iCpuFlag) : m_sParam (sParam) {
    m_pfSad = WelsSampleSad8x8_c;
#ifdef X86_ASM
    if (iCpuFlag & WELS_CPU_SSE2) {
      m_pfSad = WelsSampleSad8x8_sse21;
    }
#endif
#ifdef HAVE_NEON
    if (iCpuFlag & WELS_CPU_NEON) {
      m_pfSad = WelsProcessingSampleSad8x8_neon;
    }
#endif

#ifdef HAVE_NEON_AARCH64
    if (iCpuFlag & WELS_CPU_NEON) {
      m_pfSad = WelsProcessingSampleSad8x8_AArch64_neon;
    }
#endif

#ifdef HAVE_MMI
    if (iCpuFlag & WELS_CPU_MMI) {
      m_pfSad = WelsSampleSad8x8_mmi;
    }
#endif

    m_fSceneChangeMotionRatioLarge = SCENE_CHANGE_MOTION_RATIO_LARGE_VIDEO;
    m_fSceneChangeMotionRatioMedium = SCENE_CHANGE_MOTION_RATIO_MEDIUM;
  }
  virtual ~CSceneChangeDetectorVideo() {
  }
  void operator() (SLocalParam& sLocalParam) {
    int32_t iRefRowStride = 0, iCurRowStride = 0;
    uint8_t* pRefY = sLocalParam.pRefY;
    uint8_t* pCurY = sLocalParam.pCurY;
    uint8_t* pRefTmp = NULL, *pCurTmp = NULL;

    iRefRowStride  = sLocalParam.iRefStride << 3;
    iCurRowStride  = sLocalParam.iCurStride << 3;

    for (int32_t j = 0; j < sLocalParam.iBlock8x8Height; j++) {
      pRefTmp = pRefY;
      pCurTmp = pCurY;
      for (int32_t i = 0; i < sLocalParam.iBlock8x8Width; i++) {
        int32_t iSad = m_pfSad (pCurTmp, sLocalParam.iCurStride, pRefTmp, sLocalParam.iRefStride);
        m_sParam.iMotionBlockNum += iSad > HIGH_MOTION_BLOCK_THRESHOLD;
        pRefTmp += 8;
        pCurTmp += 8;
      }
      pRefY += iRefRowStride;
      pCurY += iCurRowStride;
    }
  }
  float  GetSceneChangeMotionRatioLarge() const {
    return m_fSceneChangeMotionRatioLarge;
  }
  float  GetSceneChangeMotionRatioMedium() const {
    return m_fSceneChangeMotionRatioMedium;
  }
 protected:
  SadFuncPtr m_pfSad;
  SSceneChangeResult& m_sParam;
  float    m_fSceneChangeMotionRatioLarge;
  float    m_fSceneChangeMotionRatioMedium;
};
  • WelsSampleSad8x8_c函数
int32_t WelsSampleSad8x8_c (uint8_t* pSample1, int32_t iStride1, uint8_t* pSample2, int32_t iStride2) {
  int32_t iSadSum = 0;
  int32_t i = 0;
  uint8_t* pSrc1 = pSample1;
  uint8_t* pSrc2 = pSample2;
  for (i = 0; i < 8; i++) {
    iSadSum += WELS_ABS ((pSrc1[0] - pSrc2[0]));
    iSadSum += WELS_ABS ((pSrc1[1] - pSrc2[1]));
    iSadSum += WELS_ABS ((pSrc1[2] - pSrc2[2]));
    iSadSum += WELS_ABS ((pSrc1[3] - pSrc2[3]));
    iSadSum += WELS_ABS ((pSrc1[4] - pSrc2[4]));
    iSadSum += WELS_ABS ((pSrc1[5] - pSrc2[5]));
    iSadSum += WELS_ABS ((pSrc1[6] - pSrc2[6]));
    iSadSum += WELS_ABS ((pSrc1[7] - pSrc2[7]));

    pSrc1 += iStride1;
    pSrc2 += iStride2;
  }

  return iSadSum;
}

CSceneChangeDetectorScreen类

  1. 功能:通过CSceneChangeDetection类模板调用CSceneChangeDetectorScreen类中方法实现桌面视频场景变化检测功能类
  2. 过程
  • 第一步:同CSceneChangeDetectorVideo类中检测过程;
  • 第二步:CSceneChangeDetectorScreen类中operator重载;
    • 获取滚动检测标志bScrollDetectFlag和 mv 坐标iScrollMvX、iScrollMvY;
    • 初始化工作;
    • 双层 for 嵌套循环处理每个 8x8 图像块;
      • 调用m_pfSad函数计算 iSad;
      • 如果 iSad 为 0,则标记当前块为COLLOCATED_STATIC,表明是静止的;
      • 如果滚动检测标志为真,并且滚动向量不为空,当前块的坐标加上滚动向量后仍在图像范围内;
        • 使用滚动向量调整参考块的位置pRefTmpScroll;
        • 再次调用m_pfSad函数,得到iSadScroll值;
        • 如果 iSadScroll 为 0,则标记当前块为COLLOCATED_STATIC,表明是静止的;
        • 否则,
          • 将 iSad 累加到iFrameComplexity;
          • 判断 iSad 与HIGH_MOTION_BLOCK_THRESHOLD的大小关系,将结果累加到iMotionBlockNum;
      • 否则,
        • 将 iSad 累加到iFrameComplexity;
        • 判断 iSad 与HIGH_MOTION_BLOCK_THRESHOLD的大小关系,将结果累加到iMotionBlockNum;
      • 更新图像块位置。
  1. 相关源码
  • CSceneChangeDetection模板类
template<typename T>
class CSceneChangeDetection : public IStrategy {
 public:
  CSceneChangeDetection (EMethods eMethod, int32_t iCpuFlag): m_cDetector (m_sSceneChangeParam, iCpuFlag) {
    m_eMethod   = eMethod;
    WelsMemset (&m_sSceneChangeParam, 0, sizeof (m_sSceneChangeParam));
  }

  ~CSceneChangeDetection() {
  }

  EResult Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
    EResult eReturn = RET_INVALIDPARAM;

    m_sLocalParam.iWidth = pSrcPixMap->sRect.iRectWidth;
    m_sLocalParam.iHeight = pSrcPixMap->sRect.iRectHeight;
    m_sLocalParam.iBlock8x8Width = m_sLocalParam.iWidth >> 3;
    m_sLocalParam.iBlock8x8Height = m_sLocalParam.iHeight >> 3;
    m_sLocalParam.pRefY = (uint8_t*)pRefPixMap->pPixel[0];
    m_sLocalParam.pCurY = (uint8_t*)pSrcPixMap->pPixel[0];
    m_sLocalParam.iRefStride = pRefPixMap->iStride[0];
    m_sLocalParam.iCurStride = pSrcPixMap->iStride[0];
    m_sLocalParam.pStaticBlockIdc = m_sSceneChangeParam.pStaticBlockIdc;

    int32_t iBlock8x8Num = m_sLocalParam.iBlock8x8Width * m_sLocalParam.iBlock8x8Height;
    int32_t iSceneChangeThresholdLarge = WelsStaticCast (int32_t,
                                         m_cDetector.GetSceneChangeMotionRatioLarge() * iBlock8x8Num + 0.5f + PESN);
    int32_t iSceneChangeThresholdMedium = WelsStaticCast (int32_t,
                                          m_cDetector.GetSceneChangeMotionRatioMedium() * iBlock8x8Num + 0.5f + PESN);

    m_sSceneChangeParam.iMotionBlockNum = 0;
    m_sSceneChangeParam.iFrameComplexity = 0;
    m_sSceneChangeParam.eSceneChangeIdc = SIMILAR_SCENE;

    m_cDetector (m_sLocalParam);

    if (m_sSceneChangeParam.iMotionBlockNum >= iSceneChangeThresholdLarge) {
      m_sSceneChangeParam.eSceneChangeIdc = LARGE_CHANGED_SCENE;
    } else if (m_sSceneChangeParam.iMotionBlockNum >= iSceneChangeThresholdMedium) {
      m_sSceneChangeParam.eSceneChangeIdc = MEDIUM_CHANGED_SCENE;
    }

    eReturn = RET_SUCCESS;

    return eReturn;
  }

  EResult Get (int32_t iType, void* pParam) {
    if (pParam == NULL) {
      return RET_INVALIDPARAM;
    }
    * (SSceneChangeResult*)pParam = m_sSceneChangeParam;
    return RET_SUCCESS;
  }

  EResult Set (int32_t iType, void* pParam) {
    if (pParam == NULL) {
      return RET_INVALIDPARAM;
    }
    m_sSceneChangeParam = * (SSceneChangeResult*)pParam;
    return RET_SUCCESS;
  }
 private:
  SSceneChangeResult m_sSceneChangeParam;
  SLocalParam m_sLocalParam;
  T          m_cDetector;
};
  • CSceneChangeDetectorScreen
class CSceneChangeDetectorScreen : public CSceneChangeDetectorVideo {
 public:
  CSceneChangeDetectorScreen (SSceneChangeResult& sParam, int32_t iCpuFlag) : CSceneChangeDetectorVideo (sParam,
        iCpuFlag) {
    m_fSceneChangeMotionRatioLarge = SCENE_CHANGE_MOTION_RATIO_LARGE_SCREEN;
    m_fSceneChangeMotionRatioMedium = SCENE_CHANGE_MOTION_RATIO_MEDIUM;
  }
  virtual ~CSceneChangeDetectorScreen() {
  }
  void operator() (SLocalParam& sLocalParam) {
    bool bScrollDetectFlag = m_sParam.sScrollResult.bScrollDetectFlag;
    int32_t iScrollMvX = m_sParam.sScrollResult.iScrollMvX;
    int32_t iScrollMvY = m_sParam.sScrollResult.iScrollMvY;

    int32_t iRefRowStride = 0, iCurRowStride = 0;
    uint8_t* pRefY = sLocalParam.pRefY;
    uint8_t* pCurY = sLocalParam.pCurY;
    uint8_t* pRefTmp = NULL, *pCurTmp = NULL;
    int32_t iWidth = sLocalParam.iWidth;
    int32_t iHeight = sLocalParam.iHeight;

    iRefRowStride  = sLocalParam.iRefStride << 3;
    iCurRowStride  = sLocalParam.iCurStride << 3;

    for (int32_t j = 0; j < sLocalParam.iBlock8x8Height; j++) {
      pRefTmp = pRefY;
      pCurTmp = pCurY;
      for (int32_t i = 0; i < sLocalParam.iBlock8x8Width; i++) {
        int32_t iBlockPointX = i << 3;
        int32_t iBlockPointY = j << 3;
        uint8_t uiBlockIdcTmp = NO_STATIC;
        int32_t iSad = m_pfSad (pCurTmp, sLocalParam.iCurStride, pRefTmp, sLocalParam.iRefStride);
        if (iSad == 0) {
          uiBlockIdcTmp = COLLOCATED_STATIC;
        } else if (bScrollDetectFlag && (!iScrollMvX || !iScrollMvY) && (iBlockPointX + iScrollMvX >= 0)
                   && (iBlockPointX + iScrollMvX <= iWidth - 8) &&
                   (iBlockPointY + iScrollMvY >= 0) && (iBlockPointY + iScrollMvY <= iHeight - 8)) {
          uint8_t* pRefTmpScroll = pRefTmp + iScrollMvY * sLocalParam.iRefStride + iScrollMvX;
          int32_t iSadScroll = m_pfSad (pCurTmp, sLocalParam.iCurStride, pRefTmpScroll, sLocalParam.iRefStride);

          if (iSadScroll == 0) {
            uiBlockIdcTmp = SCROLLED_STATIC;
          } else {
            m_sParam.iFrameComplexity += iSad;
            m_sParam.iMotionBlockNum += iSad > HIGH_MOTION_BLOCK_THRESHOLD;
          }
        } else {
          m_sParam.iFrameComplexity += iSad;
          m_sParam.iMotionBlockNum += iSad > HIGH_MOTION_BLOCK_THRESHOLD;
        }
        * (sLocalParam.pStaticBlockIdc) ++ = uiBlockIdcTmp;
        pRefTmp += 8;
        pCurTmp += 8;
      }
      pRefY += iRefRowStride;
      pCurY += iCurRowStride;
    }
  }
};
  • WelsSampleSad8x8_c函数
int32_t WelsSampleSad8x8_c (uint8_t* pSample1, int32_t iStride1, uint8_t* pSample2, int32_t iStride2) {
  int32_t iSadSum = 0;
  int32_t i = 0;
  uint8_t* pSrc1 = pSample1;
  uint8_t* pSrc2 = pSample2;
  for (i = 0; i < 8; i++) {
    iSadSum += WELS_ABS ((pSrc1[0] - pSrc2[0]));
    iSadSum += WELS_ABS ((pSrc1[1] - pSrc2[1]));
    iSadSum += WELS_ABS ((pSrc1[2] - pSrc2[2]));
    iSadSum += WELS_ABS ((pSrc1[3] - pSrc2[3]));
    iSadSum += WELS_ABS ((pSrc1[4] - pSrc2[4]));
    iSadSum += WELS_ABS ((pSrc1[5] - pSrc2[5]));
    iSadSum += WELS_ABS ((pSrc1[6] - pSrc2[6]));
    iSadSum += WELS_ABS ((pSrc1[7] - pSrc2[7]));

    pSrc1 += iStride1;
    pSrc2 += iStride2;
  }

  return iSadSum;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/689085.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【PostgreSQL 小课】日志及审计 01:日志

日志及审计 01&#xff1a;日志 以下内容是来自于我的知识星球&#xff1a;《PostgreSQL 小课》专栏&#xff0c;有需要可以关注一下 PostgreSQL 提供了非常丰富的日志基础设施。能够检查日志是每个 DBA 的关键技能——日志提供了关于集群过去的操作、当前正在进行的操作以及发…

Android 高德地图API(新版)

新版高德地图 前言正文一、创建应用① 获取PackageName② 获取调试版安全码SHA1③ 获取发布版安全码SHA1 二、配置项目① 导入SDK② 配置AndroidManifest.xml 三、获取当前定位信息① ViewBinding使用和导包② 隐私合规设置③ 权限请求④ 初始化定位⑤ 获取定位信息 四、显示地…

高级文件操作

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 Python内置的os模块除了可以对目录进行操作&#xff0c;还可以对文件进行一些高级操作&#xff0c;具体函数如表4所示。 表4 os模块提供的与文件相…

重新学习STM32(2)NVIC

概念简介 NVIC&#xff0c;即嵌套向量中断控制器&#xff0c;控制着中断相关的功能&#xff0c;是内核里面的一个外设。 中断在单片机编程中的作用是使单片机能及时响应需要立即处理的事件&#xff0c;但是这些事件也分紧急和非紧急&#xff0c;因此需要优先级来区分。…

frp之XTCP实现内网穿透家用电脑远程桌面公司电脑

官网XTCP介绍 《XTCP介绍》 实现图 fprs.toml # frps 服务端口&#xff08;不填&#xff0c;则默认&#xff1a;7000&#xff09; bindPort 81 auth.token "token 令牌"公司电脑frpc.toml serverAddr "frps公网服务器域名或ip" serverPort frps 服…

基于 vue-element-template 框架添加 tagsview

1. 需求 vue-element-template 是一个基础模板&#xff0c;默认没有 tagsview。所以要手动添加。 参考最全面的集成方案框架 vue-element-admin &#xff0c;拷贝和修改相关文件到你的项目中。 2. 修改 复制如下文件或文件夹 \src\layout\components\TagsView\src\store\mo…

什么情况下要配置DNS服务

什么是DNS 一、DNS就是域名解析 我们上网的方式通常都由ip地址组成&#xff0c;但是为了有个规范&#xff0c;而且我们也不可能去记住那么多一串Ip数字&#xff0c;首先域名就会比ip好记很多&#xff0c;其次固定性&#xff0c;一旦服务器换了&#xff0c;只要重新绑定域名对…

java第二十一课 —— 快捷键,包,访问修饰符

IDEA 快捷键 删除行&#xff1a;Ctrl Y复制行&#xff1a;Ctrl D补全代码&#xff1a;Alt /添加取消注释&#xff1a;Ctrl /导入该行需要的类&#xff1a;Alt Enter快速格式化代码&#xff1a;Ctrl Shift L快速运行程序&#xff1a;Ctrl Shift F10生成构造器&#xf…

分享万能点击器免费版,吾爱大佬出品,这个太赞了!

小伙伴们&#xff01;阿星又来给大家推荐神奇的小软件啦&#xff01;这次的主角可是个神器——鼠标连点器&#xff01;你听过没&#xff1f;这玩意儿简直是个“自动小助手”&#xff0c;让你的鼠标在屏幕上飞舞&#xff0c;点得飞快&#xff0c;解放你的双手&#xff0c;让你网…

企业费用标准如何制定?

在当前宏观经济环境和市场竞争日益激烈的背景下&#xff0c;国内很多企业的费用管理流程依旧面临诸多挑战。特别是制造业、零售业等人员众多的企业&#xff0c;如何通过制定精细化、自动化的企业费用标准来实现降本增效&#xff0c;已经成为企业财务流程优化的首要目标。 企业…

Oracle数据库设计规范指南(Word原件)

方便业务功能实现、业务功能扩展&#xff1b;方便设计开发、增强系统的稳定性和可维护性&#xff1b;保证数据完整性和准确性&#xff1b;提高数据存储效率&#xff0c;在满足业务需求的前提下&#xff0c;使时间开销和空间开销达到优化平衡。资料获取&#xff1a;本文本个人名…

常见硬件工程师面试题(一)

大家好&#xff0c;我是山羊君Goat。 对于硬件工程师&#xff0c;学习的东西主要和电路硬件相关&#xff0c;所以在硬件工程师的面试中&#xff0c;对于经验是十分看重的&#xff0c;像PCB设计&#xff0c;电路设计原理&#xff0c;模拟电路&#xff0c;数字电路等等相关的知识…

FANUC机器人SRVO-348 DCS MCC关闭报警处理方法总结

FANUC机器人SRVO-348 DCS MCC关闭报警处理方法总结 如下图所示,由于操作人员在操机时误打开了安全门,导致机器人紧急制动停止,示教器上显示: SRV0-348 DCS MCC关闭报警0,1, 如下图所示,查看手册中关于SRVO-348报警的具体内容: 原因分析:给机器人主电源上电的接触器在紧…

全志T527芯片详解【三】:丰富接口

工业控制接口 T527集成了大量适用于工业场景的功能接口&#xff0c;包括PCle接口、CAN总线接口、UART接口和PWM接口等。 PCle是智慧工业领域广泛应用的接口&#xff0c;可满足数据高速传输的需求&#xff0c;亦可用于外接大算力NPU/GPU进行算力扩展、外接高速存储介质以及外接…

无忧易售ERP:赋能Onbuy平台,打造产品刊登新高度

在当今全球化的电商蓝海潮涌动下&#xff0c;Onbuy平台以其独特的优势吸引了众多卖家的目光&#xff0c;成为跨境贸易的一片新蓝海。然而&#xff0c;如何在这片海域中扬帆远航&#xff0c;快速、精准地将产品推向世界舞台&#xff0c;是每位卖家面临的挑战。此刻&#xff0c;无…

压缩视频在线压缩网站,压缩视频在线压缩工具软件

在数字化时代&#xff0c;视频成为了人们记录和分享生活的重要载体。然而&#xff0c;视频文件一般都非常大&#xff0c;这不仅占据了大量的存储空间&#xff0c;也给视频的传输和分享带来了不便。因此&#xff0c;压缩视频成为了许多人必须掌握的技能。本文将详细介绍如何压缩…

python数据分析-问卷数据分析(地理课)

学生问卷 分析学生背景&#xff1a;班级分布、每周地理课数量、地理成绩分布 根据问卷&#xff0c;可以知道&#xff1a; 班级分布&#xff1a; 七年级有118名学生。 八年级有107名学生。 每周地理课的数量&#xff1a; 有28名学生每周有1节地理课。 有99名学生每周有2…

python的plt.axis()、plt.xlim() 和 plt.ylim()函数

坐标轴相关设置1、plt.axis():坐标轴设置 函数 plt.axis(*v, **kwargs) 主要用于设置坐标轴的属性&#xff0c;返回值为当前的坐标轴范围 [xmin, xmax, ymin, ymax]&#xff0c;几种调用方式如下&#xff1a; 调用方式 说明 axis() 返回当前…

echarts学习: 在图表中添加多条y轴会怎么样?

前言 在撰写如何绘制双y轴图表文章时&#xff0c;我突然萌生出了一个想法&#xff0c;如果给图表添加两个以上的y轴会怎么样呢? 带着这个问题我开始了自己的探索之旅。 我找到了一篇优秀的文章作为参考&#xff0c;虽然它需要付费&#xff0c;但是不要紧&#xff0c;文中免费…

IP域名关系的研究与系统设计(学习某知名测绘系统)

IP域名关系库管理包括域名库检索和whois库检索&#xff0c;详情如下。 域名库检索支持以下5项功能&#xff1a; 1.通过过滤器检索 筛选条件包含IP地址、口令、工具名称、可利用的漏洞编号、创建时间&#xff1b; 2.通过关键字检索 在查询框中输入域名库名称的部分关键词&a…