视频号
已经将项目运行的效果,放到了视频号上面,请移步观看,也欢迎大家关注。
环境
windows 10 64位
anaconda with python 3.8
streamlit 0.86.0
yolov5 v5.0
streamlit是什么
streamlit
是一个开源的python
库,它能够快速的帮助我们创建定制化的web
应用,而且还非常便于和他人分享,特别是在机器学习和数据科学领域。整个过程不需要你了解任何前端的知识,包括html
、css
、javascript
等,对非前端开发人员非常的友好。
streamlit安装
streamlit
要求python
版本大于等于3.6,可以直接使用pip
进行安装
pip?install?streamlit
安装成功后,使用其内置的hello app
测试,执行命令
streamlit?hello
服务启动后,它会自动帮我们打开页面,地址是 http://localhost:8501

streamlit
可以看到,streamlit
默认使用端口8501
除此之外,streamlit
官方还提供了一个稍复杂的应用,它结合了yolov3
的目标检测算法,仓库地址:https://github.com/streamlit/demo-self-driving,感兴趣的可以去研究研究,代码简短,但功能完整

streamlit
那么,针对我们自己的写的源码文件,该怎么运行呢?其实也非常简单,比如源码文件是app.py
,那么可以执行
streamlit?run?app.py
这里再说2个常用的命令
streamlit常用组件
按钮
import?streamlit?as?st
button?=?st.button('按钮')

streamlit button
文本输入框
import?streamlit?as?st
st.text_input('请输入最喜欢的编程语言',?key="name")

streamlit text_input
文本显示
import?streamlit?as?st
st.write('Hello?streamlit.')

streamlit write
streamlit
完美支持markdown
语法,可以直接使用write
方法,来看示例
import?streamlit?as?st
st.write("""
????#?一级标题
????##?二级标题
????###?三级标题
????**强调**
????
????>这是引用
????.?python????
????.?java????
????.?c/c++????
????.?rust????
""")

streamlit write markdown
除了write
方法,streamlit
还提供了text
方法,同样可以显示文本信息
import?streamlit?as?st
st.text('Hello?streamlit.')
标题
import?streamlit?as?st
st.title('title')

streamlit title
除了title
,streamlit
还提供了header
和subheader
import?streamlit?as?st
st.header('header')
st.subheader('subheader')

streamlit header
滑动条
import?streamlit?as?st
number?=?st.slider('Pick?a?number',?0,?100)

streamlit slider
选择框
import?streamlit?as?st
flag?=?st.checkbox('Yes')

streamlit checkbox
单选按钮
import?streamlit?as?st
languages?=?['python',?'c',?'rust',?'c++']
st.radio('Pick?a?language',?languages)

streamlit radio
下拉选择框
import?streamlit?as?st
st.selectbox('用过哪几种编程语言?',?('python',?'c',?'java',?'rust'))

streamlit selectbox
日期选择器
import?streamlit?as?st
date?=?st.date_input('Pick?a?date')

streamlit date_input
颜色选择器
import?streamlit?as?st
color?=?st.color_picker('Pick?a?color')

streamlit color_picker
文件选择器
import?streamlit?as?st
file?=?st.file_uploader('Pick?a?file')

streamlit file_uploader
streamlit的其它功能
显示json
import?streamlit?as?st
st.json({
????"code":?0,
????"data":?{
????????"sex":?"female",
????????"age":?18,
????????"score":?100
????}
})

streamlit json
显示代码
from?numpy.core.arrayprint?import?_leading_trailing
import?streamlit?as?st
code?=?"""
????def?func():
????????print('Hello?streamlit.')
"""
st.code(code,?language='python')

streamlit code
显示pandas中的dataframe
from?numpy.core.arrayprint?import?_leading_trailing
import?streamlit?as?st
import?pandas?as?pd
import?numpy?as?np
df?=?pd.DataFrame(np.random.randn(50,?5),?columns=(
????'col?%d'?%?i?for?i?in?range(5)))
st.dataframe(df)

streamlit pandas dataframe
最后一句中的st.dataframe(df)
可以用st.write(df)
来代替,效果一样
显示表格
import?streamlit?as?st
import?pandas?as?pd
import?numpy?as?np
df?=?pd.DataFrame(np.random.randn(50,?5),?columns=(
????'col?%d'?%?i?for?i?in?range(5)))
st.table(df)

streamlit table
与上边的dataframe
不同的是,表格会将所有数据都显示出来,而没有了滚动条
指标性数据显示
这里还需要安装另一个库streamlit-metrics
,执行安装命令pip install streamlit-metrics
即可
import?streamlit?as?st
from?streamlit_metrics?import?metric_row
st.write("一周数据统计")
metric_row(
????{
????????"关注人数":?100,
????????"点赞人数":?200,
????????"在看人数":?300,
????????"分享人数":?400
????}
)

streamlit metric
streamlit的会话状态和回调
会话状态session state
在浏览器中打开新的页面,就创建了一个会话(session
)。会话状态是页面rerun
(并非类似F5
的页面刷新)时数据交互的一种方式。
看个计数的示例
import?streamlit?as?st
st.title('Hello?streamlit.')
counter?=?0
increment?=?st.button('Increment')
if?increment:
????counter?+=?1
st.write('Count=?',?counter)

