seo查询 站长工具,章丘哪里做网站,wordpress 情侣博客,rss订阅wordpress文章目录 0. 引言1. 原始设计分析2. 新的设计思路2.1 定义通用的检测接口2.2 使用 std::function 和 std::any 管理检测模块2.3 构建可动态配置的检测管道 3. 示例实现3.1 定义检测接口和模块3.1.1 检测接口3.1.2 信号检测模块3.1.3 冻结检测模块3.1.4 其他检测模块 3.2 构建检… 文章目录 0. 引言1. 原始设计分析2. 新的设计思路2.1 定义通用的检测接口2.2 使用 std::function 和 std::any 管理检测模块2.3 构建可动态配置的检测管道 3. 示例实现3.1 定义检测接口和模块3.1.1 检测接口3.1.2 信号检测模块3.1.3 冻结检测模块3.1.4 其他检测模块 3.2 构建检测管道3.2.1 初始化管道3.2.2 创建检测模块实例3.2.3 将检测模块添加到管道 3.3 执行检测管道3.4 完整代码示例 4. 设计优势4.1 灵活性和可扩展性4.2 模块化和可维护性4.3 利用现代 C 特性 5. 参考资料 0. 引言
在整理视频质量诊断程序模块代码时发现处理流程通常是固定的各种检测功能以函数形式顺序调用。这种设计缺乏灵活性不易于扩展和维护。本文将使用 C17 的 std::function 和 std::any重新设计视频质量诊断处理流程实现模块化、可灵活扩展的处理管道。
视频质量诊断涉及多个检测模块如信号检测、冻结检测、遮挡检测等。 详细见
C基于opencv4的视频质量检测C基于opencv的视频质量检测–图像清晰度检测C基于opencv的视频质量检测–画面冻结检测C基于opencv的视频质量检测–图像抖动检测C基于opencv的视频质量检测–遮挡检测
本文将采用面向接口的设计使用现代 C 特性构建一个可动态配置的处理管道。
1. 原始设计分析
原始代码中各个检测功能以独立的函数实现处理流程固定
signalDetect();
freezeframeDetect();
occlusionDetect();
brightnessDetect();
snownoiseDetect();
stripeDetect();
cameramoveDetect();
sharpnessDetect();
colorDetect();
jitterDetect();这种设计存在以下问题
缺乏灵活性处理流程固定无法根据需求动态调整检测模块的顺序或添加新的检测功能。可扩展性差添加新的检测功能需要修改主流程代码增加了维护成本。模块耦合度高各个检测函数之间可能存在隐式依赖不利于模块化管理。
2. 新的设计思路
流程图 #mermaid-svg-Ay45BRbfmH4oWIBJ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .error-icon{fill:#552222;}#mermaid-svg-Ay45BRbfmH4oWIBJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ay45BRbfmH4oWIBJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .marker.cross{stroke:#333333;}#mermaid-svg-Ay45BRbfmH4oWIBJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ay45BRbfmH4oWIBJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .cluster-label text{fill:#333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .cluster-label span{color:#333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .label text,#mermaid-svg-Ay45BRbfmH4oWIBJ span{fill:#333;color:#333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .node rect,#mermaid-svg-Ay45BRbfmH4oWIBJ .node circle,#mermaid-svg-Ay45BRbfmH4oWIBJ .node ellipse,#mermaid-svg-Ay45BRbfmH4oWIBJ .node polygon,#mermaid-svg-Ay45BRbfmH4oWIBJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ay45BRbfmH4oWIBJ .node .label{text-align:center;}#mermaid-svg-Ay45BRbfmH4oWIBJ .node.clickable{cursor:pointer;}#mermaid-svg-Ay45BRbfmH4oWIBJ .arrowheadPath{fill:#333333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ay45BRbfmH4oWIBJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-Ay45BRbfmH4oWIBJ .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-Ay45BRbfmH4oWIBJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ay45BRbfmH4oWIBJ .cluster text{fill:#333;}#mermaid-svg-Ay45BRbfmH4oWIBJ .cluster span{color:#333;}#mermaid-svg-Ay45BRbfmH4oWIBJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Ay45BRbfmH4oWIBJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是 否 开始 初始化阈值和标志位 构建检测管道 遍历检测管道 执行检测模块 结束 2.1 定义通用的检测接口
借鉴 COM 的接口设计思想定义一个通用的检测接口 IVideoQualityDetector
class IVideoQualityDetector {
public:virtual int Detect(const cv::Mat img, const cv::Mat img_jitterRef, const cv::Mat img_moveRef,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) 0;virtual ~IVideoQualityDetector() default;
};每个具体的检测模块都实现该接口实现其特定的检测逻辑。
2.2 使用 std::function 和 std::any 管理检测模块
std::function用于存储各个检测模块的调用方法便于在管道中按顺序执行。std::any用于存储不同类型的检测模块实例实现类型擦除支持在运行时动态管理模块。
2.3 构建可动态配置的检测管道
将各个检测模块实例化后添加到一个检测管道如 std::vectorstd::functionint(...)中。这样可以根据需求动态调整检测模块的顺序、添加或移除检测模块。
3. 示例实现
3.1 定义检测接口和模块
3.1.1 检测接口
class IVideoQualityDetector {
public:virtual int Detect(const cv::Mat img, const cv::Mat img_jitterRef, const cv::Mat img_moveRef,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) 0;virtual ~IVideoQualityDetector() default;
};3.1.2 信号检测模块
class SignalDetector : public IVideoQualityDetector {
public:int Detect(const cv::Mat img, const cv::Mat, const cv::Mat,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) override {// 实现信号检测逻辑if (img.empty()) return NO_DETECT;detectData-signalVal signalDetect(img);if (detectData-signalVal threshold.signalThreshold) {detectDescribe-nosignalDescribe NO_SIGNAL;return SIGNAL_DETECT;} else {detectDescribe-nosignalDescribe SIGNAL_NORMAL;}return NO_DETECT;}
};3.1.3 冻结检测模块
class FreezeFrameDetector : public IVideoQualityDetector {
public:int Detect(const cv::Mat img, const cv::Mat img_jitterRef, const cv::Mat,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) override {// 实现冻结检测逻辑if (img.empty() || img_jitterRef.empty()) return NO_DETECT;detectData-freezeFrameVal 1 - freezeFrameDetect(img, img_jitterRef);if (detectData-freezeFrameVal threshold.freezeFrameThreshold) {detectDescribe-freezeFrameDescribe FREEZEFRAME_YES;return FREEZEFRAME_DETECT;} else {detectDescribe-freezeFrameDescribe FREEZEFRAME_NO;}return NO_DETECT;}
};3.1.4 其他检测模块
按照上述方式实现其他检测模块遮挡检测、亮度检测、雪花噪点检测等每个模块继承 IVideoQualityDetector 接口实现其特定的 Detect 方法。
3.2 构建检测管道
3.2.1 初始化管道
std::vectorstd::functionint(const cv::Mat, const cv::Mat, const cv::Mat,const Threshold_t, DetectDescribe_t*, DetectData_t*) detectPipeline;3.2.2 创建检测模块实例
std::any signalDetector std::make_uniqueSignalDetector();
std::any freezeFrameDetector std::make_uniqueFreezeFrameDetector();
// ... 创建其他检测模块实例3.2.3 将检测模块添加到管道
detectPipeline.push_back([](const cv::Mat img, const cv::Mat img_jitterRef, const cv::Mat img_moveRef,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) {return std::any_castSignalDetector(signalDetector).Detect(img, img_jitterRef, img_moveRef,threshold, detectDescribe, detectData);
});detectPipeline.push_back([](const cv::Mat img, const cv::Mat img_jitterRef, const cv::Mat img_moveRef,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) {return std::any_castFreezeFrameDetector(freezeFrameDetector).Detect(img, img_jitterRef, img_moveRef,threshold, detectDescribe, detectData);
});
// ... 将其他检测模块添加到管道3.3 执行检测管道
for (auto detectFunc : detectPipeline) {detectFunc(img, img_jitterRef, img_moveRef, threshold, detectDescribe, detectData);
}3.4 完整代码示例
这里仅展示主要结构完整代码应包括所有检测模块的实现。
#include iostream
#include vector
#include functional
#include any
#include opencv2/opencv.hpp// 定义相关的常量、结构体和函数如 Threshold_t、DetectDescribe_t、DetectData_t、signalDetect 等class IVideoQualityDetector {
public:virtual int Detect(const cv::Mat img, const cv::Mat img_jitterRef, const cv::Mat img_moveRef,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) 0;virtual ~IVideoQualityDetector() default;
};class SignalDetector : public IVideoQualityDetector {
public:int Detect(const cv::Mat img, const cv::Mat, const cv::Mat,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) override {// 信号检测实现}
};// ... 实现其他检测模块int ROCK_QualityDiagnoseFromMat(const cv::Mat img, cv::Mat img_jitterRef, cv::Mat img_moveRef,Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData, unsigned int flag) {// 初始化阈值和标志位init_threshold(threshold);init_flag(flag);// 构建检测管道std::vectorstd::functionint(const cv::Mat, const cv::Mat, const cv::Mat,const Threshold_t, DetectDescribe_t*, DetectData_t*) detectPipeline;std::any signalDetector std::make_uniqueSignalDetector();// ... 创建其他检测模块实例// 根据标志位添加需要的检测模块if (flag SIGNAL_DETECT) {detectPipeline.push_back([](const cv::Mat img, const cv::Mat img_jitterRef, const cv::Mat img_moveRef,const Threshold_t threshold, DetectDescribe_t* detectDescribe,DetectData_t* detectData) {return std::any_castSignalDetector(signalDetector).Detect(img, img_jitterRef, img_moveRef,threshold, detectDescribe, detectData);});}// ... 根据其他标志位添加检测模块// 执行检测管道for (auto detectFunc : detectPipeline) {detectFunc(img, img_jitterRef, img_moveRef, threshold, detectDescribe, detectData);}return 0;
}4. 设计优势
4.1 灵活性和可扩展性
动态配置检测模块可以根据需要在运行时添加、移除或重新排列检测模块无需修改主流程代码。支持新功能的扩展添加新检测功能只需实现 IVideoQualityDetector 接口并在构建管道时添加即可。
4.2 模块化和可维护性
降低模块耦合度各个检测模块独立实现遵循统一的接口模块之间无直接依赖。易于维护和测试每个检测模块可以独立开发和测试提高代码质量。
4.3 利用现代 C 特性
std::function方便地管理和调用函数对象实现检测管道的灵活组织。std::any实现类型擦除支持在运行时管理不同类型的检测模块实例。
5. 参考资料
C17 std::function 文档C17 std::any 文档OpenCV 官方文档