python自研流星监控系统meteor_monitor(第二篇)

简介: 该文介绍了替代流星监控软件UFOcaptureHD2的新方案,强调了原软件的性能消耗大和收费问题。文中提供了一个GitHub链接以获取最新代码。推荐使用配备Windows 10/11、2.4GHz四核CPU的主机,搭配索尼MX291摄像头进行监控。程序基于ffmpeg,支持不同编码器,如mjpeg、h264_qsv等,具体编码器选择取决于硬件环境。安装涉及创建虚拟环境、安装Python 3.10+及依赖项,并提供了Windows和Linux的详细步骤。此外,程序通过帧差法进行运动检测,然后过滤掉非流星目标,最后使用ffmpeg对原始视频切片并存储。

代码已开源:

https://github.com/xingxinghuo1000/meteor_monitor_scripts.git


本篇为最新代码的方案介绍和使用介绍。第一篇已经过时了,不建议看 。只看这一篇即可。


背景

著名的流星监控软件ufocapturehd2有几个缺陷,不能忍

1、吃性能,我的工控电脑2.4GHz的4核心CPU,发现流星后,录制出来的视频,会严重丢帧

2、收费。还相当的贵。大概700多元? 用破解版当然也可以,这里不推荐


使用方法

推荐硬件

主机:

windows系统,win10 win11. 小主机, cpu 2.4GHz, 4核心.

不推荐Linux系统, 因为显卡驱动不容易安装,需要较高的技术水平.

不推荐树莓派, 原因同Linux系统.



image.png



摄像头的选择

推荐使用 索尼 MX291 摄像头. CMOS底比较大,适合拍摄星空

如果您的摄像头CMOS尺寸太小, 则噪点会比较多. 所以推荐IMX291这款, 如果使用IMX485, 则更好.


image.png




如何使用

建议在windows使用,原因是显卡驱动程序比较容易安装. 在Ubuntu下intel核心显卡驱动安装比较困难,无法使用h264_qsv编码

本程序默认使用mjpeg码流, 如果cpu支持硬件编码h264,则可以尝试使用h264_qsv编码器

如果是windows环境 , 且是 Intel核心显卡, 则可以尝试h264_qsv编码, nvdia显卡尝试 h264_nvenc, amd显卡尝试 h264_amf

如果是Ubuntu环境, 请尝试 mjpeg 编码, 经过我的测试, 2.4GHzCPU 只能达到15fps, 如果需要更高比如30fps,则对CPU要求也会很高.

如果您在Ubuntu环境,安装好了显卡驱动程序, Intel核心显卡可以尝试 h264_qsv 编码, nvdia显卡尝试 h264_nvenc, amd显卡尝试 h264_amf

如果是树莓派, 且编译了带h264_omx编码的ffmpeg, 则编码器使用 h264_omx


安装ffmpeg

本程序依赖ffmpeg命令,

我目前只测试过 4.x.x 版本的ffmpeg, 不能保证 5.x 和 6.x也能正常工作

Windows环境,需要到ffmpeg官网(Download FFmpeg) 下载ffmpeg可执行程序, 下载压缩包,解压缩到某个目录, 并将目录添加到环境变量. 如何验证安装是否成功, 可以打开cmd, 输入 ffmpeg -v 看看是否能正常看到输出的版本号

Linux环境, sudo yum install ffmpeg 或者 sudo apt install ffmpeg, 验证方法, 在shell中输入 ffmpeg -v 看看是否正常显示版本号

如果是树莓派, 则需要手工编译ffmpeg, 启用h264_omx编码, 比较麻烦, 不推荐.


插入usb摄像头

将usb摄像头插入主机的usb口, 执行下面的命令, 检查系统是否能正常识别摄像头

Windows中, 打开cmd 输入 ffmpeg -list_devices true -f dshow -i dummy 看看返回结果

Linux系统中, 在shell中输入 ffmpeg -hide_banner -sources v4l2 看看返回结果

如何修改配置文件.config 参考.config.xx文件,对应你的操作系统, 配置 文件中都有说明

比如win11系统,可以参考.config.win

如果是Ubuntu系统,可以参考.config.linux

