python - 如何在重启后在 python 中更快地执行 opencv cv2 imread

标签 python opencv numpy

我有大约 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 哈希,以及 hsethget 并通过一个简单的整数对图像进行索引。但是,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/

相关文章:

python - 微分梯度

python - 将月年对解析为日期时间

c++ - opencv查找连通分量的周长

python - 如何从图像阵列中制作彩色点阵列?

python - 为什么我不能在 numpy 中使用链式表达式?

python - matplotlib 中的历史记录 : Bins are not centered and proportions not correct on the axis

python - 阶乘非零数字不匹配

python - 了解 : import modname -> and -> from modname import membername 之间的行为变化

c++ - 无关垫在 inRange 期间被无法解释的覆盖

python - 替换 numpy 条目的省时方法