- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章浅析Python 读取图像文件的性能对比由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
使用 python 读取一个保存在本地硬盘上的视频文件,视频文件的编码方式是使用的原始的 rgba 格式写入的,即无压缩的原始视频文件。最开始直接使用 python 对读取到的文件数据进行处理,然后显示在 matplotlib 窗口上,后来发现视频播放的速度比同样的处理逻辑的 c++ 代码慢了很多,尝试了不同的方法,最终实现了在 python 中读取并显示视频文件,帧率能够达到 120 fps 以上.
读取一帧图片数据并显示在窗口上 。
最简单的方法是直接在 python 中读取文件,然后逐像素的分配 rgb 值到窗口中,最开始使用的是 matplotlib 的 pyplot 组件.
一些用到的常量:
1
2
3
4
5
|
file_name
=
"i:/video.dat"
width
=
2096
height
=
150
channels
=
4
pack_size
=
width
*
height
*
channels
|
每帧图片的宽度是 2096 个像素,高度是 150 个像素,channels 指的是 rgba 四个通道,因此 pack_size 的大小就是一副图片占用空间的字节数.
首先需要读取文件。由于视频编码没有任何压缩处理,大概 70s 的视频(每帧约占 1.2m 空间,每秒 60 帧)占用达 4gb 的空间,所以我们不能直接将整个文件读取到内存中,借助 python functools 提供的 partial 方法,我们可以每次从文件中读取一小部分数据,将 partial 用 iter 包装起来,变成可迭代的对象,每次读取一帧图片后,使用 next 读取下一帧的数据,接下来先用这个方法将保存在文件中的一帧数据读取显示在窗口中.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
with
open
(
file
,
'rb'
) as f:
e1
=
cv.gettickcount()
records
=
iter
( partial( f.read, pack_size), b'' )
# 生成一个 iterator
frame
=
next
( records )
# 读取一帧数据
img
=
np.zeros( ( height, width, channels ), dtype
=
np.uint8)
for
y
in
range
(
0
, height):
for
x
in
range
(
0
, width ):
pos
=
(y
*
width
+
x)
*
channels
for
i
in
range
(
0
, channels
-
1
):
img[y][x][i]
=
frame[ pos
+
i ]
img[y][x][
3
]
=
255
plt.imshow( img )
plt.tight_layout()
plt.subplots_adjust(left
=
0
, right
=
1
, top
=
1
, bottom
=
0
)
plt.xticks([])
plt.yticks([])
e2
=
cv.gettickcount()
elapsed
=
( e2
-
e1 )
/
cv.gettickfrequency()
print
(
"time used: "
, elapsed )
plt.show()
|
需要说明的是,在保存文件时第 4 个通道保存的是透明度,因此值为 0,但在 matplotlib (包括 opencv)的窗口中显示时第 4 个通道保存的一般是不透明度。我将第 4 个通道直接赋值成 255,以便能够正常显示图片.
这样就可以在我们的窗口中显示一张图片了,不过由于图片的宽长比不协调,使用 matplotlib 绘制出来的窗口必须要缩放到很大才可以让图片显示的比较清楚.
为了方便稍后的性能比较,这里统一使用 opencv 提供的 gettickcount 方法测量用时。可以从控制台中看到显示一张图片,从读取文件到最终显示大概要用 1.21s 的时间。如果我们只测量三层嵌套循环的用时,可以发现有 0.8s 的时间都浪费在循环上了.
读取并显示一帧图片用时 1.21s 。
在处理循环上用时 0.8s 。
约百万级别的循环处理,同样的代码放在 c++ 里面性能完全没有问题,在 python 中执行起来就不一样了。在 python 中这样的处理速度最多就 1.2 fps。我们暂时不考虑其他方法进行优化,而是将多帧图片动态的显示在窗口上,达到播放视频的效果.
连续读取图片并显示 。
这时我们继续读取文件并显示在窗口上,为了能够动态的显示图片,我们可以使用 matplotlib.animation 动态显示图片,之前的程序需要进行相应的改动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
fig
=
plt.figure()
ax1
=
fig.add_subplot(
1
,
1
,
1
)
try
:
img
=
np.zeros( ( height, width, channels ), dtype
=
np.uint8)
f
=
open
( file_name,
'rb'
)
records
=
iter
( partial( f.read, pack_size ), b'' )
def
animatefromdata(i):
e1
=
cv.gettickcount()
frame
=
next
( records )
# drop a line data
for
y
in
range
(
0
, height ):
for
x
in
range
(
0
, width ):
pos
=
(y
*
width
+
x)
*
channels
for
i
in
range
(
0
, channels
-
1
):
img[y][x][i]
=
frame[ pos
+
i]
img[y][x][
3
]
=
255
ax1.clear()
ax1.imshow( img )
e2
=
cv.gettickcount()
elapsed
=
( e2
-
e1 )
/
cv.gettickfrequency()
print
(
"fps: %.2f, used time: %.3f"
%
(
1
/
elapsed, elapsed ))
a
=
animation.funcanimation( fig, animatefromdata, interval
=
30
)
# 这里不要省略掉 a = 这个赋值操作
plt.tight_layout()
plt.subplots_adjust(left
=
0
, right
=
1
, top
=
1
, bottom
=
0
)
plt.xticks([])
plt.yticks([])
plt.show()
except
stopiteration:
pass
finally
:
f.close()
|
和第 1 部分稍有不同的是,我们显示每帧图片的代码是在 animatefromdata 函数中执行的,使用 matplotlib.animation.funcanimation 函数循环读取每帧数据(给这个函数传递的 interval = 30 这个没有作用,因为处理速度跟不上)。另外值得注意的是不要省略掉 a = animation.funcanimation( fig, animatefromdata, interval=30 ) 这一行的赋值操作,虽然不太清楚原理,但是当我把 a = 删掉的时候,程序莫名的无法正常工作了.
控制台中显示的处理速度:
由于对 matplotlib 的了解不多,最开始我以为是 matplotlib 显示图像过慢导致了帧率上不去,打印出代码的用时后发现不是 matplotlib 的问题。因此我也使用了 pyqt5 对图像进行显示,结果依然是 1~2 帧的处理速度。因为只是换用了 qt 的界面进行显示,逻辑处理的代码依然沿用的 matplotlib.animation 提供的方法,所以并没有本质上的区别。这段用 qt 显示图片的代码来自于 github matplotlib issue,我对其进行了一些适配.
使用 numpy 的数组处理 api 。
我们知道,显示图片这么慢的原因就是在于 python 处理 2096 * 150 这个两层循环占用了大量时间。接下来我们换用一种 numpy 的 reshape 方法将文件中的像素数据读取到内存中。注意 reshape 方法接收一个 ndarray 对象。我这种每帧数据创造一个 ndarray 数组的方法可能会存在内存泄漏的风险,实际上可以调用一个 ndarray 数组对象的 reshape 方法。这里不再深究.
重新定义一个用于动态显示图片的函数 optanimatefromdata,将其作为参数传递个 funcanimation:
1
2
3
4
5
6
7
8
9
10
11
12
|
def
optanimatefromdata(i):
e1
=
cv.gettickcount()
frame
=
next
( records )
# one image data
img
=
np.reshape( np.array(
list
( frame ), dtype
=
np.uint8 ), ( height, width, channels ) )
img[ : , : ,
3
]
=
255
ax1.clear()
ax1.imshow( img )
e2
=
cv.gettickcount()
elapsed
=
( e2
-
e1 )
/
cv.gettickfrequency()
print
(
"fps: %.2f, used time: %.3f"
%
(
1
/
elapsed, elapsed ))
a
=
animation.funcanimation( fig, optanimatefromdata, interval
=
30
)
|
效果如下,可以看到使用 numpy 的 reshape 方法后,处理用时大幅减少,帧率可以达到 8~9 帧。然而经过优化后的处理速度仍然是比较慢的:
优化过的代码执行结果 。
使用 numpy 提供的 memmap 。
在用 python 进行机器学习的过程中,发现如果完全使用 python 的话,很多运算量大的程序也是可以跑的起来的,所以我确信可以用 python 解决我的这个问题。在我不懈努力下找到 numpy 提供的 memmap api,这个 api 以数组的方式建立硬盘文件到内存的映射,使用这个 api 后程序就简单一些了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
cv.namedwindow(
"file"
)
count
=
0
start
=
time.time()
try
:
number
=
1
while
true:
e1
=
cv.gettickcount()
img
=
np.memmap(filename
=
file_name, dtype
=
np.uint8, shape
=
shape, mode
=
"r+"
, offset
=
count )
count
+
=
pack_size
cv.imshow(
"file"
, img )
e2
=
cv.gettickcount()
elapsed
=
( e2
-
e1 )
/
cv.gettickfrequency()
print
(
"fps: %.2f used time: %.3f"
%
(number
/
elapsed, elapsed ))
key
=
cv.waitkey(
20
)
if
key
=
=
27
:
# exit on esc
break
except
stopiteration:
pass
finally
:
end
=
time.time()
print
(
'file data read: {:.2f}gb'
.
format
( count
/
1024
/
1024
/
1024
),
' time used: {:.2f}s'
.
format
( end
-
start ) )
cv.destroyallwindows()
|
将 memmap 读取到的数据 img 直接显示在窗口中 cv.imshow( "file", img),每一帧打印出显示该帧所用的时间,最后显示总的时间和读取到的数据大小:
执行效率最高的结果 。
读取速度非常快,每帧用时只需几毫秒。这样的处理速度完全可以满足 60fps 的需求.
总结 。
python 语言写程序非常方便,但是原生的 python 代码执行效率确实不如 c++,当然了,比 js 还是要快一些。使用 python 开发一些性能要求高的程序时,要么使用 numpy 这样的库,要么自己编写一个 c 语言库供 python 调用。在实验过程中,我还使用 flask 读取文件后以流的形式发送的浏览器,让浏览器中的 js 文件进行显示,不过同样存在着很严重的性能问题和内存泄漏问题。这个过程留到之后再讲.
本文中的相应代码可以在 github 上查看.
reference 。
functools 。
partial 。
opencv 。
matplotlib animation 。
numpy 。
numpy reshape 。
memmap 。
matplotlib issue on github 。
C 语言扩展 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:https://www.cnblogs.com/brifuture/p/10116553.html 。
最后此篇关于浅析Python 读取图像文件的性能对比的文章就讲到这里了,如果你想了解更多关于浅析Python 读取图像文件的性能对比的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试学习 Knockout 并尝试创建一个照片 uploader 。我已成功将一些图像存储在数组中。现在我想回帖。在我的 knockout 码(Javascript)中,我这样做: 我在 Jav
我正在使用 php 编写脚本。我的典型问题是如何在 mysql 中添加一个有很多替代文本和图像的问题。想象一下有机化学中具有苯结构的描述。 最有效的方法是什么?据我所知,如果我有一个图像,我可以在数据
我在两个图像之间有一个按钮,我想将按钮居中到图像高度。有人可以帮帮我吗? Entrar
下面的代码示例可以在这里查看 - http://dev.touch-akl.com/celebtrations/ 我一直在尝试做的是在 Canvas 上绘制 2 个图像(发光,然后耀斑。这些图像的链接
请检查此https://jsfiddle.net/rhbwpn19/4/ 图像预览对于第一篇帖子工作正常,但对于其他帖子则不然。 我应该在这里改变什么? function readURL(input)
我对 Canvas 有疑问。我可以用单个图像绘制 Canvas ,但我不能用单独的图像绘制每个 Canvas 。- 如果数据只有一个图像,它工作正常,但数据有多个图像,它不工作你能帮帮我吗? va
我的问题很简单。如何获取 UIImage 的扩展类型?我只能将图像作为 UIImage 而不是它的名称。图像可以是静态的,也可以从手机图库甚至文件路径中获取。如果有人可以为此提供一点帮助,将不胜感激。
我有一个包含 67 个独立路径的 SVG 图像。 是否有任何库/教程可以为每个路径创建单独的光栅图像(例如 PNG),并可能根据路径 ID 命名它们? 最佳答案 谢谢大家。我最终使用了两个答案的组合。
我想将鼠标悬停在一张图片(音乐专辑)上,然后播放一张唱片,所以我希望它向右移动并旋转一点,当它悬停时我希望它恢复正常动画片。它已经可以向右移动,但我无法让它随之旋转。我喜欢让它尽可能简单,因为我不是编
Retina iOS 设备不显示@2X 图像,它显示 1X 图像。 我正在使用 Xcode 4.2.1 Build 4D502,该应用程序的目标是 iOS 5。 我创建了一个测试应用(主/细节)并添加
我正在尝试从头开始以 Angular 实现图像 slider ,并尝试复制 w3school基于图像 slider 。 下面我尝试用 Angular 实现,谁能指导我如何使用 Angular 实现?
我正在尝试获取图像的图像数据,其中 w= 图像宽度,h = 图像高度 for (int i = x; i imageData[pos]>0) //Taking data (here is the pr
我的网页最初通过在 javascript 中动态创建图像填充了大约 1000 个缩略图。由于权限问题,我迁移到 suPHP。现在不用标准 标签本身 我正在通过这个 php 脚本进行检索 $file
我正在尝试将 python opencv 图像转换为 QPixmap。 我按照指示显示Page Link我的代码附在下面 img = cv2.imread('test.png')[:,:,::1]/2
我试图在这个 Repository 中找出语义分割数据集的 NYU-v2 . 我很难理解图像标签是如何存储的。 例如,给定以下图像: 对应的标签图片为: 现在,如果我在 OpenCV 中打开标签图像,
import java.util.Random; class svg{ public static void main(String[] args){ String f="\"
我有一张 8x8 的图片。 (位图 - 可以更改) 我想做的是能够绘制一个形状,给定一个 Path 和 Paint 对象到我的 SurfaceView 上。 目前我所能做的就是用纯色填充形状。我怎样才
要在页面上显示图像,你需要使用源属性(src)。src 指 source 。源属性的值是图像的 URL 地址。 定义图像的语法是: 在浏览器无法载入图像时,替换文本属性告诉读者她们失去的信息。此
**MMEditing是基于PyTorch的图像&视频编辑开源工具箱,支持图像和视频超分辨率(super-resolution)、图像修复(inpainting)、图像抠图(matting)、
我正在尝试通过资源文件将图像插入到我的程序中,如下所示: green.png other files 当我尝试使用 QImage 或 QPixm
我是一名优秀的程序员,十分优秀!