Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 如何从GetPixelSpan提取、上传和处理字节数组,然后保存回文件?_F#_.net Core_Imagesharp - Fatal编程技术网

F# 如何从GetPixelSpan提取、上传和处理字节数组,然后保存回文件?

F# 如何从GetPixelSpan提取、上传和处理字节数组,然后保存回文件?,f#,.net-core,imagesharp,F#,.net Core,Imagesharp,这可能是一件非常简单的事情,但我不太明白如何将这些片段组合在一起。以及在API文档中,所有这些都或多或少地暗示了答案,但我一直无法从它们中找到我需要的东西 所以现在我正在尝试实现一个天真的小程序来打开一个图像,将像素取出到一个数组中,对它们进行一点处理,然后将更新后的像素保存回一个新图像。在这个特殊的例子中,我想把每个像素周围3x3窗口的平均值作为一个简单的模糊。具体的操作并不太重要(肯定有更有效的方法,我现在特别尝试编写一个幼稚的版本,以便稍后与其他版本进行比较),但我还没有找到实现这一点的方

这可能是一件非常简单的事情,但我不太明白如何将这些片段组合在一起。以及在API文档中,所有这些都或多或少地暗示了答案,但我一直无法从它们中找到我需要的东西

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

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
让accessClampedArrayWithDefault(arr:uint32[][])宽度高度定义x y:uint32[]=
如果x<0 | | x>宽度-1 | | y<0 | | y>高度-1,则
def
其他的
方位角[x+宽度*y]
let extractPixelParts(p:Rgba32)=
设R=uint32 p.R
设G=uint32 p.G
设B=uint32 p.B
设A=uint32 p.A
[R;G;B;A]
[]
让主argv=
使用img=Image.Load(@“D:\Users\sampleimage.jpg”)
让可变输出\u img=img.Clone()
让pxs=img.GetPixelSpan().ToArray()|>Array.map提取PixelParts
让可变(nps:uint32[]]])=Array.zeroCreate pxs.Length
设ac=AccessClampedArray,默认pxs img.宽度img.高度[|0u;0u;0u;0u |]
对于0..img.Width-1 do中的x
对于y,0..img.Height-1 do
设p=ac×y
对于z in-1..1 do
对于w in-1..1 do
设q=ac(x+z)(y+w)
nps。[x+y*img.Width]Array.map(乐趣(a,b)->a+b)
nps。[x+y*惯性宽度]浮动i/9.0 |>uint32)nps。[x+y*惯性宽度]
让rpx=Array.collect(funa->Array.map字节a)nps
释放\u img=Image.Load(img.GetConfiguration(),rpx,Formats.Jpeg.JpegDecoder())
打印fn“out\u img的宽度为%d,高度为%d”out\u img.width out\u img.height
但是它失败了,在
释放\u img=
行出现异常。如果我没有包含JPEG解码器部分,那么我会得到一条关于丢失解码器的错误消息,但是如果我包含了它,那么我会得到一条关于丢失SOI的错误消息

因此,我的问题是,在将最终结果转换回字节之前,如何提取像素并以大于8位(例如32位)的可变大小处理它们/每个通道,以便执行不能以每个通道8位表示的中间操作,然后将其重新构造成可以作为图像保存到磁盘上的东西

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

我对F#不熟悉,但似乎有几个问题:

  • Image.Load(img.GetConfiguration()、rpx、Formats.Jpeg.JpegDecoder())
    将尝试解码内存流中编码的Jpeg(作为
    字节[]
    提供)

  • 关于你的问题:

    因此,我可以执行不能以每个通道8位表示的中间操作

为什么不直接使用
Rgba32[]
阵列呢? 不需要
extractPixelParts…
之类的东西。将所有像素存储在锯齿阵列(
uint32[][]
)中会导致代码执行非常缓慢,因为不必要的堆分配

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

我的建议(仍然没有优化,但可能很容易理解):
  • 不要复制图像。只需通过
    let pxs=img.GetPixelSpan().ToArray()创建一个
    Rgba32[]
    (!!!)
    数组
  • 使用以下公式处理数组内的值:
    arr[y*Width+x]=CreateMyNewRgbaPixelValueAtXY(…)
    其中
    CreateMyNewRgbaPixelValueAtXY(…)
    应返回一个
    Rgba32
  • 通过
    image.LoadPixelData(pxs)
    返回新图像。
    LoadPixelData
    方法将通过将
    pxs:Rgba32[]
    数据复制到图像中来创建新图像
  • 处理您的原始图像
  • 编辑2 为了有效地执行中间操作,我建议如下:

    • 通过调用每个输入像素的
      pixel.ToVector4()
      为中间数组创建一个
      inputPixelData:Vector4[]
    • 创建另一个数组
      outputPixelData:Vector4[]
      并通过处理
      inputPixelData
    • 使用
      .PackFromVector4(outputPixelData[y*Width+x])
      outputPixelData
      打包回一个
      像素:Rgba32[]
      数组(不知道在F中使用这种方法的最佳方式是什么)
    • Image.LoadPixelData(像素)

    也许有更好的方法,但我不熟悉F#。

    是的,用你的输入就可以了!非常感谢:)