如何用Python+OpenCV检测视频为逐行或隔行扫描?
判断视频逐行/隔行扫描的两种方法
方法一:使用OpenCV内置属性
OpenCV提供了cv2.CAP_PROP_INTERLACED属性,可以直接查询视频的扫描类型,返回值规则如下:
- 0:逐行扫描(progressive)
- 1:隔行扫描(interlaced)
- -1:无法检测(取决于视频后端支持)
你可以把这个属性查询加入到现有代码中:
cam: cv2.VideoCapture = cv2.VideoCapture(filename) if cam.isOpened(): video_codec: str = cam.get(cv2.CAP_PROP_FOURCC) video_fps: int = cam.get(cv2.CAP_PROP_FPS) video_height: int = cam.get(cv2.CAP_PROP_FRAME_HEIGHT) video_width: int = cam.get(cv2.CAP_PROP_FRAME_WIDTH) total_frames: int = cam.get(cv2.CAP_PROP_FRAME_COUNT) length: int = int(total_frames / video_fps) audio_samplerate: int = cam.get(cv2.CAP_PROP_AUDIO_SAMPLES_PER_SECOND) audio_channels: int = cam.get(cv2.CAP_PROP_AUDIO_TOTAL_CHANNELS) # 新增:查询扫描类型 interlaced_flag = cam.get(cv2.CAP_PROP_INTERLACED) if interlaced_flag == 0: print("视频为逐行扫描") elif interlaced_flag == 1: print("视频为隔行扫描") else: print("无法通过内置属性确定扫描类型,建议使用帧内容检测法")
注意:这个属性的有效性依赖于视频的编码格式和OpenCV使用的后端(比如FFmpeg),部分老旧或特殊编码的视频可能返回-1,这时需要用第二种方法。
方法二:基于帧内容的检测(更可靠)
如果内置属性无法给出结果,可以通过分析视频帧的奇偶行差异来判断:隔行扫描的视频中,相邻帧的奇行和偶行是在不同时间捕获的,当画面有运动时,奇偶行的内容会出现明显错位。
具体实现步骤:
- 读取连续两帧
- 分离每帧的奇数行和偶数行
- 计算相邻帧对应行的像素差异均值
- 根据差异阈值判断是否为隔行扫描
代码示例:
import cv2 import numpy as np def is_interlaced_by_frame_analysis(filename, threshold=10.0, sample_frames=5): cam = cv2.VideoCapture(filename) if not cam.isOpened(): return None # 跳过前几帧(避免开头黑屏/静态帧) cam.set(cv2.CAP_PROP_POS_FRAMES, min(10, cam.get(cv2.CAP_PROP_FRAME_COUNT)-2)) prev_frame = None diff_scores = [] for _ in range(sample_frames): ret, frame = cam.read() if not ret: break if prev_frame is None: prev_frame = frame continue # 转换为灰度图减少计算量 gray_prev = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY) gray_curr = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 分离奇偶行 prev_odd = gray_prev[1::2, :] # 奇数行(索引1,3,5...) prev_even = gray_prev[0::2, :] # 偶数行(索引0,2,4...) curr_odd = gray_curr[1::2, :] curr_even = gray_curr[0::2, :] # 计算相邻帧对应行的差异 diff_odd = np.mean(np.abs(curr_odd - prev_even)) diff_even = np.mean(np.abs(curr_even - prev_odd)) avg_diff = (diff_odd + diff_even) / 2 diff_scores.append(avg_diff) prev_frame = frame cam.release() if not diff_scores: return None # 取平均差异值,超过阈值则判断为隔行扫描 avg_score = np.mean(diff_scores) return avg_score > threshold # 使用示例 is_interlaced = is_interlaced_by_frame_analysis("your_video.mp4") if is_interlaced is True: print("视频为隔行扫描") elif is_interlaced is False: print("视频为逐行扫描") else: print("无法确定视频扫描类型")
说明:
- 阈值可以根据实际情况调整,一般运动场景下隔行视频的差异均值会远高于逐行视频
- 跳过开头几帧是为了避免静态帧导致的误判
- 转换为灰度图可以大幅减少计算量,不影响检测结果
内容的提问来源于stack exchange,提问作者Eelco
相关产品推荐
相关产品推荐

