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;
}
}
}