streamlit session state
可以看到只有第一次点击按钮时,Count
增加了1,后面的点击,counter
都不会改变,这显然跟我们的预期是不一样的。
我们修改下上面的代码
from?typing?import?Counter
import?streamlit?as?st
st.title('Hello?streamlit.')
if?'counter'?not?in?st.session_state:
????st.session_state.counter?=?0
increment?=?st.button('Increment')
if?increment:
????st.session_state.counter?+=?1
st.write('Count=?',?st.session_state.counter)

streamlit session state
这样功能就正常了,每点击一次按钮,Count
就加1
回调callbacks
回调(callbacks
)是一个python
函数,它在输入组件更改时被调用,比如按钮被点击、滑动条被拉拽等。
针对上边的示例,使用callbacks
修改一下
from?typing?import?Counter
import?streamlit?as?st
#?callbacks
def?increment_counter():
????st.session_state.counter?+=?1
st.title('Callbacks')
if?'counter'?not?in?st.session_state:
????st.session_state.counter?=?0
st.button('Increment',?on_click=increment_counter)
st.write('Count=?',?st.session_state.counter)
代码执行的效果是一样的。这是无需传参的示例,如果需要数据交互,可以使用args
或kwargs
,看下面的示例
import?streamlit?as?st
st.title('Callbacks?with?args')
if?'counter'?not?in?st.session_state:
????st.session_state.counter?=?0
increment_value?=?st.number_input('Enter?a?value',?value=0,?step=1)
def?increment_counter(increment_value):
????st.session_state.counter?+=?increment_value
increment?=?st.button('Increment',?on_click=increment_counter,
??????????????????????args=(increment_value,?))
st.write('Count?=?',?st.session_state.counter)

streamlit callbacks args
下面看看kwargs
的用法,它接收的是命名参数
import?streamlit?as?st
st.title('Callbacks?with?kwargs')
if?'counter'?not?in?st.session_state:
????st.session_state.counter?=?0
def?increment_counter(increment_value=0):
????st.session_state.counter?+=?increment_value
def?decrement_counter(decrement_value=0):
????st.session_state.counter?-=?decrement_value
st.button('Increment',?on_click=increment_counter,
??????????kwargs=dict(increment_value=5))
st.button('Decrement',?on_click=decrement_counter,
??????????kwargs=dict(decrement_value=1))
st.write('Count?=?',?st.session_state.counter)

callbacks kwargs
点击Increment
按钮,Count
就加5,点击Decrement
按钮,Count
就减1
会话状态的注意事项
关于会话状态,有两点需要注意,分别是
streamlit部署
streamlit
最重要的一个优势就是分享了
进入站点 https://streamlit.io/sharing ,请求邀请

streamlit share
填写基本信息后,就是等待回复了

streamlit share
streamlit
处理的很快,我是第二天就收到了确认的邮件

stremlit share email
电子邮件中,详细给出了部署的步骤,基本上照着操作就可以了
将工程保存到github
中,默认是main
分支,工程下需要有requirements.txt
文件
访问 https://share.streamlit.io/, 使用github
的账号登录
创建应用

streamlit share
填写项目信息,分支和入口文件不要填错

streamlit share
开始部署,后台就开始安装各种依赖

streamlit share
项目运行

streamlit share
我这里报了个错
Traceback?(most?recent?call?last):
??File?"/home/appuser/venv/lib/python3.7/site-packages/streamlit/script_runner.py",?line?350,?in?_run_script
????exec(code,?module.__dict__)
??File?"/app/yolov5-streamlit/main.py",?line?5,?in?<module>
????from?detect?import?detect
??File?"/app/yolov5-streamlit/detect.py",?line?5,?in?<module>
????import?cv2
??File?"/home/appuser/venv/lib/python3.7/site-packages/cv2/__init__.py",?line?5,?in?<module>
????from?.cv2?import?*
ImportError:?libGL.so.1:?cannot?open?shared?object?file:?No?such?file?or?directory
这里需要将requirements.txt
文件中的opencv-python
更改为opencv-python-headless
点击右上方的rerun
后,重新安装依赖,就可以运行成功了

streamlit share
最后,来测试下功能是否正常。选择一张本地图片上传,然后点击检测

streamlit share
没有问题,那至此,整个App
的部署就完成了,可以分享给你的朋友们了

streamlit share

streamlit share
如果想线上体验下,可以访问
https://share.streamlit.io/xugaoxiang/yolov5-streamlit/main/main.py
源码下载
github
地址:https://github.com/xugaoxiang/yolov5-streamlit
入口文件是main.py
,里面跟streamlit
相关的界面代码,其实非常少,这样看,streamlit
真的是非常适合不懂前端的朋友。yolov5
的代码部分,基本上把原始的项目拷贝过来,只修改了2个地方
detect.py中的detect方法,增加了一个参数opt
修改视频检测后存储的格式,由原来的mp4v
改成了avc1
。原因是streamlit
中的video
适合播放h264
编码的mp4
,详细的操作可以参考 https://xugaoxiang.com/2021/08/20/opencv-h264-videowrite/
参考资料
https://docs.streamlit.io/en/stable/
https://github.com/ultralytics/yolov5
https://discuss.streamlit.io/t/streamlit-sharing-importerror-libgl-so-1-cannot-open-shared-object-file-no-such-file-or-directory-opencv-error/12367/12