如何设置分辨率和fps?

根据自己的硬件性能,逐步调整fps到可用的程度. 如果 ffmpeg 日志中提示丢帧, 则fps设置过大, 需要降低fps, 以保证画面流畅

还要看摄像头支持哪些分辨率.如果设置错误,则无法录制视频



查看摄像头信息

根据ffmpeg显示出来的信息, 查看摄像头支持哪些分辨率和fps. 配置到.config 文件中



配置Python环境

版本: 推荐使用Python 3.10及以上

步骤1

新建virtual env. 在 detect_meteor目录下, 执行如下命令

windows下, python3 -m venv venv

Linux下, python3 -m venv venv


步骤2

安装依赖

windows下, 打开 cmd, 在 detect_meteor 目录下, 执行命令 .\venv\Script\python -m pip install -r requirement.txt

Linux下, 在 detect_meteor目录下, 执行命令 ./venv/bin/python -m pip install -r requirement.txt


步骤3

运行本程序

windows下, 双击 offline_detect_from_mp4.bat

Linux下, 在detect_meteor目录下, 执行 sh run.sh


步骤4

配置开机自动启动,

Windows下, 右键点击 offline_detect_from_mp4.bat, 发送到桌面快捷方式, 将 快捷方式,复制到 开始菜单的 启动 目录

Linux下, crontable中配置 */5 * * * * cd /home/yourname/workspace/meteor_monitor_script/detect_meteor && sh run.sh


步骤5 可选

配置 mask-1280-720.bmp 遮罩图像, 目的是排除掉画面中的一些非天空部分, 这部分可能会引起False Positive, 流星的误报

比如 画面中远处楼宇的灯光变化, 可能会让程序以为是有画面变化

问题: 在哪个目录新建 遮罩图像?

答: 在视频目标输出目录, 在配置文件的 base_output_path 选项, 该路径由您指定

问题: 遮罩图像黑色白色代表什么意思?

答: 黑色表示要遮盖的部分, 白色表示要检测的部分



原理介绍

高效的录制mp4视频

使用ffmpeg, 高效录制视频. 这部分,我没有足够能力使用python实现, 所以借助ffmpeg的能力

ffmpeg 支持多种编码格式, h264支持多种硬件加速, 比如Intel核心显卡, nvdia显卡, AMD显卡

备注: 曾经使用过一个方案 使用windows自带的相机app,进行录像. 这个方案不够稳定, 已被废弃. 该方案使用sikuli进行UI自动化操作, 非常不稳定.



为了帮您理解该项目,下面是一个代码示例片段,演示如何使用 Python 和 FFmpeg 从 USB 摄像头录制视频,并自动获取摄像头的最佳帧率和最大画面尺寸:


import subprocess
import re

def get_camera_info():
    # 使用 ffmpeg 获取摄像头信息
    cmd = ["ffmpeg", "-f", "v4l2", "-list_formats", "all", "-i", "/dev/video0"]
    result = subprocess.run(cmd, stderr=subprocess.PIPE, text=True)

    # 解析输出以获取最佳帧率和最大画面尺寸
    output = result.stderr
    frame_rates = []
    resolutions = []

    for line in output.split("\n"):
        # 获取帧率信息
        frame_rate_match = re.search(r"([0-9]+(\.[0-9]+)?) fps", line)
        if frame_rate_match:
            frame_rates.append(float(frame_rate_match.group(1)))

        # 获取分辨率信息
        resolution_match = re.search(r"([0-9]+)x([0-9]+)", line)
        if resolution_match:
            width = int(resolution_match.group(1))
            height = int(resolution_match.group(2))
            resolutions.append((width, height))

    best_frame_rate = max(frame_rates) if frame_rates else 30  # 如果未找到,默认为30fps
    max_resolution = max(resolutions, key=lambda x: x[0]*x[1]) if resolutions else (640, 480)  # 默认640x480

    return best_frame_rate, max_resolution

