基于树莓派的流星雨监测系统(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
相关文章
|
存储 域名解析 数据安全/隐私保护
离线云监测系统OCMS软件
OCMS 是什么? OCMS ( Offline Cloud Monitoring System)是利用人们熟知的稳定可靠的第三方电子邮件、FTP 服务商提供的数据永久存储服务作为中间环节,监测设备向服务器发送数据,监测软件从服务器获取数据的以非实时在线的方式工作的无线监测预警系统。 具有数据可靠、部署快捷、操作简单、无需在线等主要优势和特点。
离线云监测系统OCMS软件
|
1月前
|
数据采集 监控 测试技术
大型IM稳定性监测实践:手Q客户端性能防劣化系统的建设之路
本文以iOS端为例,详细分享了手 Q 客户端性能防劣化系统从0到1的构建之路,相信对业界和IM开发者们都有较高的借鉴意义。
90 2
|
4月前
|
数据采集 监控 网络协议
LabVIEW开发工业设备远程在线状态监测
LabVIEW开发工业设备远程在线状态监测
25 2
|
25天前
|
存储 监控 数据管理
不会写代码,我如何开发一套设备巡检系统
在竞争激烈的商业环境中,中小企业常面临设备管理和维护的难题。由于预算有限和信息化能力不足,它们难以找到合适的管理系统。无代码平台的出现为这些问题提供了高性价比的解决方案。此类平台允许非技术背景的业务人员自行搭建设备巡检系统,不仅开发和部署速度快,而且成本低。草料二维码无代码平台便是一个典型例子,它可以帮助企业批量生成设备二维码、设置巡检项、安排巡检周期,并自动通知维修人员处理异常情况。此外,平台还提供了多种防作弊措施,确保巡检工作的规范性。所有巡检记录均可在电脑端进行管理和打印,方便企业进行数据分析和存档。这一平台特别适合预算有限且追求轻量化解决方案的中小企业。
|
1月前
|
监控 安全 iOS开发
|
3月前
|
存储 Shell 开发工具
基于树莓派的流星雨监测系统(RMS)的搭建
该文介绍了基于树莓派的流星雨监测系统的改造系列,包括改造的第二和第三部分。作者分享了选用索尼IMX291 USB摄像头和大光圈镜头的设备选型,并提供了树莓派的固定及防反光处理方法。文章简化了RMS安装过程,强调了针对USB摄像头用户的安装步骤,通过创建venv、安装依赖库和脚本实现开机自动运行。此外,还调整了系统参数以适应城市光污染环境,并修改了监测时间以避免室内灯光干扰。
|
4月前
|
传感器 数据可视化 物联网
LabVIEW开发低成本静脉监测和控制输液系统
LabVIEW开发低成本静脉监测和控制输液系统
43 2
|
4月前
|
数据采集 存储 监控
LabVIEW起重机工作参数远程监测系统
LabVIEW起重机工作参数远程监测系统
31 1
|
4月前
|
运维 网络协议 安全
【专栏】30个必备的思科设备巡检命令,涵盖设备基本信息、性能、网络连接、安全及其它重要方面
【4月更文挑战第28天】本文列举了30个必备的思科设备巡检命令,涵盖设备基本信息、性能、网络连接、安全及其它重要方面。这些命令包括`show version`、`show running-config`、`show ip route`、`show access-lists`等,对监控设备状态、排查故障及优化性能至关重要。熟悉并运用这些命令能提升网络工程师的工作效率,确保网络稳定运行。不断学习新命令以适应网络技术发展是网络工程师的必修课。
448 0
|
监控 算法 调度
转:时间片轮转算法对电脑监控软件的影响
时间片轮转算法是操作系统中常用的一种进程调度算法,它就像是个大调度师,负责把CPU时间切成小块,让一帮进程轮番上阵,保证大家都有公平的机会争夺计算力,好让系统不再卡顿。现在,要是把这时间片轮转算法和电脑监控软件捆绑在一起,就像是一对独特的组合拳,会激发出一堆影响。比如监控效率会变得咋样,员工的个人秘密会不会被窥探,还有系统的资源会不会被合理利用,用户体验会不会哭唧唧?下面,我们就一起来探讨一下时间片轮转算法对电脑监控软件的影响——
86 0