无法使用opencv加载大图像

Can not load large image with opencv

我尝试使用 opencv 加载大小为 100.000 * 15.000 像素且文件大小为 4.305 kb 的图像。如果我使用以下代码加载此图像:

   cv::Mat reallyBigImage = cv::imread("reallyBigImage.png");

我收到以下错误:

我有一台 32 GB RAM 的电脑,用 64 位编译这个程序。对于这种尺寸的图像,这应该足够了。这么大的图片可以整体加载到opencv吗?

这是我的程序在汇编程序中中断的地方。 箭头指示具体位置。此片段来自 memcpy.asm.

    CopyUp:
    cmp     r8, 128
    jbe     XmmCopySmall

    bt      __favor, __FAVOR_ENFSTRG ; check for ENFSTRG (enhanced fast strings)
    jnc     XmmCopyUp               ; If Enhanced Fast String not available, use XMM

    ; use Enhanced Fast Strings
    ; but first align the destination dst to 16 byte alignment
    mov     rax, r11                ; return original destination pointer
    mov     r11, rdi                ; save rdi in r11
    mov     rdi, rcx                ; move destination pointer to rdi
    mov     rcx, r8                 ; move length to rcx
    mov     r8, rsi                 ; save rsi in r8
    mov     rsi, r10                ; move source pointer to rsi
    -->rep     movsb                   ; copy source to destination buffer
    mov     rsi, r8                 ; restore rsi
    mov     rdi, r11                ; restore rdi
    ret

该图像是 6 GB 原始数据(100,000 * 15,000 * 4 字节)。通常 Windows 将进程的最大堆大小限制为远低于该大小。但即使你增加了这个限制,你也会遇到内存碎片(无法写入单个 6GB 连续内存块),OpenCV 的分配器可能无法处理。

这就是您在将图像数据写入内存时遇到访问冲突错误的原因。它正在尝试写入不是 allowed/supposed 写入的内存位置。

您要么必须将图像拆分成多个 ROIs/sub-images 以避免碎片化,要么编写您自己的分配器,以较小的块在内存中分配图像。

如果你处理的是大图,我可以向你推荐libvips吗?它可用于 Linux、macOS 和 Windows - 免费,来自 here

如果您有一张 100,000 x 15,000 PNG 的图像,并且您想要从一个点 (100,100) 开始提取一个 2000x1000 的区域,您可以这样做:

time vips crop test.png excerpt.png 2000 1000 100 100 --vips-leak

示例输出

memory: high-water mark 192.29 MB

real    0m1.771s
user    0m0.826s
sys     0m0.082s

如您所见,它仅使用了 200MB 的 RAM,并花费了大约 1 秒的时间。 time--vips-leak 仅用于演示目的 - 您可以正常省略它们。

运行 一些本地测试,这可以用 OpenCV 3.1 重现,但不能用 3.2 或 3.3。这表明这是一个错误(以及您首先遇到访问冲突的事实)。

具体来说issue #6317.

这是在 OpenCV 3.2 发布之前修复的,这将符合上述观察结果。因此,最好的选择是升级您的 OpenCV 副本。