You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何存储16位每通道图像?求C++16位灰度图存储方案及代码示例

处理16位灰度图像的C++方案:格式、库与代码示例

嘿,刚好我之前在C++项目里处理过16位灰度图像的需求,给你整理些实用的方案,应该能帮到你:

一、支持16位每像素灰度的图像格式

  • TIFF:这是最常用的选择,原生完美支持16位灰度,几乎所有专业图像工具都能识别,还能选择无压缩或多种压缩格式(比如LZW、Deflate),非常适合存储高精度的相机图像。
  • PNG:别以为PNG只有8位,它其实原生支持16位灰度模式,压缩效率不错,普通看图软件也能打开,兼容性拉满。
  • OpenEXR:专为高动态范围场景设计,天生支持16位(甚至32位)整数/浮点灰度,适合科研、影视这类对精度要求极高的场景,不过普通工具支持度稍弱。
  • 相机RAW格式:相机原生的RAW文件本身就是16位数据,但需要对应品牌的SDK解析,通用性不强,除非你专门做相机原生数据处理。

二、推荐的C++读写库

  • stb_image/stb_image_write:强推!单头文件库,无需编译,直接include就能用,对16位PNG和TIFF的读写支持很到位,个人项目或者轻量场景首选,零配置成本。
  • libtiff:老牌专业TIFF处理库,对16位灰度的支持极其完善,API虽然有点复古但稳定性拉满,跨平台,适合复杂的TIFF定制需求(比如自定义压缩、元数据)。
  • OpenCV:如果你已经在用OpenCV做图像处理,那直接用它的imread/imwrite就行——读取时加IMREAD_UNCHANGED标志保留16位深度,写入时自动识别格式(TIFF、PNG都支持),无缝衔接。
  • FreeImage:封装友好的多格式库,支持16位灰度的TIFF、PNG等,跨平台,适合需要同时处理多种格式的场景。

三、16位灰度图像写入文件的代码片段

1. stb_image_write(最简单,零依赖)

先下载stb_image_write.h,然后直接用:

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

// 写入16位灰度PNG
int write_16bit_gray_png(const char* filename, int width, int height, const uint16_t* data) {
    // 参数说明:文件名、宽、高、通道数(1=灰度)、数据指针、行字节数
    return stbi_write_png(filename, width, height, 1, data, width * sizeof(uint16_t));
}

// 写入16位灰度TIFF
int write_16bit_gray_tiff(const char* filename, int width, int height, const uint16_t* data) {
    return stbi_write_tiff(filename, width, height, 1, data);
}

// 调用示例
int main() {
    const int width = 640, height = 480;
    uint16_t* image_data = new uint16_t[width * height];
    
    // 这里替换成你的相机数据填充逻辑
    // 比如:memcpy(image_data, camera_buffer, width*height*sizeof(uint16_t));
    
    write_16bit_gray_png("camera_output_16bit.png", width, height, image_data);
    write_16bit_gray_tiff("camera_output_16bit.tif", width, height, image_data);
    
    delete[] image_data;
    return 0;
}

2. libtiff(专业场景)

需要链接libtiff库,适合需要定制TIFF参数的场景:

#include <tiffio.h>

void write_16bit_gray_libtiff(const char* filename, int width, int height, const uint16_t* data) {
    TIFF* tif = TIFFOpen(filename, "w");
    if (!tif) return;

    // 设置TIFF元数据
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
    TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
    TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); // 0=黑,65535=白
    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); // 可选压缩格式
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);

    // 逐行写入(TIFF标准要求逐行处理)
    for (int y = 0; y < height; ++y) {
        const uint16_t* row_ptr = data + y * width;
        if (TIFFWriteScanline(tif, (void*)row_ptr, y, 0) == -1) {
            break;
        }
    }

    TIFFClose(tif);
}

// 调用示例类似上面,编译时记得链接libtiff(比如g++ -o test test.cpp -ltiff)

3. OpenCV(已有OpenCV环境)

如果你的项目已经用了OpenCV,这是最省心的方式:

#include <opencv2/opencv.hpp>

void write_16bit_gray_opencv(const char* filename, int width, int height, const uint16_t* data) {
    // 创建16位灰度Mat对象
    cv::Mat gray_image(height, width, CV_16UC1, (void*)data);
    // 直接写入,OpenCV自动处理格式(支持TIFF、PNG)
    cv::imwrite(filename, gray_image);
}

// 调用示例
int main() {
    const int w = 640, h = 480;
    uint16_t* camera_data = new uint16_t[w*h];
    // 填充相机数据...
    
    write_16bit_gray_opencv("opencv_output.tif", w, h, camera_data);
    
    delete[] camera_data;
    return 0;
}

小提醒:从相机获取的原始16位数据要注意字节序(大端/小端),大部分库会自动适配,但如果写入的图像显示异常,记得检查字节序,必要时用__builtin_bswap16手动交换高低位。

内容的提问来源于stack exchange,提问作者Fernando

火山引擎 最新活动