掘金 人工智能 43分钟前
IP101系列:图像存储技术,从基础概念到性能优化
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入浅出地讲解了图像存储的关键概念与技术。从像素、位深度、分辨率等基础概念入手,详细介绍了RAW、JPEG、PNG、WebP等多种存储格式及其特性。同时,阐述了RGB/BGR、YUV、HSV/HSL等颜色空间,以及连续存储、分离存储等内存布局方式。针对深度学习,对比了NCHW和NHWC两种主流张量格式。最后,探讨了内存访问优化、SIMD优化、内存池、零拷贝技术等性能优化策略,并提供了实战建议,助力读者掌握图像存储的核心技术。

🧱 **基础概念:** 图像由像素构成,像素的颜色深度(位深度)决定了图像的色彩丰富程度。分辨率则决定了图像的清晰度,即图像包含的像素数量。

🗄️ **存储格式:** 图像存储格式分为原始格式(如RAW)和压缩格式(如JPEG、PNG、WebP)。JPEG是有损压缩,适合照片;PNG是无损压缩,适合图形;WebP兼具两者优点,是网页图片的新选择。

🌈 **颜色空间:** RGB/BGR是基于三原色的颜色空间;YUV将亮度与色度分离,可以节省存储空间;HSV/HSL则更符合人类对颜色的直观理解。

🧠 **内存布局:** 图像数据可以连续存储或分离存储。连续存储将所有像素数据按顺序排列,而分离存储则将不同颜色通道的数据分开存储。此外,内存对齐也是影响性能的重要因素。

🚀 **性能优化:** 优化图像存储性能的关键在于优化内存访问模式、使用SIMD指令集进行并行处理、采用内存池管理以及应用零拷贝技术。

📦 图像存储秘籍

🌟 在计算机视觉的世界里,理解图像存储就像是掌握了数字图像的"DNA"。今天,让我们一起来当福尔摩斯,解开图像数据存储之谜!

📚 目录

    基础概念 - 计算机眼中的"世界"存储格式 - 数字图像的"百宝箱"内存布局 - 数据的"豪宅装修指南"深度学习格式 - AI时代的"新潮流"性能优化 - 存储的"速度与激情"

🎯 基础概念

1. 像素(Pixel)- 图像界的"原子"

就像乐高积木一样,再宏伟的建筑也是由一个个小方块搭建而成。在图像世界里,这些"小方块"就是像素:

像素的"全家福":┌──────────────┐│ 二值像素:1bit│ <- 非黑即白的小清新├──────────────┤│ 灰度像素:8bit│ <- 文艺黑白片├──────────────┤│ 彩色像素:24bit│ <- 多彩人生└──────────────┘

2. 位深度(Bit Depth)- 色彩界的"财富密码"

决定每个像素能"穿"多少种颜色:

位深度可表示颜色数典型应用通俗解释
1位2 (2¹)二值图像非黑即白,像考试答题卡
8位256 (2⁸)灰度图像一生只爱一种颜色,但有256种深浅
24位16.7M (2²⁴)真彩色比你衣柜里的衣服还要多的选择
32位4.3B (2³²)带透明通道加上了"隐身衣"功能

3. 分辨率(Resolution)- 图像的"颜值密度"

就像房地产一样,面积(分辨率)决定气质:

class ImageResolution:    def __init__(self, width, height):        self.width = width    # 横向有多少"格子"        self.height = height  # 纵向有多少"格子"        self.total_pixels = width * height  # 总"面积"        self.aspect_ratio = width / height  # "身材比例"

📊 存储格式

1. 二进制格式 - 数据的"生存方式"

