基于树莓派的流星雨监测系统(RMS)的进一步改造(1)

简介: 本文介绍了如何搭建和改造流星雨监测系统,主要涉及两个步骤。首先,文章提供了访问[此处链接](https://blog.csdn.net/delacroix_xu/article/details/119813807)来了解如何搭建系统。接着,针对系统输出的.bin文件格式,作者改造了FRbinViewer.py脚本,增加了输出MP4和GIF格式的功能。改造后的脚本可以根据用户选择将检测到的流星雨帧保存为.gif或.mp4格式,并提供了相应的参数设置。此外,文章还包含了代码示例以展示如何实现这一功能。

如何搭建流星雨监测系统,传送门:https://blog.csdn.net/delacroix_xu/article/details/119813807


进一步改造系列文章,第二篇,传送门:https://blog.csdn.net/delacroix_xu/article/details/119744925


背景:

近期开始使用一个开源项目,在树莓派4B上玩耍。监测流星雨并存储下来。


https://github.com/CroatianMeteorNetwork/RMS


但该项目有个令人不爽的地方,存储下来的是.bin文件,一种自研的格式,我希望能输出gif或者mp4,方便分享到社交媒体上。


FRbinViewer.py 增加功能


1、输出 MP4格式的文件


新增参数 -f avi 实际输出的是mp4文件, 该参数需要配合 --extract 参数一起使用。该功能会在.bin文件同一级目录下,生成对应的mp4文件


举例说明:


python Utils/FRbinViewer.py  ~/RMS_data/ArchivedFiles/XX_0001_20210723/  --extract -f avi --hide


--hide 表示不显示到屏幕上


2、输出gif文件


新增参数 -f gif 。会在.bin文件同一级目录下,生成对应的gif文件


具体使用方法,同 -f avi




""" Showing fireball detections from FR bin files. """
 
# RPi Meteor Station
# Copyright (C) 2017  Dario Zubovic, Denis Vida
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
from __future__ import print_function, absolute_import, division
 
import os
import sys
 
sys.path.append("./")
import argparse
 
import cv2
from cv2 import VideoWriter, VideoWriter_fourcc
from PIL import Image as PILImage
import numpy as np
import Utils.ConvertPng2Avi as cp2a
import imageio
import shutil
 
import RMS.ConfigReader as cr
from RMS.Formats import FFfile, FRbin
 
 
def view(dir_path, ff_path, fr_path, config, save_frames=False, extract_format='png', hide=False,
    avg_background=False):
    """ Shows the detected fireball stored in the FR file. 
    
    Arguments:
        dir_path: [str] Current directory.
        ff: [str] path to the FF bin file
        fr: [str] path to the FR bin file
        config: [conf object] configuration structure
    Keyword arguments:
        save_frames: [bool] Save FR frames to disk. False by defualt.
        extract_format: [str] Format of saved images. png by default.
        hide: [bool] Don't show frames on the screen.
        avg_background: [bool] Avepixel as background. False by default, in which case the maxpixel will be
            used.
    """
 
    if extract_format is None:
        extract_format = 'png'
    
    name = fr_path
    fr = FRbin.read(dir_path, fr_path)
 
    print('------------------------')
    print('Showing file:', fr_path)
 
 
    if ff_path is None:
        #background = np.zeros((config.height, config.width), np.uint8)
 
        # Get the maximum extent of meteor frames
        y_size = max([max(np.array(fr.yc[i]) + np.array(fr.size[i])//2) for i in range(fr.lines)])
        x_size = max([max(np.array(fr.xc[i]) + np.array(fr.size[i])//2) for i in range(fr.lines)])
 
        # Make the image square
        img_size = max(y_size, x_size)
 
        background = np.zeros((img_size, img_size), np.uint8)
 
    else:
        if avg_background:
            background = FFfile.read(dir_path, ff_path).avepixel
        else:
            background = FFfile.read(dir_path, ff_path).maxpixel
    
    print("Number of lines:", fr.lines)
    
    first_image = True
    wait_time = 2*int(1000.0/config.fps)
 
    pause_flag = False
 
    
    print("output format: ", extract_format)
    for current_line in range(fr.lines):
 
        # if output format is gif , then declare this variable
        if extract_format == 'gif':
            gif_frames = []
        
        # if outpu format is avi, then declare this variable
        if extract_format == 'avi':
            videoWriter = None
            temp_dir = os.path.join(dir_path, "TEMP_DIR_" + fr_path.replace('.bin', ''))
            if os.path.exists(temp_dir):
                shutil.rmtree(temp_dir)
            
        print('Frame,  Y ,  X , size')
        
        for z in range(fr.frameNum[current_line]):
 
            # Get the center position of the detection on the current frame
            yc = fr.yc[current_line][z]
            xc = fr.xc[current_line][z]
 
            # Get the frame number
            t = fr.t[current_line][z]
 
            # Get the size of the window
            size = fr.size[current_line][z]
            
            print("  {:3d}, {:3d}, {:3d}, {:d}".format(t, yc, xc, size))
 
            img = np.copy(background)
            
            # Paste the frames onto the big image
            y_img = np.arange(yc - size//2, yc + size//2)
            x_img = np.arange(xc - size//2,  xc + size//2)
 
            Y_img, X_img = np.meshgrid(y_img, x_img)
 
            y_frame = np.arange(len(y_img))
            x_frame = np.arange(len(x_img))
 
            Y_frame, X_frame = np.meshgrid(y_frame, x_frame)                
 
            img[Y_img, X_img] = fr.frames[current_line][z][Y_frame, X_frame]
 
 
            # Save frame to disk
            if save_frames:
                if extract_format == "png":
                    frame_file_name = fr_path.replace('.bin', '') \
                        + "_line_{:02d}_frame_{:03d}.{:s}".format(current_line, t, extract_format)
                    cv2.imwrite(os.path.join(dir_path, frame_file_name), img)
                elif extract_format == 'gif':
                    gif_frames.append(img)
                elif extract_format == "avi":
                    
                    if not os.path.exists(temp_dir):
                        os.makedirs(temp_dir)
                    frame_file_name = os.path.join(
                        temp_dir, 
                        "line_{:02d}_frame_{:03d}.png".format(current_line, t)
                    )
                    cv2.imwrite(frame_file_name, img)
                
                
 
            if not hide:
            
                # Show the frame
                try:
                    cv2.imshow(name, img)
                except:
                    print("imshow not available in OpenCV, Rebuild the library with Windows, GTK+ 2.x or Cocoa support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'")
                    hide = True
                    first_image = False
                    continue
 
                # If this is the first image, move it to the upper left corner
                if first_image:
                    cv2.moveWindow(name, 0, 0)
                    first_image = False
 
 
                if pause_flag:
                    wait_time = 0
                else:
                    wait_time = 2*int(1000.0/config.fps)
 
                # Space key: pause display. 
                # 1: previous file. 
                # 2: next line. 
                # q: Quit.
                key = cv2.waitKey(wait_time) & 0xFF
 
                if key == ord("1"): 
                    cv2.destroyWindow(name)
                    return -1
 
                elif key == ord("2"): 
                    break
 
                elif key == ord(" "): 
                    
                    # Pause/unpause video
                    pause_flag = not pause_flag
 
                elif key == ord("q") : 
                    os._exit(0)
        
        # if gif format is set, then output gif file
        if extract_format == 'gif':
            
            gif_name = fr_path.replace('.bin', '.gif')
            gif_path = os.path.join(dir_path, gif_name)
            print(" try output gif file: ", gif_path)
            imageio.mimsave(gif_path, gif_frames, 'GIF', duration=2*1.0/config.fps)
        
        # release handle
        if extract_format == 'avi':
            temp_dir = os.path.join(dir_path, "TEMP_DIR_" + fr_path.replace('.bin', ''))
            cp2a.convert_from_dir(
                temp_dir, 
                "",
                os.path.join(dir_path, fr_path.replace('.bin', '.mp4')),
                config.fps,
                True
            )
            
            
    if not hide:
        cv2.destroyWindow(name)
            
 
if __name__ == "__main__":
 
    ### COMMAND LINE ARGUMENTS
 
    # Init the command line arguments parser
    arg_parser = argparse.ArgumentParser(description="""Show reconstructed fireball detections from FR files.
        Key mapping:
            Space: pause display.
            1: previous file.
            2: next line.
            q: Quit.
            """, formatter_class=argparse.RawTextHelpFormatter)
 
    arg_parser.add_argument('dir_path', nargs=1, metavar='DIR_PATH', type=str, \
        help='Path to the directory which contains FR bin files.')
 
    arg_parser.add_argument('-e', '--extract', action="store_true", \
        help="Save frames from FR files to disk.")
 
    arg_parser.add_argument('-a', '--avg', action="store_true", \
        help="Average pixel as the background instead of maxpixel.")
 
    arg_parser.add_argument('-x', '--hide', action="store_true", \
        help="Do not show frames on the screen.")
    
    arg_parser.add_argument('-f', '--extractformat', metavar='EXTRACT_FORMAT', help="""Image format for extracted files. png by default. gif is supported """)
 
    # Parse the command line arguments
    cml_args = arg_parser.parse_args()
 
    #########################
 
    dir_path = cml_args.dir_path[0]
 
    # Load the configuration file
    config = cr.parse(".config")
 
    
 
    # Get the list of FR bin files (fireball detections) in the given directory
    fr_list = [fr for fr in os.listdir(dir_path) if fr[0:2]=="FR" and fr.endswith('bin')]
    fr_list = sorted(fr_list)
 
    if not fr_list:
 
        print("No files found!")
        sys.exit()
 
    # Get the list of FF bin files (compressed video frames)
    ff_list = [ff for ff in os.listdir(dir_path) if FFfile.validFFName(ff)]
    ff_list = sorted(ff_list)
 
 
    i = 0
 
    while True:
 
        # Break the loop if at the end
        if i >= len(fr_list):
            break
 
        fr = fr_list[i]
 
        ff_match = None
 
        # Strip extensions
        fr_name = ".".join(fr.split('.')[:-1]).replace('FR', '').strip("_")
 
        # Find the matching FF bin to the given FR bin
        for ff in ff_list:
 
            # Strip extensions
            ff_name = ".".join(ff.split('.')[:-1]).replace('FF', "").strip("_")
 
 
            if ff_name[2:] == fr_name[2:]:
                ff_match = ff
                break
        print("ff_match:", ff_match)
        # View the fireball detection
        retval = view(dir_path, ff_match, fr, config, save_frames=cml_args.extract, \
            extract_format=cml_args.extractformat, hide=cml_args.hide, avg_background=cml_args.avg)
 
        # Return to previous file
        if retval == -1:
            i -= 2
 
        if i < 0:
            i = 0
 
        i += 1
相关文章
|
6月前
|
编解码 算法 固态存储
Visual C++ 6.0环境开发PACS影像系统的技术指标和精准算法
Visual C++ 6.0环境开发PACS影像系统的技术指标和精准算法
57 0
|
3月前
|
传感器 C# 监控
硬件交互新体验:WPF与传感器的完美结合——从初始化串行端口到读取温度数据,一步步教你打造实时监控的智能应用
【8月更文挑战第31天】本文通过详细教程,指导Windows Presentation Foundation (WPF) 开发者如何读取并处理温度传感器数据,增强应用程序的功能性和用户体验。首先,通过`.NET Framework`的`Serial Port`类实现与传感器的串行通信;接着,创建WPF界面显示实时数据;最后,提供示例代码说明如何初始化串行端口及读取数据。无论哪种传感器,只要支持串行通信,均可采用类似方法集成到WPF应用中。适合希望掌握硬件交互技术的WPF开发者参考。
68 0
|
5月前
|
存储 Shell 开发工具
基于树莓派的流星雨监测系统(RMS)的搭建
该文介绍了基于树莓派的流星雨监测系统的改造系列,包括改造的第二和第三部分。作者分享了选用索尼IMX291 USB摄像头和大光圈镜头的设备选型,并提供了树莓派的固定及防反光处理方法。文章简化了RMS安装过程,强调了针对USB摄像头用户的安装步骤,通过创建venv、安装依赖库和脚本实现开机自动运行。此外,还调整了系统参数以适应城市光污染环境,并修改了监测时间以避免室内灯光干扰。
|
4月前
|
数据采集 存储 监控
通过LabVIEW提升生产设备自动化水平
通过LabVIEW提升生产设备自动化水平
34 0
|
6月前
|
传感器 存储 数据采集
LabVIEW通过视频识别开发布氏硬度机自动化测量系统
LabVIEW通过视频识别开发布氏硬度机自动化测量系统
47 4
|
6月前
|
数据采集 数据可视化 测试技术
五台山风景区旅游模拟漫游系统的设计与实现_kaic
五台山风景区旅游模拟漫游系统的设计与实现_kaic
|
运维 算法 调度
(文章复现)建筑集成光储系统规划运行综合优化方法matlab代码
参考文献: [1]陈柯蒙,肖曦,田培根等.一种建筑集成光储系统规划运行综合优化方法[J].中国电机工程学报,2023,43(13):5001-5012.
|
存储 数据库
PACS系统源码,自主研发,3D重建、三维虚拟内窥镜、心脏动脉钙化分析
RIS/PACS系统源码是按照DICOM3.0和HL7标准,遵循IHE标准工作流程, 100%自主知识产权,以医疗影像的采集、传输、存储和诊断为核心,集流程质控、患者信息管理应用和患者关注服务于一体的,覆盖放射、超声、窥镜和病理等科室的CS架构的综合应用系统。集成三维影像后处理功能,包括三维多平面重建、三维容积重建、三维表面重建、三维虚拟内窥镜、最大/小密度投影、心脏动脉钙化分析等功能。系统功能强大,代码完整。
154 0
PACS系统源码,自主研发,3D重建、三维虚拟内窥镜、心脏动脉钙化分析
利用AidLux实现热成像电力巡检项目操作演示
本项目参考AidLux五月实战训练营内容:基于热成像的巡检及AidLux工程方案。利用AIdlux平台和手机移动端算力,轻松落地部署基于热成像智能巡检项目。
|
网络协议 网络虚拟化 网络架构
路由与交换利用ENSP模拟器分析和配置中小型企业网络的综合实验(上)
路由与交换利用ENSP模拟器分析和配置中小型企业网络的综合实验
4133 1
路由与交换利用ENSP模拟器分析和配置中小型企业网络的综合实验(上)