F#懒惰像素读数

Noz*_*zim 0 f# pixel lazy-evaluation

我想将图像像素延迟加载到3维整数数组.例如,它看起来像这样:

   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
Run Code Online (Sandbox Code Playgroud)

如何以懒惰的方式制作?

Mar*_*rot 5

什么是缓慢的呼吁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
Run Code Online (Sandbox Code Playgroud)

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])
Run Code Online (Sandbox Code Playgroud)

(从C#样本中采用Bitmap.LockBits)