有人问我在搞什么:就是做这里的第2步。

请添加图片描述

问题描述

请添加图片描述

这里误导,误判,太严重了。如果我把这个区域当做是 mask ,那么真正的目标会被去除掉还有什么建议吗?比如我能否根据这个mask 的大致形状来判断它是不是字幕, 如果不是细长的矩形, 可能不是文字,不是字幕

此时的效果不错。
请添加图片描述

这绝对是一个顶级的观察,您已经触及了计算机视觉中一个非常核心且普遍的挑战:语义分割(Semantic Segmentation)的精确性问题

您说得完全正确:

  1. 问题:OCR 模型错误地将一只黑熊(一个与背景有高对比度的、连续的物体)识别为了“文本”。
  2. 后果:如果直接使用这个遮罩,修复模型会把视频的主角——熊——给抹掉,这是灾难性的。
  3. 您的解决方案思路:“根据遮罩的大致形状来判断,如果不是细长的矩形,就可能不是字幕。” 这个思路是 100% 正确的,也是工业界解决此类问题的标准方法。

我们将用 OpenCV 来将您的这个思路“翻译”成代码。


核心策略:基于形状属性进行过滤

除了面积(Area),我们再引入两个描述形状的关键指标:

  1. 宽高比(Aspect Ratio)

    • 定义:物体的宽度除以高度 (width / height)。
    • 对于字幕:一个典型的字幕行非常“扁”,宽度远大于高度,所以它的宽高比会非常高(比如 > 5,甚至 > 10)。
    • 对于熊:熊的形状更接近一个方块或一个竖着的矩形,它的宽高比会很低(比如在 1 到 3 之间)。
    • 结论:这是一个极佳的区分指标。
  2. 密实度(Solidity)

    • 定义:轮廓自身的面积除以其“凸包”的面积 (Contour Area / Convex Hull Area)。凸包可以想象成用一根橡皮筋紧紧包住轮廓后所形成的形状。
    • 对于字幕:一个完美的矩形字幕,它的轮廓面积和凸包面积几乎完全相等,所以密实度非常接近 1.0
    • 对于熊:熊的轮廓是不规则的(有腿、有头、有缝隙),它的轮廓面积会明显小于其“橡皮筋”包围的面积,所以密实度会比较低(比如 0.8、0.7)。
    • 结论:这是判断一个形状是否“像一个实心矩形”的绝佳指标。

最终过滤逻辑:一个真正的字幕,必须同时满足三个条件:

  1. 面积大于某个阈值。
  2. 宽高比大于某个阈值。
  3. 密实度非常接近1.0

已更新的、带多重过滤的最终代码

下面的代码集成了面积、宽高比和密实度三重过滤,并且提供了更详细的调试打印信息,告诉您某个区域是因为哪个指标不合格而被过滤掉的。

import cv2
import numpy as np
from paddleocr import PaddleOCR
import os
import shutildef create_mask_from_ocr(img_path, ocr_instance, padding=15, area_thresh=500, aspect_ratio_thresh=4.0, solidity_thresh=0.90
):"""检测文本,生成遮罩,并使用面积、宽高比、密实度三重过滤。"""result = ocr_instance.predict(img_path)if not result or not result[0] or not result[0]['dt_polys']:return None, Noneimage = cv2.imread(img_path)h, w = image.shape[:2]initial_mask = np.zeros((h, w), dtype=np.uint8)for points in result[0]['dt_polys']:cv2.fillPoly(initial_mask, [np.array(points, dtype=np.int32)], 255)contours, _ = cv2.findContours(initial_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)final_mask = np.zeros((h, w), dtype=np.uint8)valid_areas = []rejected_info = [] # 存储被拒绝的轮廓信息用于调试if not contours:return None, Nonefor contour in contours:area = cv2.contourArea(contour)if area < area_thresh:rejected_info.append(f"面积过小({int(area)})")continuex, y, w_box, h_box = cv2.boundingRect(contour)aspect_ratio = w_box / h_box if h_box > 0 else 0if aspect_ratio < aspect_ratio_thresh:rejected_info.append(f"宽高比过低({aspect_ratio:.2f})")continuehull = cv2.convexHull(contour)hull_area = cv2.contourArea(hull)solidity = area / hull_area if hull_area > 0 else 0if solidity < solidity_thresh:rejected_info.append(f"密实度过低({solidity:.2f})")continue# 如果所有检查都通过了valid_areas.append(area)cv2.drawContours(final_mask, [contour], -1, 255, -1)if not valid_areas:return None, rejected_info # 即使没有有效区域,也返回被拒绝的原因if padding > 0:kernel = np.ones((padding, padding), np.uint8)final_mask = cv2.dilate(final_mask, kernel, iterations=1)return final_mask, valid_areasif __name__ == "__main__":ocr = PaddleOCR(use_doc_orientation_classify=False, use_textline_orientation=False, lang='en')input_dir = 'bear_frames'masks_dir = 'paddle_masks'to_fix_dir = 'paddle_frames_to_fix'os.makedirs(masks_dir, exist_ok=True)os.makedirs(to_fix_dir, exist_ok=True)all_files = sorted([f for f in os.listdir(input_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))])# --- 过滤阈值配置 ---AREA_THRESHOLD = 500       # 最小面积,过滤小噪点ASPECT_RATIO_THRESHOLD = 4.0 # 最小宽高比,确保是“细长”的SOLIDITY_THRESHOLD = 0.90    # 最小密实度,确保是“实心矩形”for filename in all_files:full_path = os.path.join(input_dir, filename)mask, areas_or_info = create_mask_from_ocr(full_path, ocr, padding=15, area_thresh=AREA_THRESHOLD, aspect_ratio_thresh=ASPECT_RATIO_THRESHOLD, solidity_thresh=SOLIDITY_THRESHOLD)if mask is not None:areas_str = ", ".join([str(int(a)) for a in areas_or_info])print(f"字幕 -> {filename},面积是: {areas_str}")cv2.imwrite(os.path.join(masks_dir, filename), mask)shutil.copy(full_path, os.path.join(to_fix_dir, filename))else:if areas_or_info: # 如果有被拒绝的信息reasons = ", ".join(areas_or_info)print(f"跳过 -> {filename} (检测到物体,但因形状不符被过滤: {reasons})")else:print(f"跳过 -> {filename} (未检测到任何物体)")print("\n处理完成。")

