视频V4改进

问1:

你好 下面是我的一个代码,我想通过代码实现对视频的每个不同的字幕帧截一个图保存下来

import cv2
import os
from skimage.metrics import structural_similarity as ssim
import numpy as np
from PIL import Image
# 视频路径
video_path = '/kaggle/input/202408282/vv1.mp4'  # 请替换为你的视频文件路径
output_dir = '/kaggle/working/captured_frames'
output_dir2 = '/kaggle/working'
os.makedirs(output_dir, exist_ok=True)

def save_frame(frame, count):
    """保存当前帧为图像文件"""
    img = Image.fromarray(frame)
    img.save(os.path.join(output_dir, f'frame_{count}.png'))

def compare_frames(prev_frame, current_frame, region):
    """比较两帧中指定区域的相似度"""
    x, y, w, h = region
    prev_cropped = prev_frame[y:y+h, x:x+w]
    curr_cropped = current_frame[y:y+h, x:x+w]
    
    # 转换为灰度图
    prev_gray = cv2.cvtColor(prev_cropped, cv2.COLOR_BGR2GRAY)
    curr_gray = cv2.cvtColor(curr_cropped, cv2.COLOR_BGR2GRAY)
    
    # 计算结构相似度 (SSIM)
    score, _ = ssim(prev_gray, curr_gray, full=True)
    
    return score

def capture_frames_with_changes(video_path, region, threshold=0.75):
    cap = cv2.VideoCapture(video_path)
    prev_frame = None
    count = 0

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        if prev_frame is not None:
            # 计算当前帧与上一帧中指定区域的相似度
            similarity = compare_frames(prev_frame, frame, region)
            print(f"Frame {count}: Similar = {similarity:.4f}")
            
            # 如果相似度低于阈值,认为发生了显著变化,保存帧
            if similarity < threshold:
                print(f"Significant change detected at frame {count}")
                save_frame(frame, count)
        prev_frame = frame
        count += 1
    
    cap.release()
    print(f"Finished processing. Total frames captured: {count}")

# 设置比较区域 (根据实际视频的内容调整)
# 请根据视频中需要比较的区域调整参数
compare_region = (260, 710, 940, 70)  # x, y, width, height

# 运行程序
capture_frames_with_changes(video_path, compare_region)

答1:

你好!从你提供的代码来看,你已经了通过比较视频中某个区域字幕位置)来检测帧与帧之间的差异,并保存发生显著变化的帧。这是一种不错的方法。下面我将帮助你检查代码并进行一些可能的优化和改进,以确保字幕帧能够准确地保存下来。

优化与改进点

SSIM的计算区域:你目前将一个固定区域(compare_region)作为字幕比较区域,建议在处理不同视频时可以动态调整此区域。字幕在不同的视频中位置可能不同,是否考虑让用户手动输入或用其他方式自动确定字幕区域?

重复保存第一帧:你目前的代码会保存第一帧,无论是否发生了字幕变化。如果你希望第一帧只在有字幕出现时保存,可以考虑在读取第一帧时该区域是否有字幕。

字幕帧识别:如果字幕区域的变化非常微小(比如只是字幕边缘闪烁),可能会导致误判。如果字幕变化的幅度较小,但频繁,可以适当调节阈值 threshold。

性能优化:视频处理可能非常耗时,特别是对于高分辨率视频。你可以考虑跳帧处理,即每隔几帧检查一次字幕变化,从而加快处理速度。

import cv2
import os
from skimage.metrics import structural_similarity as ssim
import numpy as np
from PIL import Image

# 视频路径
video_path = '/kaggle/input/202408282/vv1.mp4'  # 请替换为你的视频文件路径
output_dir = '/kaggle/working/V1/captured_frames'

os.makedirs(output_dir, exist_ok=True)

def save_frame(frame, count):
    """保存当前帧为图像文件"""
    img = Image.fromarray(frame)
    img.save(os.path.join(output_dir, f'frame_{count}.png'))

