# 1.图像功能实现
邮箱:yiyangyu1314@outlook.com
作者:易陽羽
时间:2023-06-08
2
3
4
5
# 1.1 使用C++实现12位图像buffer 拉伸为16位图像
这是一个相对较广泛的向导性问题,需要进行多方面的考虑和分析。下面是一些建议和思考:
首先确定应用程序的具体需求。您需要什么功能?它是用来管理什么类型的数据或信息?例如,如果它是用于管理图片或视频数据,那么将OPENCV集成到WPF中可能会很重要。
确定数据库设计,以便能够存储和检索必要的数据。使用MYSQL可以提供一个开源且跨平台的解决方案,但需要熟悉SQL。
开发并测试您的WPF用户界面。这需要一定的编程技术和WPF知识。
集成OPENCV库到您的应用程序中。这需要你对计算机视觉技术有良好的理解,以及集成C++代码到C#的能力。
编写后台逻辑代码,使其与数据库交互以获取/存储数据。需要熟悉MySQL数据库,并在C#中使用ADO.NET库来实现与数据库的通信。
最后,进行综合测试和部署。确保整个应用程序在各个环境中都能正常运行。
总之,开发一个涉及多种技术和领域的应用程序是一个复杂的工作,需要大量的计划、设计和测试。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
要将12位图像 buffer 拉伸为 16 位图像,可以采用如下方法:
- 首先确定如何将 12 位数据(假设数据类型为 unsigned short)扩展成 16 位数据。我们可以考虑在高四位补充 0 或者重复 低四位的数值,例如,将 0x123 转换为 0x0123 或者 0x1230。
- 定义一个新数组用于储存 16 位数据,并根据第一步中确定的方式对原始图像的 12 位数据进行扩展。
- 在扩展后的数组中进行拉伸操作,即根据结果图像的最大灰度值和最小灰度值,按比例对每个像素进行重新映射。例如,如果 结果图像的最大灰度值是 65535,最小灰度值是 0,则对于第 i 个像素,新的灰度值应该是:
new_pixel[i] = (original_pixel[i] - min_value) * 65535 / (max_value - min_value)
其中 original_pixel[i] 表示原始图像中第 i 个像素值,min_value 和 max_value 分别表示原始图像所有像素值中的最小和最大值。
通过这样的方式,就可以将 12 位图像 buffer 拉伸为 16 位图像。需要注意的是,在编写代码时要处理好边界条件,确保图 像处理的正确性。
# 1.2 实现大恒相机图像12位的buffer拉伸为16位图像
对于大恒相机的图像,可以使用其提供的 SDK 进行采集和处理。将 12 位图像 buffer 拉伸为 16 位图像的方法可以如下:
- 在 SDK 中设置数据的输出格式,使其输出 12 位数据(如果默认输出是 16 位,则需要进行额外的转换处理)。
- 接收采集到的图像数据,并按照数据类型进行强制转换。假设数据类型是 uint16_t,则需将每个 12 位的数值高四位补零 得到一个完整的 uint16_t 数值。
- 定义一个新数组用于储存 16 位数据,并按第二步方式对原始图像的 12 位数据进行扩展。
- 在扩展后的数组中进行拉伸操作,具体方法同上一问题,即根据结果图像的最大灰度值和最小灰度值,按比例对每个像素进行 重新映射。
- 将处理后的数据传递给后续的图像处理或显示模块。
需要注意的是,在实现过程中要检查是否存在数据溢出或越界等情况,并按照实际要求选择合适的映射范围进行拉 伸。同时,由于大恒相机可能有不同的型号和设置,需要在程序中进行相应的适配和调整,以确保正确性和稳定性。
# 1.3 用c++实现byte[]数组 保存为tiff,png,raw,jpg功能
将 byte[] 数组保存为不同格式的图像文件,可以使用相关的 C++ 图像处理库(如 libtiff, libpng, libraw, libjpeg 等)来实现。具体实现步骤可以参考以下步骤:
- 根据需要保存的图像格式选择相应的库,并对其进行初始化配置。
- 将 byte[] 数组中的数据传递到库中,生成相应的图像对象或结构体。
- 根据函数或接口将图像对象或结构体保存为指定格式的图像文件。这些函数或接口通常提供有关压缩、颜色空间、分辨率等参数的选项。
- 释放所有已分配的内存资源,关闭相关的库。
下面是一个简单的代码示例,实现将 byte[] 数组保存为 TIFF 格式的图像文件。
#include <tiffio.h>
void saveTiff(byte* data, int width, int height, const char* filename) {
// 打开 TIFF 文件
TIFF* tif = TIFFOpen(filename, "w");
if (tif) {
// 设置 TIFF 文件属性
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); // 每个样本位数
TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); // 数据格式
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, height);
// 写入图像数据
for (int row = 0; row < height; row++) {
if (TIFFWriteScanline(tif, &data[row * width], row) < 0) {
break;
}
}
TIFFClose(tif);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- 根据不同的文件格式,需要调用相应格式对应的库并设置相应的属性细节。请参考相关的库的文档和示例进行进一步的学习和实践。
# 1.4 C++ 把byte* 保存为12位和16位的bmp,png
将 byte* 数组保存为不同位数和不同格式的图像文件,需要使用相关的 C++ 图像处理库(如 OpenCV,libpng 等)来实现。下面给出一些简单的示例代码:
- 将 byte* 保存为12位BMP图像文件
#include <opencv2/opencv.hpp>
#include <stdint.h>
void save12BitBmp(byte* data, int width, int height, const char* filename) {
const int channels = 1;
cv::Mat image = cv::Mat(height, width, CV_MAKETYPE(CV_16U, channels));
uint16_t *imageData = (uint16_t*)image.ptr(0);//获得图像数据首地址,转换成16-bit指针
int imageIndex = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
imageData[imageIndex++] = ((data[x + y * width] & 0x0F) << 8 | (data[x + y * width] & 0xF0) << 4);
}
}
// 转换为 12 位图像数据,再保存
cv::imwrite(filename, image);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
此函数使用了 OpenCV 库,创建一个 Mat 对象,并将 byte* 数组转换为 16 位的 unsigned short 类型,在给 定范围之内映射到 12 位。最后将其保存为 BMP 格式的图像文件。
- 将 byte* 保存为16位PNG图像文件
#include <png.h>
void save16BitPng(byte* data, int width, int height, const char* filename) {
FILE *fp;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
bool alpha_flag = false;
fp = fopen(filename, "wb");
if (NULL == fp) {
return; // 打开文件失败
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(fp);
return;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(fp);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
return;
}
png_set_IHDR(png_ptr, info_ptr, width, height, 16, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_init_io(png_ptr, fp);
png_write_info(png_ptr, info_ptr);
for (int y = 0; y < height; y++) {
byte* row = data + y*width*sizeof(uint16_t);
png_write_row(png_ptr, (byte*)&row[0]);
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
此函数使用了 libpng 库,创建一个 PNG 结构体和信息结构体,并将 byte* 数组数据保存为 16 位的 PNG 图像文件。 注意,在这个示例中,16位采用unsigned short表示,且需要手动填充每个像素的黑色分量。在实际应用中,根据不同 的需求可能需要进一步调整和优化,保证图像保存质量和正确性。
# 1.5 C# 把Intptr类型 保存为12位和16位的bmp,png,tiff,raw格式
将 IntPtr
类型保存为不同位数和不同格式的图像文件,需要使用相关的 C# 图像
处理库(如 OpenCVSharp, LibTiff.NET, AForge.Imaging 等)来实现。下面给出一些简单的示例代码:
- 将
IntPtr
保存为12位BMP图像文件
using Emgu.CV;
using Emgu.CV.Structure;
public static void Save12BitBmp(IntPtr data, int width, int height, string filename)
{
var channels = 1;
using (var image = new Image<Gray, ushort>(width, height))
{
var imageData = image.DataPointer;
var imageIndex = 0;
for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
{
imageData[imageIndex++] = (ushort)((Marshal.ReadByte(data, x / 2 + y * width / 2) & 0x0F) << 8 | (Marshal.ReadByte(data, x / 2 + y * width / 2) & 0xF0) << 4);
}
}
// 转换为 12 位图像数据,再保存
image.Save(filename);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- 此函数使用了 Emgu CV 库,创建一个 Image 对象,并将
IntPtr
转换为 16 位无符号整 数类型,在给定范围之内映射到 12 位。最后将其保存为 BMP 格式的图像文件。
2.将 IntPtr
保存为16位PNG图像文件
using AForge.Imaging;
using AForge.Imaging.Formats;
using System.Drawing;
public static void Save16BitPng(IntPtr data, int width, int height, string filename)
{
var bitmapData = (Bitmap)ImageDecoder.DecodeFromIntPtr(data, new ImageFormat(isIndexed:false,bitsPerPixel:16));
using (var pngEncoder = new PngEncoder())
{
pngEncoder.Encode(bitmapData, filename);
}
}
2
3
4
5
6
7
8
9
10
11
12
- 此函数使用了 AForge.Imaging 库,将
IntPtr
数据保存为 16 位 PNG 图像文件。
3.将 IntPtr
保存为 TIFF 图像文件
using BitMiracle.LibTiff.Classic;
public static void SaveTiff(IntPtr data, int width, int height, string filename)
{
using (Tiff output = Tiff.Open(filename, "w"))
{
if (output == null)
return;
try
{
// 设置 TIFF 文件属性
output.SetField(TiffTag.IMAGEWIDTH, width);
output.SetField(TiffTag.IMAGELENGTH, height);
output.SetField(TiffTag.BITSPERSAMPLE, 16); // 每个样本位数
output.SetField(TiffTag.SAMPLESPERPIXEL, 1);
output.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);
output.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
output.SetField(TiffTag.COMPRESSION, Compression.NONE);
output.SetField(TiffTag.ROWSPERSTRIP, height);
output.SetField(TiffTag.XRESOLUTION, 96);
output.SetField(TiffTag.YRESOLUTION, 96);
output.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.CENTIMETER);
byte[] buffer = new byte[width * 2];
for (int i = 0; i < height; i++)
{
Marshal.Copy(IntPtr.Add(data, width * 2 * i), buffer, 0, buffer.Length);
output.WriteScanline(buffer, i);
}
}
finally
{
output.Close();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
此函数使用了 LibTiff.NET 库,将 IntPtr
数据保存为 TIFF 格式的图像文件。
4.将 IntPtr
保存为 RAW 图像文件
public static void SaveRaw(IntPtr data, int width, int height, string filename)
{
using (var fileStream = new FileStream(filename, FileMode.Create))
{
using (var binaryWriter = new BinaryWriter(fileStream))
{
var bufferSize = width * 2;
var buffer = new byte[bufferSize];
for (var y = 0; y < height; ++y)
{
Marshal.Copy(data + y * bufferSize, buffer, 0, bufferSize);
binaryWriter.Write(buffer);
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 此函数直接将
IntPtr
数据以原始的二进制形式保存到 RAW 格式的图像文件中。需要注意 的是在不同机器上保存和读取时可能会存在字节序问题,因此在开发过程中要特别注意这方面的设置。
# 1.6 用C#实现一个12位的原始图像IntPtr 拉伸为16位图像buffer
要将 12 位的原始图像 IntPtr
拉伸为 16 位图像,一种简单的方法是对每个像素的值左移四
位,然后对不足 16 位部分进行两次复制以填充。以下为示例代码:
public static unsafe void Stretch12To16Bit(IntPtr input, int width, int height, out ushort[] output)
{
output = new ushort[width * height];
var inputBytes = new byte[((width*3+1)/2)*height];
Marshal.Copy(input, inputBytes, 0, inputBytes.Length);
fixed (ushort* pOutput = output)
{
ushort* ptr = pOutput;
fixed (byte* pInput = inputBytes)
{
for (int i = 0; i < inputBytes.Length; i += 3)
{
int pixelValue = ((pInput[i] << 8) | pInput[i + 1]) << 4;
ptr[0] = (pixelValue & 0xFFF0) | ((pixelValue & 0xF) << 1);
ptr[1] = (pixelValue & 0xFFF0) | ((pixelValue & 0xF) << 1);
ptr += 2;
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 此函数使用了
unsafe
代码块和指针操作提高计算效率。在此之前需要将IntPtr
转换为字节数组(每个像素占用 1.5 个字节),并根据行宽将其转换成 12 位数据。函数返回一个通过拷贝数据生成的具有 16 位深度的输出缓冲区(ushort[]
)。
# 1.7 用C#实现一个Mogo12格式 图像IntPtr 拉伸为16位图像buffer
Mogo12 格式是 Mogo Vision Co. Ltd. 公司的专有图像格式,一种简单的实现方法是对于每个像素值乘以 16 进行拉伸操作,并将不足 16 位的部分用高位进行填充。以下为示例代码:
public static unsafe void StretchMogo12Bit(IntPtr input, int width, int height, out ushort[] output)
{
output = new ushort[width * height];
var buffer = new byte[width * 3];
fixed (ushort* pOutput = output)
{
ushort* ptr = pOutput;
for (int y = 0; y < height; y++)
{
Marshal.Copy(input + y * width * 3 / 2, buffer, 0, buffer.Length);
for (int x = 0; x < width; x++)
{
int pixelValue = ((buffer[x * 3 / 2] & 0x0F) << 8) | buffer[x * 3 / 2 + 1];
*ptr++ = (ushort)(pixelValue << 4);
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 此函数使用
unsafe
代码块和指针操作提高计算效率,与常规的拉伸函数类似,先将输入缓冲区中存放 的数据以一定的格式转换出来(此处采用每个像素 18 位深度的 RGB 数据,中间包含了一个未使用的 6 位),然后 对每个像素的值乘以 16 进行拉伸。函数返回一个通过拷贝数据生成的具有 16 位深度的输出缓冲区(ushort[]
)。
# 1.8 用C++实现Mono12Packed图像格式拉伸位16位,并且保存为tiff,png,jpg,raw文件
下面是用 C++ 实现 Mono12Packed 图像格式拉伸为 16 位并保存为 tiff、png、jpg 和 raw 文件的示例代码。保存 TIFF 和 JPEG 图像需要使用第三方库,以此处使用的 libtiff 和 libjpeg 库为例。
// 包含常用的头文件
#include <fstream>
#include <iostream>
#include <iterator>
#include <algorithm>
// 使用 libtiff 库处理 tiff 格式图像
#include <tiffio.h>
// 使用 libjpeg 库处理 jpeg 格式图像
#include <jpeglib.h>
// OpenCV 库可以读写多种格式的图像
#include <opencv2/opencv.hpp>
void StretchMono12PackedTo16Bit(const uint8_t* input, int width, int height, uint16_t* output)
{
int dstSize = width * height;
int srcSize = ((width + 1) / 2) * height * 3;
const uint8_t* pSrc0 = input;
const uint8_t* pSrc1 = input + 2;
for (int i = 0; i < dstSize; ++i)
{
int value = (pSrc0[0] << 4) | (pSrc1[0] >> 4);
output[i] = static_cast<uint16_t>(value);
pSrc0 += 3;
pSrc1 += 3;
if (pSrc1 >= input + srcSize)
{
pSrc0++;
pSrc1 = pSrc0 + 2;
}
}
}
void SaveAsTIFF(const std::string& filename, int width, int height, int depth, const void* data)
{
TIFF* tiff = TIFFOpen(filename.c_str(), "w");
if (!tiff)
return;
// 设置图像参数
TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, depth);
TIFFSetField(tiff, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
// 写入图像数据
uint32_t row_bytes = (width * depth + 7) / 8;
for (int i = 0; i < height; ++i)
{
TIFFWriteScanline(tiff, static_cast<const char*>(data) + i * row_bytes, i);
}
// 关闭文件
TIFFClose(tiff);
}
void SaveAsPNG(const std::string& filename, int width, int height, const void* data)
{
cv::Mat image(static_cast<int>(height), static_cast<int>(width), CV_16U, const_cast<void*>(data));
cv::imwrite(filename, image);
}
void SaveAsJPEG(const std::string& filename, int width, int height, const void* data)
{
// 声明并初始化 JPEG 相关参数
struct jpeg_compress_struct cinfo{};
struct jpeg_error_mgr jerr{};
// 初始化错误处理
cinfo.err = jpeg_std_error(&jerr);
// 打开输出文件
FILE* outfile = fopen(filename.c_str(), "wb");
if (!outfile)
return;
// 设置输出文件
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
// 设置图像参数
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 1;
cinfo.in_color_space = JCS_GRAYSCALE;
// 设置压缩质量
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 90, TRUE);
// 开始压缩
jpeg_start_compress(&cinfo, TRUE);
JSAMPROW row_pointer[1];
int row_stride = width * sizeof(decltype(*static_cast<const uint16_t*>(data)));
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = static_cast<JSAMPLE*>(&const_cast<uint16_t*>(static_cast<const uint16_t*>(data))[cinfo.next_scanline * width]);
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
// 完成压缩
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
}
void SaveAsRAW(const std::string& filename, const void* data, size_t size)
{
std::ofstream file(filename, std::ios::binary | std::ios::out);
if (!file)
return;
std::copy(static_cast<const uint8_t*>(data), static_cast<const uint8_t*>(data) + size,
std::ostream_iterator<uint8_t>(file));
file.close();
}
int main()
{
// 加载输入数据,假设宽、高、深度等都已知
int width = 1920;
int height = 1080;
std::vector<uint8_t> inputData(width * height * 3 / 2);
std::ifstream inputFile
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# 2.1 图像深度原理是什么
图像深度(bit depth)是指数字图像中用来表达单个像素颜色值的二进制位数。 它决定了一个像素能够表示的不同颜色数量和灰度阶数的范围。
在一个图像中,每个像素由一定数量的位组成:一个二元格式的黑白图像包含1比特的 每个像素;8位灰度图像可以表示256个不同的灰度级别;而16位的彩色图像则可以表 示65536(2^{16}216)种不同的颜色,即每个像素有 2^828 种红色、2^828 种绿色和 2^828 种蓝色组合而成。
图像深度越高,能够表示的颜色范围也就越广,我们更容易区分不同的亮度,并在拍摄 中保留更多的信息。然而,高位数的图像会占用更多的存储空间和计算时间,并对输入设备与输出设备的性能要求更高。
另外,需要注意的是,在图像处理过程中,当我们将低位数的图像放大或缩小时,经常 会产生明显的失真和模糊。这是因为像素之间的差异被放大到可见的程度。因此,在图像 处理任务中,选择正确的图像深度非常重要。
# 2.2 图像深度转换原理和实现
深度转换是将一个任意位数的图像转换为另一个不同位数的图像的过程,通常用 于格式转换或者改变一个图像的亮度范围。下面介绍一种将 8 位灰度图像转换 为 16 位灰度图像的实现方法。
对于 8 位灰度图像每个像素点的值在 0-255 的范围内取值,而 16位灰度图像每个 像素值在 0-65535 的范围内取值。因此,简单的方法是通过线性缩放将 8 位像素值映射到 16 位像素值。
以下为C#代码示例:
public static void Convert8To16Bit(byte[] input, int width, int height, out ushort[] output)
{
output = new ushort[width * height];
byte minPixelValue = input.Min();
byte maxPixelValue = input.Max();
double span = (double)(ushort.MaxValue - ushort.MinValue) / (maxPixelValue - minPixelValue);
for(int i=0; i<input.Length; ++i) {
int pixelValue = (int)Math.Round((input[i] - minPixelValue) * span + ushort.MinValue);
output[i] = (ushort)pixelValue;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
- 此函数输入一维数组
input
中存储了 8 位灰度图像每个像素的值,输出一维数组output
表示位置对应的 16 位像素值。
# 2.3 整理一下图像格式Mono12Packed,Mono12,Mono8,Mono8Packed的存储结构和实现原理
这里是关于不同图像格式的存储结构及其实现原理的简单介绍。
- Mono12Packed Mono12Packed 是一种 12 位深度、只有一个灰度通道的图像格式,其中每 两个相邻像素共用3个字节(即24位)进行存储,低位在前、高位在后。具体来说,如果 用 Little Endian 方式编码,每三个字节可以表示两个像素:
|Byte0, Byte1, Byte2|Byte3, Byte4, Byte5|
|Pixel 0, lo byte |Pixel 0, hi nibble|
|Pixel 1, hi nibble |Pixel 1, lo byte |
2
3
在实际使用中,需要将读取到的数据进行解码处理,重新组合成以连续字节序列存储的
格式,即将上述示例中的 Pixel 0
和 Pixel 1
组合成两个 16 位整数。
- Mono12 Mono12 是一种 12 位深度的图像格式,每个像素用两个字节(16位)存储,高 位在前、低位在后。具体来说,在 Little Endian 编码方式下,每个像素采用以下格式进行存储:
|Byte0 |Byte1 |
|Pixel, high |Pixel, low |
2
- Mono8 Mono8 是一种 8 位深度的灰度图像格式,用一个字节(8位)存储每个像素的灰度值。每个 像素在图像文件中占用一个字节,范围是 0 到 255。
- Mono8Packed Mono8Packed 是一种 8 位深度的灰度图像格式,采用一定方式进行压缩以节约存储空 间。具体来说,它把两个像素共用一个字节(即8位)进行存储,低位存放第一个像素的值,高位存放第二个 像素的值。具体格式如下:
复制代码|Byte0 |
|Pixel 0 (lo)|Pixel 1 (hi)|
2
在读取图像时,需要将从文件中读取的数据按照上述格式解析出各自的像素值。
注:以上内容可能有多种实现方式和变形格式。这里仅介绍了常见的情况,具体使用时请根据自己的需 求和待处理数据的格式进行适当修改。