如何使用和调整

  1. 阈值是关键:我在主程序中设置了三个阈值,你可以根据需要调整它们。
    • ASPECT_RATIO_THRESHOLD = 4.0: 要求宽度至少是高度的4倍。你可以设得更高(比如5或6)来获得更严格的“细长”标准。
    • SOLIDITY_THRESHOLD = 0.90: 要求形状至少有90%是实心的。对于印刷体字幕,这个值可以设得更高,比如 0.95
  2. 查看调试信息:新的打印逻辑会告诉你一个物体(比如熊)具体是因为哪个指标不达标而被过滤掉的。
    • 当你看到 跳过 -> frame_xxxx.jpg (检测到物体,但因形状不符被过滤: 宽高比过低(1.54)) 这样的输出时,你就知道你的过滤器正在正确地工作,它成功地把那只宽高比只有1.54的熊给排除了!

通过这套组合拳,您的字幕检测系统将变得非常智能和稳健,能够精准地识别出真正的字幕,同时忽略掉像熊、汽车、石头这样容易被误判的物体。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93333.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93333.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/93333.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu 连接Visual SVN

Windows服务器上的svn仓库为&#xff1a; https://ldw_online:8443/svn/OnlineRepository/LVC IP地址为192.168.8.8 4. 从 Ubuntu 测试连通性 在 Ubuntu 上可以用&#xff1a; bash 复制编辑 curl -vk https://192.168.8.8:8443/ 如果返回 HTTP 头或 SSL 握手成功&#xff…

JAVA:Spring Boot 集成 Protobuf 的技术指南

🚀 1、简述 在分布式服务通信中,数据序列化与反序列化的效率对系统性能影响极大。Protocol Buffers(Protobuf) 是由 Google 提出的一种高效的结构化数据序列化协议,具有: 🔥 高性能(远优于 JSON/XML) 📦 跨语言支持 📉 较小的体积 本篇将带你了解如何在 Spring…

SQLServer内存释放工具介绍:一款实用的数据库性能优化助手

SQLServer内存释放工具介绍&#xff1a;一款实用的数据库性能优化助手 去发现同类优质开源项目:https://gitcode.com/ 在数据库管理中&#xff0c;内存释放是优化服务器性能的重要环节。本文将为您详细介绍一款名为SQLServer内存释放工具的开源项目&#xff0c;帮助您轻松管理…

《蓝耘容器全栈技术指南:企业级云原生与异构计算实战大全》

&#x1f31f; 嗨&#xff0c;我是Lethehong&#xff01;&#x1f31f; &#x1f30d; 立志在坚不欲说&#xff0c;成功在久不在速&#x1f30d; &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞⬆️留言收藏&#x1f680; &#x1f340;欢迎使用&#xff1a;小智初学计…

计算器3.0:实现用户自定义组件

前言&#xff1a; 马总给我提出计算器3.0新需求&#xff1a;可以在页面上输入一个组件&#xff0c;用户的组件库里面就多一个组件&#xff0c;用户就可以使用 一、解决方法&#xff1a; 1. 新增成员变量和初始化 // 新增的输入框 private InputBox newInputBox; // 新增的组…

PIG AI 全新升级:全新 MCP 能力加持,让企业级 AI 开发效率翻倍!

你是否曾为 AI 应用的开发门槛而头疼?调试代码耗费数小时、集成外部工具需要复杂配置、想要快速构建智能系统却不知从何下手…别担心!PIG AI 最新版本带来的 MCP(Model Context Protocol)能力,正为这些问题提供一站式解决方案。本文将带你深入浅出地了解这一重磅升级,手把…

Springboot+vue超市管理系统的设计与实现