def compare_frames(prev_frame, current_frame, region):
    """比较两帧中指定区域的相似度"""
    x, y, w, h = region
    prev_cropped = prev_frame[y:y+h, x:x+w]
    curr_cropped = current_frame[y:y+h, x:x+w]
    
    # 转换为灰度图
    prev_gray = cv2.cvtColor(prev_cropped, cv2.COLOR_BGR2GRAY)
    curr_gray = cv2.cvtColor(curr_cropped, cv2.COLOR_BGR2GRAY)
    
    # 计算结构相似度 (SSIM)
    score, _ = ssim(prev_gray, curr_gray, full=True)
    
    return score

def capture_frames_with_changes(video_path, region, threshold=0.85, skip_frames=5):
    cap = cv2.VideoCapture(video_path)
    prev_frame = None
    count = 0
    saved_count = 0

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # 跳帧处理(例如每隔 skip_frames 帧处理一次)
        if count % skip_frames == 0:
            if prev_frame is None:
                # 保存第一帧
                save_frame(frame, count)
                print(f"Saved first frame at frame {count}")
                saved_count += 1
            else:
                # 计算当前帧与上一帧中指定区域的相似度
                similarity = compare_frames(prev_frame, frame, region)
                print(f"Frame {count}: Similarity = {similarity:.4f}")

                # 如果相似度低于阈值,认为发生了显著变化,保存帧
                if similarity < threshold:
                    print(f"Significant change detected at frame {count}")
                    save_frame(frame, count)
                    saved_count += 1

            prev_frame = frame
        
        count += 1

    cap.release()
    print(f"Finished processing. Total frames processed: {count}, Total frames saved: {saved_count}")

# 设置比较区域 (根据实际视频的内容调整)
compare_region = (260, 710, 940, 70)  # 这是字幕区域的x, y, width, height

# 运行程序
capture_frames_with_changes(video_path, compare_region)

改进说明

跳帧处理:通过 skip_frames 参数,程序会每隔 skip_frames 帧处理一次字幕变化。这样可以显著减少处理时间,特别适用于高帧率的视频。

保存帧计数:增加了 saved_count 变量来统计保存下来的帧数。

调整对比区域:可以根据视频字幕的位置调整 compare_region 的参数,使其更精确。

如何进一步改进

自动字幕区域检测:你可以使用OCR(如Tesseract)自动检测字幕区域,并在字幕变化时保存帧。这样即使字幕在不同视频中的位置不同,程序也能自动调整。

多线程处理:如果视频非常长,或者帧数非常多,可以使用多线程或GPU加速来提高处理速度。

希望这些改进能够帮助你更好地处理视频中的字幕帧!如果有进一步的问题,随时联系我!

问2:

我现在遇到的问题是,当视频出现新的字幕时会截取新字幕帧,但是当该字幕消失时(此时新的字幕还未出现)会截取没有字幕的帧,我只想截取有字幕的帧,但是我的视频文件和字幕文件不是独立的,字幕是嵌入在视频中的。我应该怎么做

答2:

为了只截取带有字幕的帧,你尝试使用光学字符识 (OCR) 来检测帧中的字幕区域。通过OCR技术,你可以识别每帧中的文本内容,判断是否有字幕出现,然后只保存包含字幕的帧,而忽略没有字幕的帧。

思路:

使用OCR识别字幕:在每一帧中使用OCR技术检测是否有字幕文本存在。

判断字幕是否存在:如果OCR结果有文本(即检测到字幕),则保存该帧;如果OCR没有检测到字幕,则跳过该帧。

跳帧处理:为了提高性能,依然可以使用跳帧处理,比如每隔几帧做一次字幕检测。

具体步骤:
安装OCR库:我们可以使用Tesseract,这是一个开源的OCR库,合从图像中提取文本。

首先,你需要确保安装了Tesseract。如果是在本地开发环境,使用以下命令:

bash

Copy code

  sudo apt-get install tesseract-ocr
  pip install pytesseract
使用OCR检测字幕帧:在每一帧中,提取字幕区域并使用Tesseract进行文本识别。如果识别到文本,就保存帧。

代码改进:

import cv2
import os
from PIL import Image
import pytesseract  # Tesseract的Python接口

# 视频路径
video_path = '/kaggle/input/202408282/vv1.mp4'  # 请替换为你的视频文件路径
output_dir =kaggle/working/V1/captured_frames'

