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 设置确保录像的流畅性,确保在低成本的硬件环境下依然能够有效地进行高质量的流星监控录像


相关文章
|
5月前
|
存储 监控 Java
python自研流星监控系统meteor_monitor(第一篇)
本文介绍了作者开发的一个Python流星监控系统,替代了性能不佳且收费的ufocapturehd2软件。系统采用Win10相机应用低耗录制视频,通过SikuliX进行自动化控制,分段录制并存储到本地,然后通过脚本同步到NAS。视频分析使用帧差法检测流星,支持分布式分析。代码已更新,旧文章不再适用,最新内容可见:[用python自行开发的流星监控系统meteor_monitor(第二篇)-CSDN博客](https://github.com/xingxinghuo1000/meteor_monitor_scripts.git)。
|
算法 数据挖掘 API
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
156 0
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
|
算法 数据挖掘 API
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
Sentieon|应用教程:利用Sentieon Python API引擎为自研算法加速
89 0
|
3天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
3天前
|
机器学习/深度学习 数据挖掘 Python
Python编程入门——从零开始构建你的第一个程序
【10月更文挑战第39天】本文将带你走进Python的世界,通过简单易懂的语言和实际的代码示例,让你快速掌握Python的基础语法。无论你是编程新手还是想学习新语言的老手,这篇文章都能为你提供有价值的信息。我们将从变量、数据类型、控制结构等基本概念入手,逐步过渡到函数、模块等高级特性,最后通过一个综合示例来巩固所学知识。让我们一起开启Python编程之旅吧!
|
3天前
|
存储 Python
Python编程入门:打造你的第一个程序
【10月更文挑战第39天】在数字时代的浪潮中,掌握编程技能如同掌握了一门新时代的语言。本文将引导你步入Python编程的奇妙世界,从零基础出发,一步步构建你的第一个程序。我们将探索编程的基本概念,通过简单示例理解变量、数据类型和控制结构,最终实现一个简单的猜数字游戏。这不仅是一段代码的旅程,更是逻辑思维和问题解决能力的锻炼之旅。准备好了吗?让我们开始吧!
|
5天前
|
设计模式 算法 搜索推荐
Python编程中的设计模式:优雅解决复杂问题的钥匙####
本文将探讨Python编程中几种核心设计模式的应用实例与优势,不涉及具体代码示例,而是聚焦于每种模式背后的设计理念、适用场景及其如何促进代码的可维护性和扩展性。通过理解这些设计模式,开发者可以更加高效地构建软件系统,实现代码复用,提升项目质量。 ####
|
4天前
|
机器学习/深度学习 存储 算法
探索Python编程:从基础到高级应用
【10月更文挑战第38天】本文旨在引导读者从Python的基础知识出发,逐渐深入到高级编程概念。通过简明的语言和实际代码示例,我们将一起探索这门语言的魅力和潜力,理解它如何帮助解决现实问题,并启发我们思考编程在现代社会中的作用和意义。
|
5天前
|
机器学习/深度学习 数据挖掘 开发者
Python编程入门:理解基础语法与编写第一个程序
【10月更文挑战第37天】本文旨在为初学者提供Python编程的初步了解,通过简明的语言和直观的例子,引导读者掌握Python的基础语法,并完成一个简单的程序。我们将从变量、数据类型到控制结构,逐步展开讲解,确保即使是编程新手也能轻松跟上。文章末尾附有完整代码示例,供读者参考和实践。
|
5天前
|
人工智能 数据挖掘 程序员
Python编程入门:从零到英雄
【10月更文挑战第37天】本文将引导你走进Python编程的世界,无论你是初学者还是有一定基础的开发者,都能从中受益。我们将从最基础的语法开始讲解,逐步深入到更复杂的主题,如数据结构、面向对象编程和网络编程等。通过本文的学习,你将能够编写出自己的Python程序,实现各种功能。让我们一起踏上Python编程之旅吧!