好久更新了,随便找点东西填一填。
部分函数假定输入的bitmap是24bpprgb格式。
GetColorEntropy
获取图片的色彩熵,一定程度的反映了图片的质量。
从一段c++代码翻译过来,代码风格有点怪。
GetRgbHistogram
获取图片的RGB颜色的直方图统计。
CropRGBValues
从一个RGB数组里获取一个矩形里的RGB数组。
CropRGBValuesFromBitmapFrame
从一个BitmapFrame里获取一个矩形里的RGB数组,这个函数其实是先转成Bitmap然后重画一个bitmap。
GetRGBValuesFromBitmap
获取一个Bitmap的RGB数组。
GetRGBValuesFromBitmapFrame
获取一个BitmapFrame的RGB数组。
WriteRGBValuesToBitmap
把一个RGB数组写到一个Bitmap中,方便保存出来看看模样。
GetBitmapFromBitmapSource
利用BitmapData把RGB数据从BitmapSource拷贝到Bitmap。
也可以利用BmpBitmapEncoder,先把数据拷到MemoryStream,然后再从MemoryStream构造Bitmap。
BitmapFrame继承了BitmapSource,所以这个函数也可以传BitmapFrame。
GetBitmapFromBitmapFrame
同上,不过这里用的BmpBitmapEncoder。
GetBitmapSourceFromBitmap
从Bitmap里获取BitmapSource。
GetBitmapFrameFromBitmap
先获取BitmapSource,然后Create BitmapFrame。
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media.Imaging; namespace MyTools { class BitmapHelper { public static double GetColorEntropy(byte[] rgbValues, int dwWidth, int dwHeight, int lStride) { int dwRSize = 16, dwGSize = 16, dwBSize = 16; int dwNumBins = dwRSize * dwGSize * dwBSize; var pdHistogramForColorEntropy = GetRgbHistogram(rgbValues, dwWidth, dwHeight, lStride); // Compute the entropy based on the histogram. double dEntropy = 0.0; for (int n = 0; n < dwNumBins; n++) { if (pdHistogramForColorEntropy[n] > 0.0) { dEntropy += -pdHistogramForColorEntropy[n] * Math.Log(pdHistogramForColorEntropy[n]); } } dEntropy /= Math.Log(2.0); if (dEntropy < 0.0) { dEntropy = 0.0; } return dEntropy; } public static double[] GetRgbHistogram(byte[] rgbValues, int dwWidth, int dwHeight, int lStride) { int dwRSize = 16, dwGSize = 16, dwBSize = 16; int c_dwProcessImageWidth = 80; int c_dwProcessImageHeight = 60; int dwNumBins = dwRSize * dwGSize * dwBSize; double[] pdHistogram = new double[dwNumBins]; Array.Clear(pdHistogram, 0, pdHistogram.Length); int dwSubsampleRatioX = Math.Max(dwWidth / c_dwProcessImageWidth, 1); int dwSubsampleRatioY = Math.Max(dwHeight / c_dwProcessImageHeight, 1); int dwNumSamples = (dwWidth / dwSubsampleRatioX) * (dwHeight / dwSubsampleRatioY); float fRQtzRatio = (dwRSize - 1) / 255.0f; float fGQtzRatio = (dwGSize - 1) / 255.0f; float fBQtzRatio = (dwBSize - 1) / 255.0f; long lInputXOffset = dwSubsampleRatioX * lStride; long lInputYOffset = dwSubsampleRatioY * lStride; for (int y = 0; y < dwHeight; y += dwSubsampleRatioY) { for (int x = 0; x < dwWidth; x += dwSubsampleRatioX) { int idx = (y * dwWidth + x) * 3; int dwB = (int)(rgbValues[idx] * fRQtzRatio); int dwG = (int)(rgbValues[idx + 1] * fGQtzRatio); int dwR = (int)(rgbValues[idx + 2] * fBQtzRatio); pdHistogram[dwB * dwGSize * dwRSize + dwG * dwRSize + dwR] += 1.0; } } for (int n = 0; n < dwNumBins; n++) { pdHistogram[n] /= dwNumSamples; } return pdHistogram; } public static byte[] CropRGBValues(byte[] rgbValues, int width, int height, Rectangle rect) { int descStride = rect.Width * 3; int srcStride = width * 3; int destOffset = 0; int srcOffset = (rect.Y * rect.Width + rect.X) * 3; byte[] cropValues = new byte[rect.Width * rect.Height * 3]; for (int i = 0; i < rect.Height; i++) { Array.Copy(rgbValues, srcOffset, cropValues, destOffset, descStride); srcOffset += srcStride; destOffset += descStride; } return cropValues; } public static byte[] CropRGBValuesFromBitmapFrame(BitmapFrame bitmapFrame, Rectangle rect) { Bitmap target = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb); BmpBitmapEncoder encoder = new BmpBitmapEncoder(); encoder.Frames.Add(bitmapFrame); using (MemoryStream ms1 = new MemoryStream()) { encoder.Save(ms1); Bitmap src = new Bitmap(ms1); using (Graphics g = Graphics.FromImage(target)) { g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height), rect, GraphicsUnit.Pixel); } } return GetRGBValuesFromBitmap(target); } public static byte[] GetRGBValuesFromBitmap(Bitmap bmp) { Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat); int st = bmpData.Stride; IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap. int stride = 3; if (bmp.PixelFormat != PixelFormat.Format24bppRgb) { throw new Exception("doesn't support this format"); } int bytes = stride * rect.Width * rect.Height; byte[] rgbValues = new byte[bytes]; // Copy the RGB values into the array. System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); bmp.UnlockBits(bmpData); return rgbValues; } public static byte[] GetRGBValuesFromBitmapFrame(BitmapFrame bitmapFrame) { int width = bitmapFrame.PixelWidth; int height = bitmapFrame.PixelHeight; int bitsPerPixel = bitmapFrame.Format.BitsPerPixel; int stride = (bitsPerPixel >> 3) * width; if (bitsPerPixel != 24) { throw new IOException("expected 24 BPP JXR, but got " + bitsPerPixel); } byte[] rgbValues = new byte[width * height * 3]; bitmapFrame.CopyPixels(rgbValues, stride, 0); return rgbValues; } public static Bitmap WriteRGBValuesToBitmap(byte[] rgbValues, int width, int height) { if (rgbValues.Length != width * height * 3) { throw new Exception("invalid data"); } Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat); int bytes = Math.Abs(bmpData.Stride) * bmp.Height; IntPtr ptr = bmpData.Scan0; System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); bmp.UnlockBits(bmpData); return bmp; } //https://stackoverflow.com/questions/2284353/is-there-a-good-way-to-convert-between-bitmapsource-and-bitmap public static Bitmap GetBitmapFromBitmapSource(BitmapSource source) { Bitmap bmp = new Bitmap( source.PixelWidth, source.PixelHeight, PixelFormat.Format24bppRgb); BitmapData data = bmp.LockBits( new Rectangle(Point.Empty, bmp.Size), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); source.CopyPixels( System.Windows.Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); bmp.UnlockBits(data); return bmp; } public static Bitmap GetBitmapFromBitmapFrame(BitmapFrame source) { // method 1. //GetBitmapFromBitmapSource(source); // method 2. Bitmap bitmap; using (var outStream = new MemoryStream()) { BitmapEncoder enc = new BmpBitmapEncoder(); enc.Frames.Add(source); enc.Save(outStream); bitmap = new Bitmap(outStream); } return bitmap; } public static BitmapSource GetBitmapSourceFromBitmap(Bitmap bmp) { return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( bmp.GetHbitmap(), IntPtr.Zero, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } public static BitmapFrame GetBitmapFrameFromBitmap(Bitmap bmp) { return BitmapFrame.Create(GetBitmapSourceFromBitmap(bmp)); } } }