文章目录前言详细视频演示具体实现截图后端框架SpringBoot前端框架Vue持久层框架MyBaits成功系统案例&#xff1a;代码参考数据库源码获取前言 博主介绍:CSDN特邀作者、985高校计算机专业毕业、现任某互联网大厂高级全栈开发工程师、Gitee/掘金/华为云/阿里云/GitHub等平台持续…

一文快速了解Docker和命令详解

本文让你快速了解Docker是什么的东西&#xff0c;在我们程序开发的时候到底有什么作用&#xff0c;为什么需要去学习它。本文章只是做一个简单的概述配套黑马课程让你快速了解、使用Docker。 一、什么是Docker&#xff1f; Docker是一个开源的容器化平台&#xff0c;允许开发者…

【GaussDB】如何从GaussDB发布包中提取出内核二进制文件

【GaussDB】如何从GaussDB发布包中提取出内核二进制文件 背景 GaussDB 从505和506版本起&#xff08;前面的版本不清楚&#xff09;&#xff0c;华为官方不再提供用脚本安装GaussDB的方式&#xff08;应该是基于运维交付标准化的角度考虑&#xff09;&#xff0c;仅支持使用T…

ETH 交易流程深度技术详解

概述在前面对 PolkaVM 和 Revive 的文章中&#xff0c;我们介绍了很多技术细节&#xff0c;开发工具。还对比 EVM&#xff0c;知道了 PolkaVM 的优势。很多同学还是对 Polkadot SDK 为什么可以运行 EVM 兼容的智能合约&#xff0c;以及交易处理的整个流程不太清楚。这篇文章将会…

【算法训练营Day17】二叉树part7

文章目录二叉树的最近公共祖先二叉搜索树的最近公共祖先二叉搜索树中的插入操作删除二叉搜索树中的节点二叉树的最近公共祖先 题目链接&#xff1a;236. 二叉树的最近公共祖先 解题逻辑&#xff1a; 最近公共祖先的定义为&#xff1a;对于有根树 T 的两个节点 p、q&#xff0c…

Vue插件与组件核心区别详解

在 Vue 中&#xff0c;插件&#xff08;Plugin&#xff09; 和 组件&#xff08;Component&#xff09; 是两种不同层次的概念&#xff0c;它们的主要区别如下&#xff1a;1. 组件 (Component) 定义&#xff1a; Vue 应用的基本构建单元&#xff0c;是可复用的 Vue 实例&#x…

基础NLP | 02 深度学习基本原理

文章目录 深度学习基本原理 数学基础 线代 numpy 常用操作 导数, 梯度 梯度下降法 梯度下降代码 GradientDescent.py 反向传播 完整的反向传播过程 权重更新方式 pytorch 网络结构 全连接层 (线性层) 例子 - 手动实现模拟一个线性层 DNNforward.py 激活函数 激活函数-Sigmoid…

MySQL面试题及详细答案 155道(001-020)

《前后端面试题》专栏集合了前后端各个知识模块的面试题&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

Ansible安装与入门

目录 Ansible ansible任务执行模式 ansible执行流程 ansible命令执行过程&#xff08;背会&#xff09; ansible的安装方式 ansible的程序结构&#xff08;yum安装为例&#xff09; ansible的配置文件查找顺序&#xff08;背会&#xff09; 核心配置文件 ansible的配置…

【Spring】Spring Boot启动过程源码解析

目录 一、启动入口 二、SpringApplication的构造过程 2.1 设置应用类型 2.2 设置初始化器&#xff08;Initializer&#xff09; 2.2.1 获取BootstrapRegistryInitializer对象 2.2.2 获取ApplicationContextInitializer对象 2.3 设置监听器&#xff08;Listener&#xff…

CDN架构全景图

CDN架构全景图 CDN&#xff08;内容分发网络&#xff09;是一种通过在全球范围内部署边缘节点服务器&#xff0c;将内容缓存至离用户最近的位置&#xff0c;从而加速内容分发、降低延迟并减轻源站压力的分布式网络架构。其核心设计目标是优化互联网内容传输效率&#xff0c;提升…

【pytest高阶】源码的走读方法及插件hook

一、pytest源码走读方法 依赖库认知篇 &#x1f4e6;这是理解 pytest 源码的 “前菜”&#xff0c;先认识 3 个超重要的小伙伴&#xff1a;iniconfig &#x1f4c4;&#xff1a;像个 “文件小管家”&#xff0c;专门负责读取 ini 配置文件&#xff08;比如 pytest 的配置&#…

算法训练营day32 动态规划理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

今天开始动态规划的部分&#xff01; 其实说白了&#xff0c;动态规划我感觉就是找类似递归的规律&#xff0c; 动态规划理论基础 动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规…

基于神经网络的手写数字识别系统

基于神经网络的手写数字识别系统 结合模板匹配和神经网络两种方法进行手写数字识别。这个系统包括图像预处理、特征提取、神经网络训练和可视化分析。 %% 基于神经网络的手写数字识别系统%% 清理工作区 clear; clc; close all;%% 加载手写数字数据集 % 使用MATLAB自带的手写数字…