def record_video(output_file, duration):
    best_frame_rate, max_resolution = get_camera_info()
    width, height = max_resolution

    # 使用 ffmpeg 录制视频
    cmd = [
        "ffmpeg",
        "-f", "v4l2",
        "-framerate", str(best_frame_rate),
        "-video_size", f"{width}x{height}",
        "-i", "/dev/video0",
        "-t", str(duration),
        "-c:v", "libx264",
        "-preset", "fast",
        "-pix_fmt", "yuv420p",
        output_file
    ]

    subprocess.run(cmd)

# 调用示例
output_video_path = "output_video.mp4"
record_duration = 10  # 录制10秒
record_video(output_video_path, record_duration)


  1. 获取摄像头信息 get_camera_info:
  • 使用 FFmpeg 命令列出摄像头支持的所有格式。
  • 解析 FFmpeg 的输出以获取帧率和分辨率信息。
  • 选择最佳帧率和最大分辨率。
  1. 录制视频 record_video:
  • 使用上面函数获取最佳帧率和最大分辨率。
  • 调用 FFmpeg 命令通过 USB 摄像头录制视频,并使用 H.264 编码。
  1. FFmpeg 命令解释:
  • -f v4l2:指定输入格式为 V4L2(Video for Linux 2)。
  • -framerate:设置帧率。
  • -video_size:设置分辨率。
  • -i /dev/video0:指定输入设备为 USB 摄像头。
  • -t:设置录制时长。
  • -c:v libx264:指定视频编码器为 H.264。
  • -preset fast:设置编码速度,fast 是编码速度和质量之间的平衡。
  • -pix_fmt yuv420p:设置像素格式为 YUV 4:2:0。

请注意:

  • /dev/video0 是 Linux 下的摄像头设备路径。对于 Windows 系统可以使用如 -i video="YOUR_CAMERA_NAME".
  • 在运行代码之前,请确保你的摄像头可以被 FFmpeg 识别,并且你的系统 PATH 中包含了 FFmpeg 程序。

通过上述代码,你可以实现从 USB 摄像头录制视频,并根据摄像头的最佳帧率和最大画面尺寸来设置录制参数



离线分析流星

为什么不做实时分析?

因为硬件性能不够. 我的目的是在低配置的硬件上,运行本程序. 如果您的硬件性能已经很强悍, 则建议直接使用ufohd2



离线分析的原理


步骤1

使用典型的opencv 运动检测算法: 帧差法, 识别画面的变化。为了讲解原理,下面给一个代码示例


功能描述:

  1. 视频文件的读取:
  • 使用 cv2.VideoCapture 打开视频文件。
  • 检查视频是否成功打开。
  1. 帧的读取和预处理:
  • 循环读取视频帧,并将其转换为灰度图像。
  • 使用一个列表 frames 来存储最近的五个灰度帧。
  1. 判断画面变化:
  • 每次读取新帧时,将其添加到 frames 列表中,并移除列表中最早的一帧,以确保列表长度为 5。
  • 当 frames 列表中有五帧时,计算第一个和第五个帧之间的差异。
  • 使用阈值处理和膨胀操作填补孔洞,以便更好地检测轮廓,并忽略小的变化区域。
  • 查找并绘制检测到的运动区域。
  1. 显示结果:
  • 显示当前帧和帧差图像。
  • 每隔 5 帧进行一次判断,因此设置循环间隔为 30 毫秒(可根据需要调整)。
  1. 释放资源:
  • 释放视频捕获对象和关闭所有窗口。


import cv2

