问题
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.
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?
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?
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?
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:
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.
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)
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.
The
values
array is a flattening of a 2D array into a flat array. The 2D-index.[x,y]
is atstride * 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