1. 用 Python 監(jiān)控 NASA TV 直播畫面

        共 22626字,需瀏覽 46分鐘

         ·

        2021-05-21 02:37

        本文分享一個名為"Spacestills"的開源程序,它可以用于查看 NASA TV 的直播畫面(靜止幀)。
        演示地址:
        https://replit.com/@PaoloAmoroso/spacestills


        在Replit上運行的Spacestills主窗口
        這是一個具有GUI的簡單系統(tǒng),它訪問feed流并從Web下載數(shù)據(jù)。該程序僅需350行代碼,并依賴于一些開源的Python庫。
        關(guān)于程序
        Spacestills會定期從feed流中下載NASA TV靜止幀并將其顯示在GUI中。
        該程序可以校正幀的縱橫比,并將其保存為PNG格式。它會自動下載最新的幀,并提供手動重新加載,禁用自動重新加載或更改下載頻率的選項。
        Spacestillsis是一個比較初級的版本,但是它可以做一些有用的事情:捕獲并保存NASA TV直播的太空事件圖像。太空愛好者經(jīng)常在社交網(wǎng)絡(luò)或論壇共享他們從NASA TV手動獲取的屏幕截圖。Spacestills節(jié)省了使用屏幕捕獲工具的時間,并保存了可供共享的圖像文件。您可以在Replit上在線運行Spacestills。
        開發(fā)環(huán)境
        筆者用Replit開發(fā)了Spacestills。Replit是云上的開發(fā),部署和協(xié)作環(huán)境,它支持包括Python在內(nèi)的數(shù)十種編程語言和框架。作為Chrome操作系統(tǒng)和云計算愛好者,筆者非常喜歡Replit,因為它可以在瀏覽器中完全正常運行,無需下載或安裝任何內(nèi)容。
        資源和依賴包
        Spacestills依賴于一些外部資源和Python庫。
        • NASA TV feed 流
        肯尼迪航天中心的網(wǎng)站上有一個頁面,其中包含精選的NASA視頻流,包括NASA電視公共頻道。feed流顯示最新的靜止幀并自動更新。
        每個feed都帶有三種尺寸的幀,Spacestills依賴于具有704x408像素幀的最大NASA TV feed流。最大更新頻率為每45秒一次。因此,檢索最新的靜止幀就像從feed流的URL下載JPEG圖像一樣簡單。
        原始圖像被垂直拉伸,看起來很奇怪。因此,該程序可以通過壓縮圖像并生成未失真的16:9版本來校正縱橫比。
        • Python
        因PySimpleGUI的原因需要安裝 Python 3.6 版本。
        • 第三方庫
        Pillow:圖像處理
        PySimpleGUI:GUI框架(Spacestills使用Tkinter后端)
        Request:HTTP請求
        完整代碼

        from io import BytesIO
        from datetime import datetime, timedelta
        from pathlib import Path
        import requests
        from requests.exceptions import Timeout
        from PIL import Image
        import PySimpleGUI as sg


        FEED_URL = 'https://science.ksc.nasa.gov/shuttle/countdown/video/chan2large.jpg'

        # Frame size without and with 16:9 aspect ratio correction
        WIDTH = 704
        HEIGHT = 480
        HEIGHT_16_9 = 396

        # Minimum, default, and maximum autoreload interval in seconds
        MIN_DELTA = 45
        DELTA = MIN_DELTA
        MAX_DELTA = 300


        class StillFrame():
            """Holds a still frame.
            
            The image is stored as a PNG PIL.Image and kept in PNG format.
            Attributes
            ----------
                image : PIL.Image
                    A still frame
                original : PIL.Image
                    Original frame with wchich the instance is initialized, cached in case of
                    resizing to the original size
            
            Methods
            -------
                bytes : Return the raw bytes
                resize : Resize the screenshot
                new_size : Calculate new aspect ratio
            """


            def __init__(self, image):
                """Convert the image to PNG and cache the converted original.
                Parameters
                ----------
                    image : PIL.Image
                        Image to store
                """

                self.image = image
                self._topng()
                self.original = self.image

            def _topng(self):
                """Convert image format of frame to PNG.
                Returns
                -------
                    StillFrame
                        Frame with image in PNG format
                """

                if not self.image.format == 'PNG':
                    png_file = BytesIO()
                    self.image.save(png_file, 'png')
                    png_file.seek(0)
                    png_image = Image.open(png_file)
                    self.image = png_image
                return self

            def bytes(self):
                """Return raw bytes of a frame image.
                
                Returns
                -------
                    bytes
                        Byte stream of the frame image
                """

                file = BytesIO()
                self.image.save(file, 'png')
                file.seek(0)
                return file.read()

            def new_size(self):
                """Return image size toggled between original and 16:9.
                
                Returns
                -------
                    2-tuple
                        New size
                """

                size = self.image.size
                original_size = self.original.size
                new_size = (WIDTH, HEIGHT_16_9) if size == original_size else (WIDTH, HEIGHT)
                return new_size

            def resize(self, new_size):
                """Resize frame image.
                
                Parameters
                ----------
                    new_size : 2-tuple
                        New size
                Returns
                -------
                    StillFrame
                        Frame with image resized
                """

                if not(self.image.size == new_size):
                    self.image = self.image.resize(new_size)
                return self
            

        def make_blank_image(size=(WIDTH, HEIGHT)):
            """Create a blank image with a blue background.
            
            Parameters
            ----------
                size : 2-tuple
                    Image size
            
            Returns
            -------
                PIL.Image
                    Blank image
            """

            image = Image.new('RGB', size=size, color='blue')
            return image


        def download_image(url):
            """Download current NASA TV image.
            Parameters
            ----------
                url : str
                    URL to download the image from
            
            Returns
            -------
                PIL.Image
                    Downloaded image if no errors, otherwise blank image
            """

            try:
                response = requests.get(url, timeout=(0.50.5))
                if response.status_code == 200:
                    image = Image.open(BytesIO(response.content))
                else:
                    image = make_blank_image()
            except Timeout:
                image = make_blank_image()
            return image


        def refresh(window, resize=False, feed=FEED_URL):
            """Display the latest still frame in window.
            
            Parameters
            ----------
                window : sg.Window
                    Window to display the still to
                feed : string
                    Feed URL
            
            Returns
            -------
                StillFrame
                    Refreshed screenshot
            """

            still = StillFrame(download_image(feed))
            if resize:
                still = change_aspect_ratio(window, still, new_size=(WIDTH, HEIGHT_16_9))
            else:
                window['-IMAGE-'].update(data=still.bytes())
            return still


        def change_aspect_ratio(window, still, new_size=(WIDTH, HEIGHT_16_9)):
            """Change the aspect ratio of the still displayed in window.
            
            Parameters
            ----------
                window : sg.Window
                    Window containing the still
                new_size : 2-tuple
                    New size of the still
            
            Returns
            -------
                StillFrame
                    Frame containing the resized image
            """

            resized_still = still.resize(new_size)
            window['-IMAGE-'].update(data=resized_still.bytes())
            return resized_still


        def save(still, path):
            """Save still to a file.
            Parameters
            ----------
                still : StillFrame
                    Still to save
                path : string
                    File name
            
            Returns
            -------
                Boolean
                    True if file saved with no errors
            """

            filename = Path(path)
            try:
                with open(filename, 'wb'as file:
                    file.write(still.bytes())
                saved = True
            except OSError:
                saved = False
            return saved


        def next_timeout(delta):
            """Return the moment in time right now + delta seconds from now.
            Parameters
            ----------
                delta : int
                    Time in seconds until the next timeout
            
            Returns
            -------
                datetime.datetime
                    Moment in time of the next timeout
            """

            rightnow = datetime.now()
            return rightnow + timedelta(seconds=delta)


        def timeout_due(next_timeout):
            """Return True if the next timeout is due.
            Parameters
            ----------
                next_timeout : datetime.datetime
            
            Returns
            -------
                bool
                    True if the next timeout is due
            """

            rightnow = datetime.now()
            return rightnow >= next_timeout


        def validate_delta(value):
            """Check if value is an int within the proper range for a time delta.
            Parameters
            ----------
                value : int
                    Time in seconds until the next timeout
            
            Returns
            -------
                int
                    Time in seconds until the next timeout
                bool
                    True if the argument is a valid time delta
            """

            isinteger = False
            try:
                isinteger = type(int(value)) is int
            except Exception:
                delta = DELTA
            delta = int(value) if isinteger else delta
            isvalid = MIN_DELTA <= delta <= MAX_DELTA
            delta = delta if isvalid else DELTA
            return delta, isinteger and isvalid


        LAYOUT = [[sg.Image(key='-IMAGE-')],
                  [sg.Checkbox('Correct aspect ratio', key='-RESIZE-', enable_events=True),
                   sg.Button('Reload', key='-RELOAD-'),
                   sg.Button('Save', key='-SAVE-'),
                   sg.Exit()],
                  [sg.Checkbox('Auto-reload every (seconds):', key='-AUTORELOAD-',
                               default=True),
                   sg.Input(DELTA, key='-DELTA-', size=(31), justification='right'),
                   sg.Button('Set', key='-UPDATE_DELTA-')]]


        def main(layout):
            """Run event loop."""
            window = sg.Window('Spacestills', layout, finalize=True)
            current_still = refresh(window)

            delta = DELTA
            next_reload_time = datetime.now() + timedelta(seconds=delta)

            while True:
                event, values = window.read(timeout=100)
                if event in (sg.WIN_CLOSED, 'Exit'):
                    break
                elif ((event == '-RELOAD-'or
                        (values['-AUTORELOAD-'and timeout_due(next_reload_time))):
                    current_still = refresh(window, values['-RESIZE-'])
                    if values['-AUTORELOAD-']:
                        next_reload_time = next_timeout(delta)
                elif event == '-RESIZE-':
                    current_still = change_aspect_ratio(
                        window, current_still, current_still.new_size())
                elif event == '-SAVE-':
                    filename = sg.popup_get_file(
                        'File name', file_types=[('PNG''*.png')], save_as=True,
                        title='Save image', default_extension='.png')
                    if filename:
                        saved = save(current_still, filename)
                        if not saved:
                            sg.popup_ok('Error while saving file:', filename, title='Error')
                elif event == '-UPDATE_DELTA-':
                    # The current cycle should complete at the already scheduled time. So
                    # don't update next_reload_time yet because it'll be taken care of at the
                    # next -AUTORELOAD- or -RELOAD- event.
                    delta, valid = validate_delta(values['-DELTA-'])
                    if not valid:
                        window['-DELTA-'].update(str(DELTA))

            window.close()
            del window


        if __name__ == '__main__':
            main(LAYOUT)

        更多閱讀



        用 XGBoost 進(jìn)行時間序列預(yù)測


        5分鐘掌握 Python 隨機(jī)爬山算法


        5分鐘完全讀懂關(guān)聯(lián)規(guī)則挖掘算法

        特別推薦





        點擊下方閱讀原文加入社區(qū)會員

        瀏覽 72
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
          
          

            1. 欧美一区二区三区电影 | 免费看黄毛片 | 欧美精品成人视频 | 免费无遮挡 网站在线观看 | 做爱网站日产 |