def main():
    # 打开视频文件
    cap = cv2.VideoCapture('your_video_file.mp4')  # 替换为你的视频文件路径

    # 检查视频是否成功打开
    if not cap.isOpened():
        print("Error: Could not open video.")
        return

    # 用于存储当前帧和前五帧的列表
    frames = []

    while True:
        ret, frame = cap.read()

        # 如果视频读取结束,退出循环
        if not ret:
            break

        # 转换为灰度图
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # 将当前帧添加到帧列表中
        frames.append(gray)

        # 保持帧列表的长度为5
        if len(frames) > 5:
            frames.pop(0)

        # 计算每隔五帧之间的帧差
        if len(frames) == 5:
            frame_diff = cv2.absdiff(frames[0], frames[4])

            # 阈值处理
            _, thresh = cv2.threshold(frame_diff, 25, 255, cv2.THRESH_BINARY)

            # 膨胀操作以填补孔洞
            thresh = cv2.dilate(thresh, None, iterations=2)

            # 查找轮廓
            contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            # 绘制检测到的运动区域
            for contour in contours:
                if cv2.contourArea(contour) < 500:  # 忽略小的变化区域
                    continue
                (x, y, w, h) = cv2.boundingRect(contour)
                cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

            # 显示结果
            cv2.imshow('Motion Detection', frame)
            cv2.imshow('Frame Diff', frame_diff)

        # 每隔5帧进行判断,所以这里以5帧为间隔
        if cv2.waitKey(30) & 0xFF == 27:  # 按下ESC键退出
            break

    # 释放资源
    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()


通过上述代码,你可以计算每隔五帧之间的差异,并判断画面是否有变动。你可以根据自己的需要调整阈值和帧间隔,以获得更好的检测效果




步骤2

根据一些特征,过滤掉不是流星的东西, 比如蝙蝠, 小飞虫等。该部分逻辑,不具备通用性,请参考最上方源码查看具体原理。



步骤3

使用ffmpeg 将原始视频切片, 切片后单独存储起来。 以下是示例代码



介绍:FFmpeg 是一个强大的多媒体处理工具,可以轻松实现视频的切割、转换等操作。我们可以使用 subprocess 模块来调用 FFmpeg 命令。

首先你需要确保已经安装 FFmpeg,你可以从 FFmpeg 官网 下载并安装它。

下面是一个 Python 函数示例,使用 FFmpeg 来切割视频文件并输出多个视频文件。


功能描述:

  1. 获取视频的帧率 (fps):
  • 使用 ffprobe 命令来获取输入视频的帧率。这个步骤很重要,因为你需要用帧率来将起始帧转化为时间秒数。
  1. 切割视频文件:
  • 循环遍历 start_frames_list,对于每个起始帧,计算其对应的时间秒数。
  • 使用 ffmpeg 命令切割视频。-ss 参数指定起始时间,-t 参数指定切割时长,-c copy 参数表示直接拷贝视频流而不进行重新编码,从而加速处理。
  1. 调用示例:
  • video_path 指定输入视频文件。
  • output_directory 指定输出视频片段存放的目录。
  • start_frames_list 给定起始帧列表,假设我们想从第0帧、第150帧、第300帧开始切割视频。
  • duration_in_seconds 指定每段视频的时长(秒)。


import subprocess
import os

def cut_video(input_file, output_dir, start_frames, duration):
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    # 获取视频的帧率 (fps)
    cmd = [
        "ffprobe",
        "-v", "error",
        "-select_streams", "v:0",
        "-show_entries", "stream=r_frame_rate",
        "-of", "default=noprint_wrappers=1",
        input_file
    ]
    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    fps_str = result.stdout.strip().split('=')[1]
    fps = eval(fps_str)
    
    # 切割视频
    for i, start_frame in enumerate(start_frames):
        start_time = start_frame / fps  # 计算起始时间(秒)
        output_file = os.path.join(output_dir, f'output_{i}.mp4')
        cmd = [
            "ffmpeg",
            "-i", input_file,
            "-ss", str(start_time),
            "-t", str(duration),
            "-c", "copy",
            output_file
        ]
        subprocess.run(cmd)

# 示例调用
video_path = 'input_video.mp4'
output_directory = 'output_videos'
start_frames_list = [0, 150, 300]  # 示例起始帧,假设我们想从第0帧、第150帧、第300帧开始切割
duration_in_seconds = 10  # 每段视频的时长为10秒

cut_video(video_path, output_directory, start_frames_list, duration_in_seconds)



总结

