我有大约 650,000 个图像文件,我使用 cv2 将它们转换为 numpy 数组。这些图像被排列到子文件夹中,每个子文件夹中约有 10k 个图像。每个图像都很小;大约 600 字节(2x100 像素 RGB)。
当我阅读它们时,使用:
cv2.imread()
每 10k 图像需要半秒,所有 650k 图像需要不到一分钟......除非我重新启动机器之后。然后,重新启动后第一次运行脚本时,每 10k 图像需要 20-50 秒;完整阅读需要半个小时左右。
为什么?
如何在重新启动后保持它们可以快速访问,而不需要极其缓慢的初始读取?
历史图像数据库每天都在增长;旧的不会被重写。
代码:
print 'Building historic database...'
elapsed = elapsed2 = time.time()
def get_immediate_subdirectories(a_dir):
return [name for name in os.listdir(a_dir)
if os.path.isdir(os.path.join(a_dir, name))]
compare = get_immediate_subdirectories('images_old')
compare.sort()
images = []
for j in compare:
begin = 1417024800
end = 1500000000
if ASSET == j:
end = int(time.time()-86400*30)
tally = 0
for i in range (begin, end, 7200):
try:
im = cv2.imread("images_old/%s/%s_%s.png" % (j,j,i))
im = np.ndarray.flatten(im)
if im is not None:
images.append([j,i,im])
tally+=1
except: pass
print j.ljust(5), ('cv2 imread elapsed: %.2f items: %s' % ((time.time()-elapsed),tally))
elapsed = time.time()
print '%.2f cv2 imread big data: %s X %s items' % ((time.time()-elapsed2),len(images),len(a1))
elapsed = time.time()
AMD fm2+ 16GB
linux 薄荷 17.3
python 2.7
最佳答案
我想提出一个基于 REDIS 的概念,它就像一个数据库,但实际上是一个“数据结构服务器”,其中数据结构是 600 字节的图像。我并不是建议您依赖 REDIS 作为永久存储系统,而是继续使用您的 650,000 个文件,但将它们缓存在 REDIS 中,这是免费的,可用于 Linux、macOS 和 Windows。
因此,基本上,您可以在一天中的任何时间将图像复制到 REDIS 中,为下次重新启动做好准备。
我不会说 Python,但这里有一个 Perl 脚本,我用它生成 650,000 个图像,每个图像有 600 个随机字节,并将它们插入到 REDIS 哈希中。相应的Python很容易编写:
#!/usr/bin/perl
################################################################################
# generator <number of images> <image size in bytes>
# Mark Setchell
# Generates and sends "images" of specified size to REDIS
################################################################################
use strict;
use warnings FATAL => 'all';
use Redis;
use Time::HiRes qw(time);
my $Debug=1; # set to 1 for debug messages
my $nargs = $#ARGV + 1;
if ($nargs != 2) {
print "Usage: generator <number of images> <image size in bytes>\n";
exit 1;
}
my $nimages=$ARGV[0];
my $imsize=$ARGV[1];
my @bytes=(q(a)..q(z),q(A)..q(Z),q(0)..q(9));
my $bl = scalar @bytes - 1;
printf "DEBUG: images: $nimages, size: $imsize\n" if $Debug;
# Connection to REDIS
my $redis = Redis->new;
my $start=time;
for(my $i=0;$i<$nimages;$i++){
# Generate our 600 byte "image"
my $image;
for(my $j=0;$j<$imsize;$j++){
$image .= $bytes[rand $bl];
}
# Load it into a REDIS hash called 'im' indexed by an integer number
$redis->hset('im',$i,$image);
print "DEBUG: Sending key:images, field:$i, value:$image\n" if $Debug;
}
my $elapsed=time-$start;
printf "DEBUG: Sent $nimages images of $imsize bytes in %.3f seconds, %d images/s\n",$elapsed,int($nimages/$elapsed)
因此,您可以将 650,000 个图像(每个图像 600 字节)插入到名为“im”的 REDIS 哈希中,该哈希由一个简单的数字 [1..650000] 索引。
现在,如果您停止 REDIS 并检查数据库的大小,它是 376MB:
ls -lhrt dump.rb
-rw-r--r-- 1 mark admin 376M 29 May 20:00 dump.rdb
如果现在杀死 REDIS,然后重新启动它,启动并加载 650,000 个图像数据库需要 2.862 秒:
redis-server /usr/local/etc/redis.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 3.2.9 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 33802
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
33802:M 29 May 20:00:57.698 # Server started, Redis version 3.2.9
33802:M 29 May 20:01:00.560 * DB loaded from disk: 2.862 seconds
33802:M 29 May 20:01:00.560 * The server is now ready to accept connections on port 6379
因此,您可以在重新启动后 3 秒内启动 REDIS。然后您可以像这样查询并加载 650,000 张图像:
#!/usr/bin/perl
################################################################################
# reader
# Mark Setchell
# Reads specified number of images from Redis
################################################################################
use strict;
use warnings FATAL => 'all';
use Redis;
use Time::HiRes qw(time);
my $Debug=0; # set to 1 for debug messages
my $nargs = $#ARGV + 1;
if ($nargs != 1) {
print "Usage: reader <number of images>\n";
exit 1;
}
my $nimages=$ARGV[0];
# Connection to REDIS
my $redis = Redis->new;
my $start=time;
for(my $i=0;$i<$nimages;$i++){
# Retrive image from hash named "im" with key=$1
my $image = $redis->hget('im',$i);
print "DEBUG: Received image $i\n" if $Debug;
}
my $elapsed=time-$start;
printf "DEBUG: Received $nimages images in %.3f seconds, %d images/s\n",$elapsed,int($nimages/$elapsed)
在我的 Mac 上,需要 61 秒读取 650,000 个图像,每个图像 600 字节,因此总启动时间为 64 秒。
抱歉,我对 Python 的了解还不够多,无法用 Python 来做这件事,但我怀疑时间会非常相似。
我基本上使用名为“im”的 REDIS 哈希,以及 hset
和 hget
并通过一个简单的整数对图像进行索引。但是,REDIS 键是二进制安全的,因此您可以使用文件名而不是整数作为键。您还可以在命令行中与 REDIS 交互(无需 Python 或 Perl),这样您就可以在命令行中使用以下命令获取 650,000 个键(文件名)的列表:
redis-cli <<< "hkeys im"
或检索单个图像(key/filename=“1”):
redis-cli <<< "hget 'im' 1"
如果您没有 bash
,您可以这样做:
echo "hget 'im' 1" | redis-cli
或
echo "hkeys im" | redis-cli
我刚刚阅读了有关持久化/序列化 Numpy 数组的内容,因此这可能是比涉及 REDIS 更简单的选项... see here .
关于python - 如何在重启后在 python 中更快地执行 opencv cv2 imread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44243974/