将图像转换为 float[][][]/float[][,]/T[][][]/T[,] 数据,快速且安全
我支持多种方法将图像加载为 double[,]/double[][,]/T[][,], 这可以帮助处理图像
这提供了一种将图像快速安全地转换为 float[][][]/T[][][]
数据的方法。
背景
在图像处理领域,图像数据和算法之间存在一个障碍。在实验室里,数学家和算法工程师擅长矩阵处理。对这些科学家来说,图像只是一个矩阵。因此,他们不需要理解 Bitmap
类。此外,像 MathNet.Numerics 这样的数学工具被设计用来处理 double[]
或 T[]
数据类型。
例如,GDI+ 可以轻松放大图像,但如果你想使用一些高级插值方法来计算插值后的像素值,GDI+ 似乎无能为力。
因此,我在这里支持这个库,将 Image
转换为 float[][][]/float[][,]/T[][][]/T[,]
类型。算法工程师可以专注于算法,而不是“如何正确加载图像”。
同时,我有时发现我们实验室有一些低效的代码,比如 GetPixel()
和 SetPixel()
。所以我认为我需要提供一个连接矩阵和图像的解决方案。
概述
这个类库做了两件事:1. 将图像转换为数组。2. 将数组转换为图像。
通常,图像可以分为两类:a) 单色图像;b) 彩色图像。
单色图像可以用二维矩阵定义:float[Width][Height]/float[Width,Height] 或 T[Width][Height]/T[Width,Height]。
彩色图像可以用三维矩阵定义:float[R/G/B][Width][Height]/
[R/G/B]float[Width,Height] 或 T[R/G/B][Width][Height]/T[R/G/B][Width,Height]。
这里我支持这 4 种数据类型。
使用代码
构建完单个 cs 文件 (DoubleToImageMethod.cs) 后,您将获得一个 DLL 文件。为此 DLL 添加引用。
string fileName = "test.bmp";
float[][][] image;
//here we god the image matrix
image= DoubleToImageMethods.LoadFromFile(fileName);
// ...Do something with this matrix, for example, pattern recognize
现在您从 test.bmp 中获得了三个通道。
image[0] 是红色通道,image[1] 是绿色通道,image[2] 是蓝色通道。您也许可以对图像做些什么。完成工作后,您应该保存数据:
<pre lang="cs">// then save the matrix as a Bmp image file
DoubleToImageMethods.SaveToBmpLinear(image, "test.bmp");
然后您就得到了结果。
有时,您需要其他数据类型,例如,您需要比 float
更精确的值,比如 double
。您可以使用这种方式加载图像:
string fileName = "test.bmp"; string fileName = "test.bmp";
double[][][] image;
//here we god the image matrix, and here request the double[][][] data type
image= DoubleToImageMethods.LoadFromFile<double>(fileName);
// ...Do something with this matrix
方法详情
有三种方法:
1. 从文件加载图像矩阵
v2.0 统一了加载方法,加载图像的方式如下。它将图像文件加载为 T[][][]/T[][,]
矩阵。
a.
T[][][] LoadFromFile<T>(string fileName)
and
T[][,] LoadFromFile2DArray<T>(string fileName)
我定义了 PixelFormat.Format24bppRgb
,所以我总是得到图像的 RGB 通道,即使图像文件是 8 位灰度图像。如果您加载的是单色图像文件,则三个通道具有相同的值。
2. 将 T[][] /T[,]/ T[][,] /T[][][] 数据保存到图像文件
a.
void SaveToBmpLinear<T>(T[][,] image, string fileName)
void SaveToBmpLinear<T>(T[][][] image, string fileName)
将 T[][,]/T[][][]
图像保存为 RGB 24 位 BMP 类型图像文件。保存前,它会拉伸数据到 0-255。这可以提高图像的对比度。
b.
void SaveToBmpLinear<T>(T[,] image, string fileName)
void SaveToBmpLinear<T>(T[][] image, string fileName)
将 T[,]/T[][]
图像保存为 RGB 24 位 BMP 类型图像文件。红色、绿色、蓝色值相同。因此,它看起来像一个 8 位黑白图像,但它是一个真正的 24 位 BMP 文件。保存前,它会拉伸数据到 0-255。这可以提高图像的对比度。
c.
SaveToBmpNoLinear<T>(T[,] image, string fileName)
SaveToBmpNoLinear<T>(T[][] image, string fileName)
将 T[][]/T[,]
图像保存为 RGB 24 位 BMP 类型图像文件。红色、绿色、蓝色值相同。因此,它看起来像一个 8 位黑白图像,但它是一个真正的 24 位 BMP 文件。但它不会拉伸颜色范围。
d.
SaveToBmpNoLinear<T>(T[][,] image, string fileName)
SaveToBmpNoLinear<T>(T[][][] image, string fileName)
将 T[][,]/T[][][]
图像保存为 RGB 24 位 BMP 类型图像文件。
e.
Image ToImageLinear<T>(T[,] image)
Image ToImageLinear<T>(T[][] image)
将 T[,]/T[][]
保存到 System.Drawing.Image 类型,带有颜色拉伸,24 位 RGB 图像,看起来像 8 位灰度图像;
f.
Image ToImageLinear<T>(T[][,] image) Image ToImageLinear<T>(T[][][] image)
将 T[][,]/T[][][]
保存到 System.Drawing.Image 类型
3. 将图像转换为 T[][,]/T[][][]
a.
T[][][] LoadFromImage<T>(Image img)
将图像数据加载到 T[R/G/B][Width][Height]。
b.
T[][,] LoadFromFile2DArray<T>(Image img)
将图像数据加载到 T[R/G/B][Width,Height]。
关键方法
我发现 Marshal.Copy()
是解决这个问题的类。
当我使用 bmp 或 jpg 文件加载或保存数据时,我需要 BitmapData
和 Marshal.Copy()
,它为我提供了一种快速安全的方式来加载或保存数据。
代码效率
我使用 Parallel.For()
来填充矩阵,这显然提高了加载大图像文件(大于 5000*3000 像素)时的程序效率。
Parallel.For(0, imgHeight, (int i) =>
{
for (int j = 0; j < imgExtentWidth; j += 3)
{
if (j < imgWidth * 3)
{
linlizeImg[i * imgExtentWidth + j] = arrayData[2][j / 3][i];
linlizeImg[i * imgExtentWidth + j + 1] = arrayData[1][j / 3][i];
linlizeImg[i * imgExtentWidth + j + 2] = arrayData[0][j / 3][i];
}
else
{
linlizeImg[i * imgExtentWidth + j] = linlizeImg[i * imgExtentWidth + j - 1];
}
}
});
历史
- 2014 年 8 月 24 日,版本 2.1。简化了整个代码,删除了所有克隆代码,并支持 8000*8000 甚至更大的大图像~
- 2012 年 4 月 13 日,更新到 .net 4.0,重构了整个项目,使用了 net40 中的并行功能
- 2009 年 10 月 23 日,更新了网上的描述。
- 2009 年 5 月 23 日,更新,提供了 ImageData 转换的模板方法。修正了 rgbImage 方法中的一些错误
- 2009 年 5 月 10 日,更新,修正了 RGB 图像中的一些错误
- 2009 年 3 月 11 日,更新,修正了 RGB 图像中的 2 个错误。抱歉。
我将尽力调试并使其比以前更快