我想将图像像素延迟加载到3维整数数组。 例如,在简单的方式,它看起来是这样的:F#懒惰像素读取
for i=0 to Width
for j=0 to Height
let point=image.GetPixel(i,j)
pixels.[0,i,j] <- point.R
pixels.[1,i,j] <- point.G
pixels.[2,i,j] <- point.B
如何能在慵懒的方式进行?
我想将图像像素延迟加载到3维整数数组。 例如,在简单的方式,它看起来是这样的:F#懒惰像素读取
for i=0 to Width
for j=0 to Height
let point=image.GetPixel(i,j)
pixels.[0,i,j] <- point.R
pixels.[1,i,j] <- point.G
pixels.[2,i,j] <- point.B
如何能在慵懒的方式进行?
什么会慢是呼叫GetPixel
如果你想打电话给它只是在需要时,你可以使用类似这样的东西:
open System.Drawing
let lazyPixels (image:Bitmap) =
let Width = image.Width
let Height = image.Height
let pixels : Lazy<byte>[,,] = Array3D.zeroCreate 3 Width Height
for i = 0 to Width-1 do
for j = 0 to Height-1 do
let point = lazy image.GetPixel(i,j)
pixels.[0,i,j] <- lazy point.Value.R
pixels.[1,i,j] <- lazy point.Value.G
pixels.[2,i,j] <- lazy point.Value.B
pixels
GetPixel
对于每个像素最多会被调用一次,然后重新用于其他组件。
解决这个问题的另一种方法是对整个图像进行批量加载。这比反复调用GetPixel
要快得多。
open System.Drawing
open System.Drawing.Imaging
let pixels (image:Bitmap) =
let Width = image.Width
let Height = image.Height
let rect = new Rectangle(0,0,Width,Height)
// Lock the image for access
let data = image.LockBits(rect, ImageLockMode.ReadOnly, image.PixelFormat)
// Copy the data
let ptr = data.Scan0
let stride = data.Stride
let bytes = stride * data.Height
let values : byte[] = Array.zeroCreate bytes
System.Runtime.InteropServices.Marshal.Copy(ptr,values,0,bytes)
// Unlock the image
image.UnlockBits(data)
let pixelSize = 4 // <-- calculate this from the PixelFormat
// Create and return a 3D-array with the copied data
Array3D.init 3 Width Height (fun i x y ->
values.[stride * y + x * pixelSize + i])
你什么意思是懒惰?
数组不是懒惰的数据类型,这意味着如果要使用数组,则需要在初始化期间加载所有像素。如果我们使用的是一维数组,则另一种方法是使用seq<_>
这是懒惰的(但您只能按顺序访问元素)。对于多维数组,没有什么像seq<_>
,所以你需要使用别的东西。
也许最接近的选择是使用三维数组的懒值(Lazy<int>[,,]
)。这是一个访问像素的延迟thunks数组,只有在您实际读取该位置处的值时才进行评估。你可以像这样初始化:
for i=0 to Width
for j=0 to Height
let point = lazy image.GetPixel(i,j)
pixels.[0,i,j] <- lazy point.Value.R
pixels.[1,i,j] <- lazy point.Value.G
pixels.[2,i,j] <- lazy point.Value.B
的片断创建一个懒惰的值读取像素(point
),然后三个懒汉值获取单个颜色分量。在访问颜色分量时,将评估point
值(通过访问Value
)。
在你的代码的其余部分的唯一区别是,你需要调用Value
(如pixels.[0,10,10].Value
得到像素的实际颜色分量。
你可以定义更复杂的数据结构(如您自己的类型,支持索引和懒惰),但我认为该数组的懒惰值应该是一个很好的起点
正如您可以使用懒人像素加载3D阵列但只想让与getPixel操作懒,而不是其他的意见已经提到的(从Bitmap.LockBits
的C#示例通过)当您调用Array3D的create方法时,已经分配了数组的内存分配。
如果你想使内存分配以及GetPixel懒惰,那么你可以使用序列如图下面的代码:
let getPixels (bmp:Bitmap) =
seq {
for i = 0 to bmp.Height-1 do
yield seq {
for j = 0 to bmp.Width-1 do
let pixel = bmp.GetPixel(j,i)
yield (pixel.R,pixel.G,pixel.B)
}
}
感谢如何使用LockBits这个例子。你在创建3D阵列的最后一行做什么?它不适合我。 – Goswin 2013-06-24 17:35:03
@Gos Doh。我正在返回索引,而不是值。现在修复。 – 2013-06-24 17:59:46