os.makedirs(output_dir, exist_ok=True)

def save_frame(frame, count):
    """保存当前帧为图像文件"""
    img = Image.fromarray(frame)
    img.save(os.path.join(output_dir, f'frame_{count}.png'))

def extract_subtitle_text(frame, region):
    """从帧的指定区域提取文本"""
    x, y, w, h = region
    cropped_frame = frame[y:y+h, x:x+w]
    
    # 使用Tesseract进行OCR识别
    pil_image = Image.fromarray(cropped_frame)
    text = pytesseract.image_to_string(pil_image)
    
    return text.strip()

def capture_frames_with_subtitles(video_path, region, skip_frames=5):
    cap = cv2.VideoCapture(video_path)
    count = 0
    saved_count = 0

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # 跳帧处理(例如每隔 skip_frames 帧处理)
        if count % skip_frames == 0:
            # 从当前帧中提取字幕文本
            subtitle_text = extract_subtitle_text(frame, region)
            print(f"Frame {count}: Detected Subtitle = '{subtitle_text}'")
            
            # 如果检测到字幕(即文本不为空),保存帧
            if subtitle_text:
                print(f"Subtitle detected at frame {count}, saving frame.")
                save_frame(frame, count)
                saved_count += 1

        count += 1

    cap.release()
    print(f"Finished processing. Total frames processed: {count}, Total frames saved: {saved_count}")

# 设置比较区域 (根据实际视频的内容调整,字幕所在的x, y width, height)
compare_region = (260, 710, 940, 70) # 假设字幕位于此区域

# 运行程序
capture_frames_with_subtitles(video_path, compare_region)

代码说明:

extract_subtitle_text函数:该函数会从视频帧的指定区域中提取文本。你可以根据视频字幕的位置,调整 compare_region 的参数。

使用Tesseract OCR识别文本:通过 pytesseract.image_to_string 从帧的指定区域提取字幕文本,如果检测到有文本(即 subtitle_text 不为空),则保存当前帧。

跳帧处理:每隔 skip_frames 帧处理一次字幕检测,这可以显著提高性能,特别是处理高帧率的视频时。

需要注意的几点:

字幕区域的定位:你需要根据具体的视频调整 compare_region,确保该区域覆盖了字幕区域。如果字幕可能出现在多个位置,可以对多个区域进行检测。

OCR性能:Tesseract的速度可能不太快,如果你处理大量帧时,可以进一步优化,比如使用多线程或GPU加速(如果可能)。

字幕背景复杂性:如果字幕区域背景复杂或有噪声,可能会影响OCR的准确性。你可以考虑先对字幕区域进行预处理(比如提高对比度、二值化处理等),来提升OCR的效果。

通过这种方式,你就可以只截取包含字幕的帧,而忽略没有字幕的帧了。希望这个方法能解决你的问题!如果有其他问题,随时联系我。

问3:

我不想使用光学字符识 (OCR) 来检测帧中的字幕区域来判断该帧是否包含字幕,因为很容易出现错误

答3:

了解了你的需求,你希望避免使用 OCR 来识别字幕,这确实是一个不错的选择,尤其是在视频质量不佳或字幕复杂的情况下 OCR 容易出错。既然如此,我们尝试使用视频帧变化的其他特征来判断字幕是否存在,而不是依赖于光学字符识别。

方案思路:基于字幕区域的颜色或亮度变化来判断

字幕通常在固定的区域内出现,并且与背景有显著的颜色或亮度差异。我们可以通过检测字幕区域的像素变化(颜色或亮度)来判断是否有字幕出现。

方案步骤:

. 字幕区域检测:对比相邻帧的字幕区域,计算该区域内像素的变化情况。如果区域内的变化超过某个阈值,说明字幕出现。 2. 过滤无字幕帧:通过检测字幕区域的颜色变化,过滤掉不包含字幕的帧,仅保存字幕变化的帧。 3. 自定义变化阈值:通过调节变化检测的阈值,避免因视频噪声或细微变化导致误判。

代码实现:

我们可以使用 cv2.absdiff 函数计算前后两帧之间的差异,再结合简单的颜色变化统计,判断字幕是否发生了变化。

