好久更新了,随便找点东西填一填。
部分函数假定输入的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));
}
}
}