1.1 原始格式(RAW)- 数据的"素颜照"
// 最简单的图像存储方式,就像把数据打包放进快递盒struct RawImage {    uint32_t width;      // 宽度,像盒子的长    uint32_t height;     // 高度,像盒子的宽    uint8_t* data;       // 像素数据,就是盒子里的东西};
1.2 压缩格式 - 数据的"变形记"
# 各种压缩格式的"江湖地位"formats = {    'JPEG': {        'compression': 'lossy',        # 有损压缩,像把衣服叠起来,难免有褶皱        'best_for': 'photographs',     # 最适合拍照,不适合存放你的代码        'typical_ratio': '10:1'        # 压缩比,像减肥成功率    },    'PNG': {        'compression': 'lossless',     # 无损压缩,像真空压缩袋        'best_for': 'graphics',        # 最适合图形,保证线条不变形        'typical_ratio': '2:1'         # 压缩比相对保守    },    'WebP': {        'compression': 'both',         # 双模压缩,像可以变形的变形金刚        'best_for': 'web images',      # 网页图片的新宠        'typical_ratio': '15:1'        # 压缩比很激进    }}

2. 颜色空间 - 色彩的"多重宇宙"

2.1 RGB/BGR - 三原色的"铁三角"
三原色的"组合拳":┌─────┬─────┬─────┐│  R  │  G  │  B  ││(红) │(绿) │(蓝) │ <- 光的三原色,不是颜料哦!└─────┴─────┴─────┘
2.2 YUV - 亮度与色度的"分居协议"
明暗与色彩分开存放:┌─────┬─────┬─────┐│  Y  │  U  │  V  ││(亮度)│(色度)│(色度)│ <- Y独居,UV合租└─────┴─────┴─────┘存储方案的"节约攻略"YUV444: Y Y Y Y  每个Y都有专属UV(豪华套房)        U U U U        V V V VYUV422: Y Y Y Y  两个Y共享一组UV(合租房)        U U        V VYUV420: Y Y Y Y  四个Y共享一组UV(群租房)        Y Y Y Y        U U        V V
2.3 HSV/HSL - 更符合人类直觉的"色彩世界"
更接地气的颜色表示:┌─────┬─────┬─────┐│  H  │  S  │  V  ││(色相)│(饱和)│(明度)│ <- 像调色盘一样直观└─────┴─────┴─────┘

💾 内存布局

1. 连续存储 - 数据的"一字长城"

// 一维数组存储,像把所有东西排成一队template<typename T>class ImageData {    T* data;          // 数据"长队"    size_t width;     // 队伍每排多少人    size_t height;    // 有多少排    size_t channels;  // 每个人带多少个"背包"    T& at(size_t x, size_t y, size_t c) {        return data[(y * width + x) * channels + c];  // 找到指定位置的"战士"    }};

2. 分离存储 - 数据的"三国演义"

// 三个通道分开存储,像三个独立的王国template<typename T>class PlanarImage {    T* channel_r;     // 红色王国    T* channel_g;     // 绿色王国    T* channel_b;     // 蓝色王国    size_t width;     // 每个王国的宽度    size_t height;    // 每个王国的高度    T& at_channel(T* channel, size_t x, size_t y) {        return channel[y * width + x];  // 在指定王国找到子民    }};

3. 对齐要求 - 内存的"强迫症"

// 内存对齐,像排队时要求站在地砖的格子上struct alignas(4) Pixel {    // 4字节对齐,像四人一组    uint8_t r;    uint8_t g;    uint8_t b;    uint8_t a;};// 行对齐,像每排都要凑够一定人数size_t row_stride = ((width * channels + 3) & ~3);  // 4字节对齐

🤖 深度学习格式

1. NCHW(Channels First)- PyTorch的"独门武功"

class NCHWTensor:    def __init__(self, batch_size, channels, height, width):        self.shape = (batch_size, channels, height, width)        # PyTorch的默认格式,像先按颜色分类,再按位置排列        self.data = torch.zeros(self.shape)    def get_feature_map(self, batch_idx, channel_idx):        return self.data[batch_idx, channel_idx, :, :]

2. NHWC(Channels Last)- TensorFlow的"秘传心法"

