新闻动态

用Python监控NASA TV直播画面的实现步骤

发布日期:2022-05-30 14:33 | 文章来源:脚本之家

演示地址:

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处理。

相关文章

实时开通

自选配置、实时开通

免备案

全球线路精选!

全天候客户服务

7x24全年不间断在线

专属顾问服务

1对1客户咨询顾问

在线
客服

在线客服:7*24小时在线

客服
热线

400-630-3752
7*24小时客服服务热线

关注
微信

关注官方微信
顶部