张大妈

位图在计算机中如何存储的?如何编程使图片变亮或变暗?

源自知乎:大饼土博

02-15 13:54

想知道为什么你的图像处理代码很慢吗?答案可能在于数据在内存中的存储方式。理解位图的不同内存布局是编写高效、快速代码的关键,尤其是在修改图像亮度或对比度等操作中。

位图在计算机中如何存储的?如何编程使图片变亮或变暗?智能速览

  • 位图在内存中主要有三种存储方式:行优先交错、列优先平面和行优先平面。

  • 代码的运行速度与CPU的“局部性原理”密切相关,连续访问内存中的数据效率更高。

  • 对于行优先存储,遍历像素时应将行循环放在外层,列循环放在内层。

  • 不同的存储方式源于不同软件的历史设计目标,如OpenCV受C语言和硬件影响。

  • 颜色数据紧密存储适合需要同时处理RGB的算法,而平面存储更适合矩阵运算。

位图在计算机中如何存储的?如何编程使图片变亮或变暗?精华内容

要让图片变亮或变暗,写两层for循环遍历像素是最直接的想法,但你知道为什么有时它会慢得像蜗牛吗?关键就在于图像数据在内存中的排列方式,以及代码是否顺应了CPU的工作习惯。

图像的三种内存布局

计算机内存中,位图数据的存储方式主要有三种。最常见的是行优先交错存储,即第一个像素的RGB数据紧密存放,接着是第二个像素的RGB数据,所有像素按行依次排列。其次是列优先平面存储,它将所有像素的R通道数据、G通道数据和B通道数据分别存放在三个独立的“平面”中,且在每个平面内按列优先。最后是行优先平面存储,与列优先平面类似,区别在于每个颜色平面内是按行优先存储的。此外,为了优化性能,行优先存储的每行数据末尾可能会有填充字节以满足内存对齐要求。

局部性原理与代码速度

现代CPU为了高效访问内存,设计了缓存机制,其核心是“局部性原理”,即倾向于一次性加载当前地址附近的一整块数据。如果代码访问内存的地址是跳跃的,就会导致缓存频繁失效,大幅降低性能。例如,在遍历行优先交错存储的图像时,如果外层循环是列(y),内层循环是行(x),那么内存访问就会在物理地址上不断跳转,效率极低。正确的做法是将行循环(y)放在外层,列循环(x)放在内层,这样就能顺序访问内存,充分利用CPU缓存,从而让代码运行速度显著提升。

存储方式的由来

不同存储方式的存在源于软件的历史和设计目标。行优先存储的设计深受C语言影响,其二维数组在内存中就是按行排列的。同时,它也与显示器摄像头等硬件的“光栅扫描”工作方式(逐行扫描)天然契合,数据可以直接从硬件缓冲区复制到内存,效率最高。OpenCV作为C语言图像处理库,因此沿用了此设计。而列优先存储则源于线性代数,其中向量和矩阵通常被看作列的集合。为迎合这种数学直觉,Fortran语言选择了列优先存储。随后,基于Fortran构建的BLAS、LAPACK等科学计算基石库,以及作为其前端的MATLAB,都继承了列优先的传统,即便后来改用C++重写,为了兼容性和性能也保留了这一布局。

紧密存储与平面存储

颜色数据是交错(紧密)存储还是按平面存储,也取决于应用场景。交错存储,即一个像素的RGB数据紧密相邻,符合图像硬件(每个像素点由RGB子像素构成)和算法(如彩色转灰度)的局部性原理,方便同时访问一个像素的所有颜色通道。而按平面存储,即将整个R、G、B通道分开存放,则更利于矩阵运算。在深度学习或经典图像处理算法中,常常需要将彩色图像视为三个独立的矩阵进行运算,此时每个颜色平面内的数据是连续的,更有利于提升计算效率。

理解图像的内存布局,是从会写代码到写好代码的关键一跃。它不仅关乎速度,更体现了对计算机体系结构的深刻洞察。下次面对性能瓶颈时,不妨先思考一下数据在内存中的样子,也许答案就在其中。你的代码还能优化吗?

内容由AI生成
0
扫一下,分享更方便,购买更轻松
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

最新文章 热门文章