class NHWCTensor:    def __init__(self, batch_size, height, width, channels):        self.shape = (batch_size, height, width, channels)        # TensorFlow的默认格式,像先按位置排列,再按颜色分类        self.data = tf.zeros(self.shape)    def get_pixel(self, batch_idx, h, w):        return self.data[batch_idx, h, w, :]

3. 格式转换 - "武功秘籍互译"

def convert_format(image, source='NHWC', target='NCHW'):    if source == 'NHWC' and target == 'NCHW':        # 从TensorFlow转PyTorch,像改变队伍的排列方式        return image.transpose(0,3,1,2)    elif source == 'NCHW' and target == 'NHWC':        # 从PyTorch转TensorFlow,反其道而行之        return image.transpose(0,2,3,1)

⚡ 性能优化

1. 内存访问优化 - "数据的高速公路"

1.1 缓存友好的访问模式 - "遵守交通规则"
// 不好的实现 - 像在车流中横穿马路for(int x = 0; x < width; x++)    for(int y = 0; y < height; y++)        process_pixel(data[y][x]);// 优化实现 - 像按车道有序行驶for(int y = 0; y < height; y++)    for(int x = 0; x < width; x++)        process_pixel(data[y][x]);
1.2 SIMD优化 - "数据的并行高速路"
// 使用SIMD进行图像处理,像多车道同时通行void process_row_simd(uint8_t* row, int width) {    __m128i* row_ptr = (__m128i*)row;    for(int x = 0; x < width; x += 16) {        __m128i pixels = _mm_load_si128(row_ptr);        // 同时处理16个像素,像16辆车并排行驶        _mm_store_si128(row_ptr, pixels);        row_ptr++;    }}

2. 存储优化 - "数据的精打细算"

2.1 内存池 - "循环利用的游泳池"
template<typename T>class ImageMemoryPool {    std::vector<T*> free_buffers;  // 空闲的"泳道"public:    T* acquire(size_t size) {      // 申请一个"泳道"        if(free_buffers.empty())            return new T[size];     // 没有空闲的就新建一个        T* buffer = free_buffers.back();        free_buffers.pop_back();    // 有空闲的就重复使用        return buffer;    }    void release(T* buffer) {       // 用完放回去        free_buffers.push_back(buffer);    }};
2.2 零拷贝技术 - "数据的意念移动"
class ZeroCopyImage {    void* data;    size_t size;public:    // 使用内存映射文件,像用传送门直接访问    void map_file(const char* filename) {        int fd = open(filename, O_RDWR);        data = mmap(NULL, size, PROT_READ|PROT_WRITE,                   MAP_SHARED, fd, 0);        close(fd);    }};

3. 并行处理 - "多线程的大合唱"

void process_image_parallel(Image& img) {    #pragma omp parallel for  // 多个线程一起处理,像多人合作    for(int y = 0; y < img.height; y++) {        for(int x = 0; x < img.width; x++) {            process_pixel(img.at(x, y));        }    }}

📝 实战锦囊

    选择合适的存储格式

      考虑使用场景(显示/传输/处理)- 像选择合适的交通工具权衡压缩率和质量 - 像选择快递的服务等级评估解码性能需求 - 像考虑收货时间

    优化内存布局

      使用合适的对齐方式 - 像排队要整齐选择适合的存储模式 - 像选择合适的仓库类型考虑缓存友好的访问模式 - 像规划最优配送路线

    性能优化攻略

      使用SIMD指令集 - 像开启"多车道模式"实现并行处理 - 像多个快递员同时送货采用内存池管理 - 像循环使用快递箱应用零拷贝技术 - 像使用虫洞传送

🔗 延伸阅读

📚 进阶探索


💡 小贴士:图像存储看起来简单,但暗藏玄机。掌握这些基础知识,就像练就了一身"数字武功"!记住,即使是火箭科学家也是从"1+1=2"开始学起的~ 😉

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

图像存储 计算机视觉 深度学习 性能优化 数据结构
相关文章