本文介绍了如何使用 Python 和 FFmpeg 来替代 ufocapturehd2 进行流星监控录像,并针对其高性能消耗和高价格等缺点提供了优化方案。推荐在 Windows 系统上进行部署,使用索尼 IMX291 或 IMX485 摄像头以获得高质量画面。根据硬件环境的不同,选择适合的编码器以达到性能最佳:如 Intel 核心显卡的 h264_qsv,NVIDIA 显卡的 h264_nvenc 和 AMD 显卡的 h264_amf。在 Ubuntu 和树莓派环境下,编码配置更为复杂,需要特别注意显卡驱动的安装。本方案强调离线分析以适配低性能硬件,通过逐步调整 FPS 设置确保录像的流畅性,确保在低成本的硬件环境下依然能够有效地进行高质量的流星监控录像


相关文章
|
1月前
|
存储 监控 Java
python自研流星监控系统meteor_monitor(第一篇)
本文介绍了作者开发的一个Python流星监控系统,替代了性能不佳且收费的ufocapturehd2软件。系统采用Win10相机应用低耗录制视频,通过SikuliX进行自动化控制,分段录制并存储到本地,然后通过脚本同步到NAS。视频分析使用帧差法检测流星,支持分布式分析。代码已更新,旧文章不再适用,最新内容可见:[用python自行开发的流星监控系统meteor_monitor(第二篇)-CSDN博客](https://github.com/xingxinghuo1000/meteor_monitor_scripts.git)。
|
11月前
|
算法 数据挖掘 API
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
126 0
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
|
11月前
|
算法 数据挖掘 API
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
63 0
|
4天前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
18 3
|
6天前
|
开发者 Python
Python元类实战:打造你的专属编程魔法,让代码随心所欲变化
【7月更文挑战第7天】Python的元类是编程的变形师,用于创建类的“类”,赋予代码在构建时的变形能力。
30 1
|
7天前
|
设计模式 存储 Python
Python元类大揭秘:从理解到应用,一步步构建你的编程帝国
【7月更文挑战第6天】Python元类是创建类的对象的基石,允许控制类的生成过程。通过自定义元类,可在类定义时动态添加方法或改变行为。
16 0
|
4天前
|
数据采集 大数据 数据安全/隐私保护
Python编程:如何有效等待套接字的读取与关闭
Python网络编程中,套接字事件处理至关重要。利用`selectors`模块和代理IP能增强程序的稳定性和可靠性。代码示例展示了如何通过代理连接目标服务器,注册套接字的读写事件并高效处理。在代理IP配置、连接创建、事件循环及回调函数中,实现了数据收发与连接管理,有效应对网络爬虫或聊天应用的需求,同时保护了真实IP。
Python编程:如何有效等待套接字的读取与关闭
|
2天前
|
Python
不容错过!Python中图的精妙表示与高效遍历策略,提升你的编程艺术感
【7月更文挑战第11天】在Python编程中,图以邻接表或邻接矩阵表示,前者节省空间,后者利于查询连接。通过字典实现邻接表,二维列表构建邻接矩阵。图的遍历包括深度优先搜索(DFS)和广度优先搜索(BFS)。DFS使用递归,BFS借助队列。这些基础技巧对于解决复杂数据关系问题,如社交网络分析或迷宫求解,至关重要,能提升编程艺术。
11 5
|
4天前
|
存储 算法 Python
震撼!Python算法设计与分析,分治法、贪心、动态规划...这些经典算法如何改变你的编程世界!
【7月更文挑战第9天】在Python的算法天地,分治、贪心、动态规划三巨头揭示了解题的智慧。分治如归并排序,将大问题拆解为小部分解决;贪心算法以局部最优求全局,如Prim的最小生成树;动态规划通过存储子问题解避免重复计算,如斐波那契数列。掌握这些,将重塑你的编程思维,点亮技术之路。
13 1
|
6天前
|
程序员 Python
从零到一,彻底掌握Python闭包与装饰器的精髓,成为编程界的隐藏Boss
【7月更文挑战第7天】探索Python编程的两大基石:闭包与装饰器。闭包是内部函数记住外部作用域的变量,如`make_multiplier_of`返回的`multiplier`,它保持对`n`的引用。装饰器则是函数工厂,接收函数并返回新函数,如`my_decorator`,它在不改变原函数代码的情况下添加日志功能。掌握这些,让代码更优雅,效率更高,助你成为编程高手。
16 3

相关实验场景

更多