用Python监控NASA TV直播画面的实现步骤
演示地址:
https://replit.com/@PaoloAmoroso/spacestills
这是一个具有GUI的简单系统,它访问feed流并从Web下载数据。该程序仅需350行代码,并依赖于一些开源的Python库。
关于程序
Spacestills会定期从feed流中下载NASA TV静止帧并将其显示在GUI中。
该程序可以校正帧的纵横比,并将其保存为PNG格式。它会自动下载最新的帧,并提供手动重新加载,禁用自动重新加载或更改下载频率的选项。
Spacestillsis是一个比较初级的版本,但是它可以做一些有用的事情:捕获并保存NASA TV直播的太空事件图像。太空爱好者经常在社交网络或论坛共享他们从NASA TV手动获取的屏幕截图。Spacestills节省了使用屏幕捕获工具的时间,并保存了可供共享的图像文件。您可以在Replit上在线运行Spacestills。
开发环境
笔者用Replit开发了Spacestills。Replit是云上的开发,部署和协作环境,它支持包括Python在内的数十种编程语言和框架。作为Chrome操作系统和云计算爱好者,笔者非常喜欢Replit,因为它可以在浏览器中完全正常运行,无需下载或安装任何内容。
资源和依赖包
Spacestills依赖于一些外部资源和Python库。
NASA TV feed 流
肯尼迪航天中心的网站上有一个页面,其中包含精选的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请求
完整代码
fromioimportBytesIO fromdatetimeimportdatetime,timedelta frompathlibimportPath importrequests fromrequests.exceptionsimportTimeout fromPILimportImage importPySimpleGUIassg FEED_URL='https://science.ksc.nasa.gov/shuttle/countdown/video/chan2large.jpg' #Framesizewithoutandwith16:9aspectratiocorrection WIDTH=704 HEIGHT=480 HEIGHT_16_9=396 #Minimum,default,andmaximumautoreloadintervalinseconds MIN_DELTA=45 DELTA=MIN_DELTA MAX_DELTA=300 classStillFrame(): """Holdsastillframe. TheimageisstoredasaPNGPIL.ImageandkeptinPNGformat. Attributes ---------- image:PIL.Image Astillframe original:PIL.Image Originalframewithwchichtheinstanceisinitialized,cachedincaseof resizingtotheoriginalsize Methods ------- bytes:Returntherawbytes resize:Resizethescreenshot new_size:Calculatenewaspectratio """ def__init__(self,image): """ConverttheimagetoPNGandcachetheconvertedoriginal. Parameters ---------- image:PIL.Image Imagetostore """ self.image=image self._topng() self.original=self.image def_topng(self): """ConvertimageformatofframetoPNG. Returns ------- StillFrame FramewithimageinPNGformat """ ifnotself.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 returnself defbytes(self): """Returnrawbytesofaframeimage. Returns ------- bytes Bytestreamoftheframeimage """ file=BytesIO() self.image.save(file,'png') file.seek(0) returnfile.read() defnew_size(self): """Returnimagesizetoggledbetweenoriginaland16:9. Returns ------- 2-tuple Newsize """ size=self.image.size original_size=self.original.size new_size=(WIDTH,HEIGHT_16_9)ifsize==original_sizeelse(WIDTH,HEIGHT) returnnew_size defresize(self,new_size): """Resizeframeimage. Parameters ---------- new_size:2-tuple Newsize Returns ------- StillFrame Framewithimageresized """ ifnot(self.image.size==new_size): self.image=self.image.resize(new_size) returnself defmake_blank_image(size=(WIDTH,HEIGHT)): """Createablankimagewithabluebackground. Parameters ---------- size:2-tuple Imagesize Returns ------- PIL.Image Blankimage """ image=Image.new('RGB',size=size,color='blue') returnimage defdownload_image(url): """DownloadcurrentNASATVimage. Parameters ---------- url:str URLtodownloadtheimagefrom Returns ------- PIL.Image Downloadedimageifnoerrors,otherwiseblankimage """ try: response=requests.get(url,timeout=(0.5,0.5)) ifresponse.status_code==200: image=Image.open(BytesIO(response.content)) else: image=make_blank_image() exceptTimeout: image=make_blank_image() returnimage defrefresh(window,resize=False,feed=FEED_URL): """Displaythelateststillframeinwindow. Parameters ---------- window:sg.Window Windowtodisplaythestillto feed:string FeedURL Returns ------- StillFrame Refreshedscreenshot """ still=StillFrame(download_image(feed)) ifresize: still=change_aspect_ratio(window,still,new_size=(WIDTH,HEIGHT_16_9)) else: window['-IMAGE-'].update(data=still.bytes()) returnstill defchange_aspect_ratio(window,still,new_size=(WIDTH,HEIGHT_16_9)): """Changetheaspectratioofthestilldisplayedinwindow. Parameters ---------- window:sg.Window Windowcontainingthestill new_size:2-tuple Newsizeofthestill Returns ------- StillFrame Framecontainingtheresizedimage """ resized_still=still.resize(new_size) window['-IMAGE-'].update(data=resized_still.bytes()) returnresized_still defsave(still,path): """Savestilltoafile. Parameters ---------- still:StillFrame Stilltosave path:string Filename Returns ------- Boolean Trueiffilesavedwithnoerrors """ filename=Path(path) try: withopen(filename,'wb')asfile: file.write(still.bytes()) saved=True exceptOSError: saved=False returnsaved defnext_timeout(delta): """Returnthemomentintimerightnow+deltasecondsfromnow. Parameters ---------- delta:int Timeinsecondsuntilthenexttimeout Returns ------- datetime.datetime Momentintimeofthenexttimeout """ rightnow=datetime.now() returnrightnow+timedelta(seconds=delta) deftimeout_due(next_timeout): """ReturnTrueifthenexttimeoutisdue. Parameters ---------- next_timeout:datetime.datetime Returns ------- bool Trueifthenexttimeoutisdue """ rightnow=datetime.now() returnrightnow>=next_timeout defvalidate_delta(value): """Checkifvalueisanintwithintheproperrangeforatimedelta. Parameters ---------- value:int Timeinsecondsuntilthenexttimeout Returns ------- int Timeinsecondsuntilthenexttimeout bool Trueiftheargumentisavalidtimedelta """ isinteger=False try: isinteger=type(int(value))isint exceptException: delta=DELTA delta=int(value)ifisintegerelsedelta isvalid=MIN_DELTA<=delta<=MAX_DELTA delta=deltaifisvalidelseDELTA returndelta,isintegerandisvalid LAYOUT=[[sg.Image(key='-IMAGE-')], [sg.Checkbox('Correctaspectratio',key='-RESIZE-',enable_events=True), sg.Button('Reload',key='-RELOAD-'), sg.Button('Save',key='-SAVE-'), sg.Exit()], [sg.Checkbox('Auto-reloadevery(seconds):',key='-AUTORELOAD-', default=True), sg.Input(DELTA,key='-DELTA-',size=(3,1),justification='right'), sg.Button('Set',key='-UPDATE_DELTA-')]] defmain(layout): """Runeventloop.""" window=sg.Window('Spacestills',layout,finalize=True) current_still=refresh(window) delta=DELTA next_reload_time=datetime.now()+timedelta(seconds=delta) whileTrue: event,values=window.read(timeout=100) ifeventin(sg.WIN_CLOSED,'Exit'): break elif((event=='-RELOAD-')or (values['-AUTORELOAD-']andtimeout_due(next_reload_time))): current_still=refresh(window,values['-RESIZE-']) ifvalues['-AUTORELOAD-']: next_reload_time=next_timeout(delta) elifevent=='-RESIZE-': current_still=change_aspect_ratio( window,current_still,current_still.new_size()) elifevent=='-SAVE-': filename=sg.popup_get_file( 'Filename',file_types=[('PNG','*.png')],save_as=True, title='Saveimage',default_extension='.png') iffilename: saved=save(current_still,filename) ifnotsaved: sg.popup_ok('Errorwhilesavingfile:',filename,title='Error') elifevent=='-UPDATE_DELTA-': #Thecurrentcycleshouldcompleteatthealreadyscheduledtime.So #don'tupdatenext_reload_timeyetbecauseit'llbetakencareofatthe #next-AUTORELOAD-or-RELOAD-event. delta,valid=validate_delta(values['-DELTA-']) ifnotvalid: window['-DELTA-'].update(str(DELTA)) window.close() delwindow if__name__=='__main__': main(LAYOUT)
以上就是用 Python 监控 NASA TV 直播画面的实现步骤的详细内容,更多关于Python 监控 NASA TV 直播画面的资料请关注本站其它相关文章!
版权声明:本站文章来源标注为YINGSOO的内容版权均为本站所有,欢迎引用、转载,请保持原文完整并注明来源及原文链接。禁止复制或仿造本网站,禁止在非www.yingsoo.com所属的服务器上建立镜像,否则将依法追究法律责任。本站部分内容来源于网友推荐、互联网收集整理而来,仅供学习参考,不代表本站立场,如有内容涉嫌侵权,请联系alex-e#qq.com处理。