Bitmap image manipulation

流过昼夜 提交于 2019-12-20 02:39:10

问题


I want to replace GetPixel and SetPixel using LockBits method, so I came across this F# lazy pixels reading

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])

At the end of the code, it returns a 3D array with the copied data.

  1. So the 3D array is a copied image, how do I edit the pixels of the 3D array such as changing color? What is the pixelSize for? Why store an image in 3D byte array not 2D?

  2. Example if we want to use 2D array instead, and I want to change the colors of specified pixels, how do we go about doing that?

  3. Do we do operations on the given copied image in bytearray OUTSIDE pixels function OR we do it INSIDE the pixels function before unlocking the image?

  4. If we no longer use GetPixel or SetPixel? How do I retrieve color of the pixels from the copied image byte[]?

If you don't understand my questions, please do explain how do I use above code to do opeation such as "add 50" to R,G,B of every pixel of a given image, without getPixel, setPixel


回答1:


  1. The first component of the 3D array is the colour component. So at index 1,78,218 is the value of the blue component of the pixel at 78,218.

  2. Like this:

    Array2D.init Width Height (fun x y -> 
        let color i = values.[stride * y + x * pixelSize + i] |> int
        new Color(color 0, color 1, color 2)
    
  3. Since the images is copied, it doesn't make a difference if you mess with it before or after unlocking the image. The locking is there to make sure nobody changes the image while you do the actual copying.

  4. The values array is a flattening of a 2D array into a flat array. The 2D-index .[x,y] is at stride * y + x * pixelSize. The RGB components then have a byte each. This explains why this finds the i'th color component at x,y:

     values.[stride * y + x * pixelSize + i] |> int
    

To add 50 to every pixel, its easier to use the original 3D array. Suppose you have an image myImage:

pixels (myImage) |> Array3D.map ((+) 50) 

The type of this is Array3D<Color>, not Image. If you need the an Image, you'll need to construct that, somehow, from the Array3D you now have.



来源:https://stackoverflow.com/questions/22854027/bitmap-image-manipulation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!