import cv2
import os
import numpy as np
from PIL import Image

# 视频路径
video_path = '/kaggle/input/202408282/vv1.mp4'  # 请替换为你的视频文件路径
output_dir = '/kaggle/working/V1/captured_frames'

os.makedirs(output_dir, exist_ok=True)

def save_frame(frame, count):
    """保存当前帧为图像文件"""
    img = Image.fromarray(frame)
    img.save(os.path.join(output_dir, f'frame_{count}.png'))

def detect_subtitle_change(prev_frame, current_frame, region, threshold=30):
 """检测字幕区域是否有明显变化"""
    x, y, w, h = region
    prev_cropped = prev_frame[y:y+h, x:x+w]
    curr_cropped = current_frame[y:y+h, x:x]
    
    # 计算两帧在字幕区域的差异
    frame_diff = cv2.absdiff(prev_cropped, curr_cropped)
    
    # 转为灰度图,计算变化像素的数量
    gray_diff = cv2.cvtColor(frame_diff, cv2.COLOR_BGR2GRAY)
    non_zero_count = np.count_nonzero(gray_diff > threshold)  # 变化像素的数量
    
    # 如果变化的像素数量超过一定比例,认为字幕区域发生了变化
    change_ratio = non_zero_count / (w * h)
    
    return change_ratio > 0.05  # 如果变化超过 5%,则认为有变化

def capture_frames_with_subtitles(video_path, region, skip_frames=5, threshold=30):
    cap = cv2.VideoCapture(video_path)
    prev_frame = None
    count = 0
    saved_count = 0

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # 跳帧处理
        if count % skip_frames == 0:
            if prev_frame is None:
                # 保存第一帧
                save_frame(frame, count)
                print(f"Saved first frame at frame {count}")
                saved_count += 1
            else:
                # 检测字幕区域是否发生变化
                subtitle_changed = detect_subtitle_change(prev_frame, frame, region, threshold)
                if subtitle_changed:
                    print(f"Subtitle detected at frame {count}, saving frame.")
                    save_frame(frame, count)
                    saved_count += 1

            prev_frame = frame
        
        count += 1

    cap.release()
    print(f"Finished processing. Total frames processed: {count}, Total frames saved: {saved_count}")

# 设置字幕区域 (根据实际视频的内容调整)
compare_region = (260, 710, 940, 70)  # 这是字幕区域的x, y, width, height

# 运行程序
capture_frames_with_subtitles(video, compare_region)

关键点解释:

字幕区域的变化检测:

使用 cv2.absdiff 函数计算前后两帧字幕区域的差异。这样可以检测到字幕出现或消失时的变化。

转换为灰度图后,统计像素差异较大的区域。如果差异超过某个阈值(例如 5%),则认为字幕区域发生了变化。

阈值调整:

threshold 控制检测的灵敏度。可以根据字幕的颜色和背景的对比度来调整。如果字幕与背景颜色差异较大,可以选择较低的阈值。反之则可以调高。

change_ratio 控制字幕区域变化的比例。如果字幕区域的变化像素占比超过这个阈值,系统就会判断字幕发生了变化。默认是 5%,可以根据实际情况调整。

跳帧处理:

通过 skip_frames 控制每隔几帧处理一次。比如设置为 5 时,程序会每隔 5 帧检测一次字幕变化,这样可以加快处理速度。

优化与调整:

字幕区域选择:根据你的视频实际情况,字幕可能在不同位置,你可以通过调整 compare_region 参数来选择合适的区域。如果字幕位置固定,效果会非常好。

跳帧间隔:你可以根据视频的帧率和字幕的变化频率调整 skip_frames,适当增大跳帧数量可以提升处理效率。

阈值调节:根据视频的清晰度和字幕与背景的对比,调节 threshold 和 change_ratio 来减少误判。

这样,你就可以通过帧间变化的检测方式来识别是否有字幕,而不会误判那些没有字幕的帧。希望这个方法可以解决你遇到的问题!如果还有其他问题,随时联系我。

答二的修改:

#修改1
import cv2
import os
import numpy as np
from PIL import Image

