65.9K
CodeProject 正在变化。 阅读更多。
Home

将图像转换为 float[][][]/float[][,]/T[][][]/T[,] 数据,快速且安全

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (17投票s)

2009 年 5 月 13 日

CPOL

4分钟阅读

viewsIcon

207538

downloadIcon

1967

我支持多种方法将图像加载为 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() 是解决这个问题的类。

ImageToDouble/keyWays.jpg

当我使用 bmp 或 jpg 文件加载或保存数据时,我需要 BitmapDataMarshal.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 个错误。抱歉。

我将尽力调试并使其比以前更快

© . All rights reserved.