代码之家  ›  专栏  ›  技术社区  ›  Jarak

如何从GetPixelSpan中提取、向上投射和处理字节数组,然后保存回文件?

  •  2
  • Jarak  · 技术社区  · 8 年前

    这可能是一件非常简单的事情,但我不太明白如何把这些部分放在一起。 This question this question 以及 this page 在API文档中,所有这些都暗示了答案,但是我还没有从它们那里得到我需要的东西。

    所以现在我正在尝试实现一个nave小程序来打开一个图像,把像素放到一个数组中,对它们进行一点处理,然后将更新后的像素保存回一个新的图像。在这个特殊的例子中,我想把每个像素周围3x3窗口的平均值作为一个简单的模糊。具体的操作并不太重要(肯定有更有效的方法,我现在特别想写一个nave版本,以便以后与其他版本进行比较),但我还没能想出如何做到这一点。现在我得到的是:

    let accessClampedArrayWithDefault (arr: uint32[][]) width height def x y : uint32[] =
        if x < 0 || x > width-1 || y < 0 || y > height-1 then
            def
        else
            arr.[x + width * y]
    
    let extractPixelParts (p: Rgba32) =
        let R = uint32 p.R
        let G = uint32 p.G
        let B = uint32 p.B
        let A = uint32 p.A
        [|R; G; B; A|]
    
    [<EntryPoint>]
    let main argv =
        use img = Image.Load(@"D:\Users\sampleimage.jpg")    
        let mutable out_img = img.Clone()    
        let pxs = img.GetPixelSpan().ToArray() |> Array.map extractPixelParts    
        let mutable (nps: uint32[][]) = Array.zeroCreate pxs.Length    
        let ac = accessClampedArrayWithDefault pxs img.Width img.Height [|0u;0u;0u;0u|]
    
        for x in 0..img.Width-1 do
            for y in 0..img.Height-1 do
                let p = ac x y
                for z in -1..1 do
                    for w in -1..1 do
                        let q = ac (x + z) (y + w)
                        nps.[x + y * img.Width] <- Array.zip p q |> Array.map (fun (a,b) -> a + b)
                nps.[x + y * img.Width] <- Array.map (fun i -> float i / 9.0 |> uint32 ) nps.[x + y * img.Width]
    
        let rpx = Array.collect (fun a -> Array.map byte a) nps
    
        let out_img = Image.Load<Rgba32>(img.GetConfiguration(), rpx, Formats.Jpeg.JpegDecoder())
    
        printfn "out_img's width is %d and height is %d" out_img.Width out_img.Height
    

    但它正在失败,只有一个例外 let out_img =

    所以,我的问题是,我怎样才能取出像素,并以大于8位(例如32位)的可变大小处理它们/每个通道,以便在将最终结果转换回字节,然后将其重新构造成可以保存到磁盘的内容之前,执行不能用每个通道8位表示的中间操作作为一个形象?

    我很可能忘了提一些重要的事情,所以请随时要求澄清:)谢谢。

    1 回复  |  直到 8 年前
        1
  •  2
  •   klapancius    8 年前

    • Image.Load<Rgba32>(img.GetConfiguration(), rpx, Formats.Jpeg.JpegDecoder()) 我会尽力的 解码 在内存流中编码的Jpeg(作为 byte[] ).

    • 关于你的问题:

      这样我就可以执行不能用每个通道8位表示的中间操作

    Rgba32[] 阵列? extractPixelParts ... 什么东西。将所有像素存储在锯齿状数组中( uint32[][]

    编辑: 对不起,我误解了这一点。如果中间操作需要更高的精度,我建议使用 Vector4 pixel.ToVector4() pixel.PackFromVector4(...)

    我的建议(仍然没有优化,但可能很容易理解):

    1. Rgba32[] (!!!) let pxs = img.GetPixelSpan().ToArray()
    2. 使用以下公式处理数组中的值 arr[y * Width + x] = CreateMyNewRgbaPixelValueAtXY(....) CreateMyNewRgbaPixelValueAtXY(...) 应该返回一个 Rgba32
    3. Image.LoadPixelData(pxs) . 这个 LoadPixelData 方法将通过复制 pxs: Rgba32[]
    4. 处理你的原始图像!

    • 创建 inputPixelData:Vector4[] 通过调用 对于每个输入像素
    • 创建其他数组 outputPixelData:Vector4[] inputPixelData
    • 包裹 outputPixelData 回到一个 pixels:Rgba32[] 数组使用 .PackFromVector4(outputPixelData[y * Width + x]) (不知道什么是最好的方法)
    • Image.LoadPixelData(pixels)