using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.Drawing.Imaging; namespace ImageCls { static class ImageProcessing { /// /// Extracts image pixels in CHW using parallelization(提取像素值) /// /// The bitmap image to extract features from /// A list of pixels in CHW order public static List ParallelExtractCHW(this Bitmap image) { // We use local variables to avoid contention on the image object through the multiple threads. int channelStride = image.Width * image.Height; int imageWidth = image.Width; int imageHeight = image.Height; var features = new byte[imageWidth * imageHeight * 3]; var bitmapData = image.LockBits(new System.Drawing.Rectangle(0, 0, imageWidth, imageHeight), ImageLockMode.ReadOnly, image.PixelFormat); IntPtr ptr = bitmapData.Scan0; int bytes = Math.Abs(bitmapData.Stride) * bitmapData.Height; byte[] rgbValues = new byte[bytes]; int stride = bitmapData.Stride; // Copy the RGB values into the array. System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); // The mapping depends on the pixel format // The mapPixel lambda will return the right color channel for the desired pixel Func mapPixel = GetPixelMapper(image.PixelFormat, stride); Parallel.For(0, imageHeight, (int h) => { Parallel.For(0, imageWidth, (int w) => { Parallel.For(0, 3, (int c) => { features[channelStride * c + imageWidth * h + w] = rgbValues[mapPixel(h, w, c)]; }); }); }); image.UnlockBits(bitmapData); return features.Select(b => (float)b).ToList(); } /// /// Returns a function for extracting the R-G-B values properly from an image based on its pixel format(针对图像的对应格式提取像素值) /// /// The image's pixel format /// The stride (row byte count) /// A function with signature (height, width, channel) returning the corresponding color value private static Func GetPixelMapper(PixelFormat pixelFormat, int heightStride) { switch (pixelFormat) { case PixelFormat.Format32bppArgb: return (h, w, c) => h * heightStride + w * 4 + c; // bytes are B-G-R-A case PixelFormat.Format24bppRgb: default: return (h, w, c) => h * heightStride + w * 3 + c; // bytes are B-G-R } } /// /// Resizes an image(实现图片的尺寸变换) /// /// The image to resize /// New width in pixels /// New height in pixels /// Resize quality /// The resized image public static Bitmap Resize(this Bitmap image, int width, int height, bool useHighQuality) { var newImg = new Bitmap(width, height); newImg.SetResolution(image.HorizontalResolution, image.VerticalResolution); using (var g = Graphics.FromImage(newImg)) { g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy; if (useHighQuality) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; } else { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.Default; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.Default; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Default; } var attributes = new ImageAttributes(); attributes.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY); g.DrawImage(image, new System.Drawing.Rectangle(0, 0, width, height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); } return newImg; } } }