# 视频路径
video_path = '/kaggle/input/202408282/vv1.mp4'  # 请替换为你的视频文件路径
output_dir= '/kaggle/working/V1/captured_frames'

os.makedirs(output_dir, exist_ok=True)

def save_frame(frame, count):
    """保存当前帧为图像文件"""
    img = Image.fromarray(frame)
    img.save(os.path.join(output_dir, f'frame_{count}.png'))
def detect_subtitle_change(prev_frame, current_frame, region, threshold=30):
    """检测字幕区域是否有明显变化"""
    x, y, w, h = region
    prev_cropped = prev_frame[y:y+h, x:x+w]
    curr_cropped = current_frame[y:y+h, x:x+w]
    
    # 检查两帧的和通道是否一致
    if prev_cropped.shape != curr_cropped.shape:
        print("Error: Frame sizes do not match!")
        return False
    
    # 计算两帧在字幕区域的差异
    frame_diff = cv2.absdiff(prev_cropped, curr_cropped)
    
 # 转为灰度图,计算变化像素的数量
    gray_diff = cv2.cvtColor(frame_diff, cv2.COLOR_BGR2GRAY)
    non_zero_count = np.count_nonzero(gray_diff > threshold)  # 变化像素的数量
    
    # 如果变化的像素数量超过比例,认为字幕区域发生了变化
    change_ratio = non_zero_count / (w * h)
    print(f"F: {change_ratio}")
    return change_ratio > 0.5  # 如果变化超过 5%,则认为有变化

def capture_frames_with_subtitles(video_path, region, skip_frames=5, threshold=30):
    cap = cv2.VideoCapture(video_path)
    prev_frame = None
    count = 0
    saved_count = 0

    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # 跳帧处理
        if count % skip_frames == 0:
            if prev_frame is None:
                # 保存第一帧
                save_frame(frame, count)
                print(f"Saved first frame at {count}")
                saved_count += 1
            else:
                # 检测字幕区域发生变化
                subtitle_changed = detect_subtitle_change(prev_frame, frame, region, threshold)
                if subtitle_changed:
                    print(f"Subtitle detected at frame {count}, saving frame.")
                    save_frame(frame, count)
                    saved_count += 1

            prev_frame = frame
        
        count += 1

    cap.release()
    print(f"Finished processing. Total frames processed: {count}, Total frames saved: {saved_count}")

# 设置字幕区域 (根据实际视频的内容调整)
compare_region = (260, 710, 940, 70)  # 这是字幕区域的 x, y, width, height

# 运行程序
capture_frames_with_subtitles(video_path, compare_region)

import shutil

# 压缩文件夹
shutil.make_archive('/kaggle/working/V1/captured_frames2', 'zip', output_dir)

# 清空输出文件夹
output_dir3 = '/kaggle/working'
if os.path.exists(output_dir2):
    shutil.rmtree(output_dir2)  # 删除文件夹及其中的所有文件
#os.makedirs(output_dir2, exist_ok=True)  # 重新创建空文件夹
相关推荐
aqi001 小时前
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
android·ffmpeg·音视频·直播·流媒体
Liveweb视频汇聚平台2 小时前
Liveweb视频汇聚平台支持GB28181转RTMP、HLS、RTSP、FLV格式播放方案
websocket·网络协议·音视频·实时音视频·视频编解码
hawk2014bj3 小时前
使用开源 Whisper 视频转文字
深度学习·whisper·音视频
威桑3 小时前
详解 FFmpeg 中的 -map 选项
ffmpeg·音视频
青柠视频云11 小时前
青柠视频云——记一次大华摄像头公网语音对讲失败的问题分析
音视频·webrtc·实时音视频·h.265·h.264
FutureUniant15 小时前
GitHub每日最火火火项目(9.21)
人工智能·计算机视觉·ai·github·音视频
数据蛙苹果恢复专家17 小时前
无损转换:严选4个视频mkv转mp4格式的方法
音视频
EasyCVR17 小时前
视频存储EasyCVR视频监控汇聚管理平台设备录像下载报错404是什么原因?
音视频·视频监控·监控视频接入·视频质量诊断·视频诊断
aqi001 天前
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
android·ffmpeg·音视频·直播·流媒体