123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985 |
- using System;
- using System.Linq;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Runtime.InteropServices;
- namespace ImageProcessUtilsTest
- {
- public enum EnumMeanValueType
- {
- None,
- ConstantMean,
- CalcMeanImage,
- CalcMeanPerChannel,
- }
- public enum EnumScaleValueType
- {
- None,
- ConstantScale,
- CalcStdImage,
- CalcStdPerChannel,
- }
- public enum EnumNormalizationType
- {
- None,
- MinMaxScalingImage,
- MinMaxScalingPerChannel,
- }
- public enum EnumAxisOrder
- {
- CHW,
- HWC,
- }
- public struct StructImageInfo
- {
- public int width;
- public int height;
- public int channel;
- public IntPtr pData;
- }
- public struct StructMyRect
- {
- public int left;
- public int top;
- public int width;
- public int height;
- }
- public struct StructExtractInfo
- {
- public int meanValueType;
- public float meanR;
- public float meanG;
- public float meanB;
- public int scaleValueType;
- public float scaleR;
- public float scaleG;
- public float scaleB;
- public int normalizationType;
- public bool reverseInputChannels;
- public int axisOrder;
- }
- public class ImageUtils
- {
- #region private variables
- private int _netImgH = 256;
- private int _netImgW = 256;
- private int _netImgC = 3;
- private readonly EnumMeanValueType _meanValueType = EnumMeanValueType.ConstantMean;
- private readonly float _meanR = 61;
- private readonly float _meanG = 63;
- private readonly float _meanB = 66;
- private readonly EnumScaleValueType _scaleValueType = EnumScaleValueType.ConstantScale;
- private readonly float _scaleR = 256;
- private readonly float _scaleG = 256;
- private readonly float _scaleB = 256;
- private readonly EnumNormalizationType _normalizationType = EnumNormalizationType.MinMaxScalingImage;
- private readonly bool _reverseInputChannels = false;
- private readonly EnumAxisOrder _axisOrder = EnumAxisOrder.CHW;
- private float[] _dataBuffer = null;
- private byte[] _padValue = null;
- private RawImage _resizedImage;
- #endregion
- #region properties
- public int NetImgH => _netImgH;
- public int NetImgW => _netImgW;
- public int NetImgC => _netImgC;
- public float[] DataBuffer => _dataBuffer;
- public byte[] ResizedImageDataBuffer => _resizedImage.DataBuffer;
- #endregion
- #region dll import
- [DllImport(@"ImageProcessUtilsLib.dll", EntryPoint = "ResizeBilinear", CallingConvention = CallingConvention.Cdecl)]
- public static extern int ResizeBilinear(StructImageInfo origImg, ref StructImageInfo dstImg);
- [DllImport(@"ImageProcessUtilsLib.dll", EntryPoint = "ResizeBilinearParallel", CallingConvention = CallingConvention.Cdecl)]
- public static extern int ResizeBilinearParallel(StructImageInfo origImg, ref StructImageInfo dstImg);
- [DllImport(@"ImageProcessUtilsLib.dll", EntryPoint = "FillWithPadValue", CallingConvention = CallingConvention.Cdecl)]
- public static extern int FillWithPadValue(ref StructImageInfo origImg, IntPtr padValue);
- [DllImport(@"ImageProcessUtilsLib.dll", EntryPoint = "CropRect", CallingConvention = CallingConvention.Cdecl)]
- public static extern int CropRect(StructImageInfo origImg, StructMyRect cropRect, ref StructImageInfo dstImg);
- [DllImport(@"ImageProcessUtilsLib.dll", EntryPoint = "PasteRect", CallingConvention = CallingConvention.Cdecl)]
- public static extern int PasteRect(StructImageInfo srcImg, StructMyRect pasteRect, ref StructImageInfo dstImg);
- [DllImport(@"ImageProcessUtilsLib.dll", EntryPoint = "ExtractRGB24AsGray", CallingConvention = CallingConvention.Cdecl)]
- public static extern int ExtractRGB24AsGray(StructImageInfo srcImg, IntPtr dstDataPtr, StructExtractInfo extractInfo);
- [DllImport(@"ImageProcessUtilsLib.dll", EntryPoint = "ExtractRGB24AsColor", CallingConvention = CallingConvention.Cdecl)]
- public static extern int ExtractRGB24AsColor(StructImageInfo srcImg, IntPtr dstDataPtr, StructExtractInfo extractInfo);
- #endregion
- #region constructor
- public ImageUtils()
- {
- _resizedImage = new RawImage(new byte[_netImgH * _netImgW * _netImgC], _netImgW, _netImgH, _netImgC);
- _dataBuffer = new float[_netImgH * _netImgW * _netImgC];
- _padValue = new byte[3];
- _padValue[0] = (byte)_meanB;
- _padValue[1] = (byte)_meanG;
- _padValue[2] = (byte)_meanR;
- }
- #endregion
- #region public funcs
- public RawImage BitmapToRawImage(Bitmap image)
- {
- int width = image.Width;
- int height = image.Height;
- PixelFormat pixelFormat = image.PixelFormat;
- if (pixelFormat != PixelFormat.Format24bppRgb && pixelFormat != PixelFormat.Format32bppArgb &&
- pixelFormat != PixelFormat.Format32bppPArgb && pixelFormat != PixelFormat.Format32bppRgb &&
- pixelFormat != PixelFormat.Format8bppIndexed)
- {
- throw new Exception("Unexpected image pixel format:" + pixelFormat);
- }
- int origChannel = 3;
- int dstChannel = 3;
- if (pixelFormat == PixelFormat.Format24bppRgb)
- {
- origChannel = 3;
- }
- else if (pixelFormat == PixelFormat.Format8bppIndexed)
- {
- origChannel = 1;
- }
- else
- {
- origChannel = 4;
- }
- var bmData = image.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, pixelFormat);
- byte[] dstDataArray = new byte[width * height * dstChannel];
- unsafe
- {
- int stride = bmData.Stride;
- int dstStride = width * dstChannel;
- IntPtr ptr = bmData.Scan0;
- IntPtr ptrH, ptrW;
- for (int nh = 0; nh < height; nh++)
- {
- ptrH = IntPtr.Add(ptr, nh * stride);
- if (origChannel == dstChannel)
- {
- Marshal.Copy(ptrH, dstDataArray, nh * dstStride, dstStride);
- }
- else if (origChannel > dstChannel)
- {
- for (int nw = 0; nw < width; nw++)
- {
- ptrW = IntPtr.Add(ptrH, nw * origChannel);
- Marshal.Copy(ptrW, dstDataArray, nw * dstChannel, dstChannel);
- }
- }
- else
- {
- for (int nw = 0; nw < width; nw++)
- {
- ptrW = IntPtr.Add(ptrH, nw * origChannel);
- for (int nc = 0; nc < dstChannel; nc++)
- {
- Marshal.Copy(ptrW, dstDataArray, nw * dstChannel + nc, 1);
- }
- }
- }
- }
- }
- image.UnlockBits(bmData);
- return new RawImage(dstDataArray, width, height, dstChannel);
- }
- public Bitmap RawImageToBitmap(RawImage image)
- {
- int width = image.Width;
- int height = image.Height;
- int channel = image.Channel;
- PixelFormat pixelFormat;
- switch (channel)
- {
- case 1:
- pixelFormat = PixelFormat.Format8bppIndexed;
- break;
- case 3:
- pixelFormat = PixelFormat.Format24bppRgb;
- break;
- case 4:
- pixelFormat = PixelFormat.Format32bppArgb;
- break;
- default:
- throw new ArgumentOutOfRangeException("The expected image.channel is 1,3,4 but got:" + channel + ".");
- }
- Bitmap dstBmp = new Bitmap(width, height, pixelFormat);
- var bmData = dstBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, pixelFormat);
- unsafe
- {
- int stride = bmData.Stride;
- IntPtr ptr = bmData.Scan0;
- byte[] dataBuffer = image.DataBuffer;
- if (stride == width * channel)
- {
- Marshal.Copy(dataBuffer, 0, ptr, width * height * channel);
- }
- else
- {
- IntPtr ptrDst;
- for (int ni = 0; ni < height; ni++)
- {
- ptrDst = IntPtr.Add(ptr, ni * stride);
- Marshal.Copy(dataBuffer, ni * width * channel, ptrDst, width * channel);
- }
- }
- }
- dstBmp.UnlockBits(bmData);
- return dstBmp;
- }
- public RawImage ResizeBilinearWithCpp(RawImage image, int dstWidth, int dstHeight)
- {
- GCHandle hObjectOrig = GCHandle.Alloc(image.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataOrig = hObjectOrig.AddrOfPinnedObject();
- StructImageInfo origImgInfo = new StructImageInfo
- {
- width = image.Width,
- height = image.Height,
- channel = image.Channel,
- pData = pDataOrig,
- };
- RawImage resizedImg = new RawImage(new byte[dstWidth * dstHeight * image.Channel], dstWidth, dstHeight, image.Channel);
- GCHandle hObjectDst = GCHandle.Alloc(resizedImg.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- StructImageInfo dstImgInfo = new StructImageInfo
- {
- width = resizedImg.Width,
- height = resizedImg.Height,
- channel = resizedImg.Channel,
- pData = pDataDst,
- };
- var ret = ResizeBilinear(origImgInfo, ref dstImgInfo);
- if (hObjectOrig.IsAllocated)
- {
- hObjectOrig.Free();
- }
- if (hObjectDst.IsAllocated)
- {
- hObjectDst.Free();
- }
- if (ret != 0)
- {
- throw new Exception("Failed at calling cpp func: ResizeBilinear.(error code: " + ret + ").");
- }
- return resizedImg;
- }
- public RawImage ResizeBilinearParallelWithCpp(RawImage image)
- {
- GCHandle hObjectOrig = GCHandle.Alloc(image.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataOrig = hObjectOrig.AddrOfPinnedObject();
- StructImageInfo origImgInfo = new StructImageInfo
- {
- width = image.Width,
- height = image.Height,
- channel = image.Channel,
- pData = pDataOrig,
- };
- RawImage resizedImg = new RawImage(new byte[_netImgH * _netImgW * _netImgC], _netImgW, _netImgH, _netImgC);
- GCHandle hObjectDst = GCHandle.Alloc(resizedImg.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- StructImageInfo dstImgInfo = new StructImageInfo
- {
- width = resizedImg.Width,
- height = resizedImg.Height,
- channel = resizedImg.Channel,
- pData = pDataDst,
- };
- var ret = ResizeBilinear(origImgInfo, ref dstImgInfo);
- if (hObjectOrig.IsAllocated)
- {
- hObjectOrig.Free();
- }
- if (hObjectDst.IsAllocated)
- {
- hObjectDst.Free();
- }
- if (ret!=0)
- {
- throw new Exception("Failed at calling cpp func: ResizeBilinearParallel.");
- }
- return resizedImg;
- }
- public void FillPadValWithCpp(RawImage image, byte[] padValue)
- {
- GCHandle hObjectOrig = GCHandle.Alloc(image.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataOrig = hObjectOrig.AddrOfPinnedObject();
- StructImageInfo origImgInfo = new StructImageInfo
- {
- width = image.Width,
- height = image.Height,
- channel = image.Channel,
- pData = pDataOrig,
- };
- GCHandle hObjectPadValue = GCHandle.Alloc(padValue, GCHandleType.Pinned);
- IntPtr pDataPadValue = hObjectPadValue.AddrOfPinnedObject();
- var ret = FillWithPadValue(ref origImgInfo, pDataPadValue);
- if (hObjectOrig.IsAllocated)
- {
- hObjectOrig.Free();
- }
- if (hObjectPadValue.IsAllocated)
- {
- hObjectPadValue.Free();
- }
- if (ret!=0)
- {
- throw new Exception("Failed at calling cpp func: FillWithPadValue.");
- }
- }
- public RawImage CropRectWithCpp(RawImage image, MyRect cropRect)
- {
- GCHandle hObjectOrig = GCHandle.Alloc(image.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataOrig = hObjectOrig.AddrOfPinnedObject();
- StructImageInfo origImgInfo = new StructImageInfo
- {
- width = image.Width,
- height = image.Height,
- channel = image.Channel,
- pData = pDataOrig,
- };
- RawImage dstImage = new RawImage(new byte[cropRect.Width * cropRect.Height * image.Channel],
- cropRect.Width, cropRect.Height, image.Channel);
- GCHandle hObjectDst = GCHandle.Alloc(dstImage.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- StructImageInfo dstImgInfo = new StructImageInfo
- {
- width = dstImage.Width,
- height = dstImage.Height,
- channel = dstImage.Channel,
- pData = pDataDst,
- };
- StructMyRect structCropRect = new StructMyRect
- {
- left = cropRect.Left,
- top = cropRect.Top,
- width = cropRect.Width,
- height = cropRect.Height,
- };
- var ret = CropRect(origImgInfo, structCropRect, ref dstImgInfo);
- if (hObjectOrig.IsAllocated)
- {
- hObjectOrig.Free();
- }
- if (hObjectDst.IsAllocated)
- {
- hObjectDst.Free();
- }
- if (ret!=0)
- {
- throw new Exception("Failed at calling cpp func: CropRect.");
- }
- return dstImage;
- }
- public void PasteRectWithCpp(RawImage dstImg, RawImage srcImg, MyRect pasteRect)
- {
- GCHandle hObjectSrc = GCHandle.Alloc(srcImg.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataSrc = hObjectSrc.AddrOfPinnedObject();
- StructImageInfo srcImgInfo = new StructImageInfo
- {
- width = srcImg.Width,
- height = srcImg.Height,
- channel = srcImg.Channel,
- pData = pDataSrc,
- };
- GCHandle hObjectDst = GCHandle.Alloc(dstImg.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- StructImageInfo dstImgInfo = new StructImageInfo
- {
- width = dstImg.Width,
- height = dstImg.Height,
- channel = dstImg.Channel,
- pData = pDataDst,
- };
- StructMyRect structPasteRect = new StructMyRect
- {
- left = pasteRect.Left,
- top = pasteRect.Top,
- width = pasteRect.Width,
- height = pasteRect.Height,
- };
- var ret = PasteRect(srcImgInfo, structPasteRect, ref dstImgInfo);
- if (hObjectSrc.IsAllocated)
- {
- hObjectSrc.Free();
- }
- if (hObjectDst.IsAllocated)
- {
- hObjectDst.Free();
- }
- if (ret!=0)
- {
- throw new Exception("Failed at calling cpp func: PasteRect.");
- }
- }
- /// <summary>
- /// 对原始图像进行缩放
- /// </summary>
- public void DoResize(RawImage image, MyRect roiRect, MyRect moldRect)
- {
- // 先在resizedImage上填充背景色
- _resizedImage.Fill(_padValue);
- // 取出原始图像种的指定范围
- // 注意:由于CalcResizeParams中,当ResizeMode为FitSmallSizeAndCrop时,ROIRect的位置可能会发生改变
- // 所以g.DrawImage时srcRect不要用InputImage里的ROIRect,而是现在的
- var roiRectInSrc = image.CropRect(new MyRect(roiRect.Left, roiRect.Top,roiRect.Width, roiRect.Height));
- // 再将其resize成指定尺寸
- var molded = roiRectInSrc.Resize(moldRect.Width, moldRect.Height, EnumResizeMethod.Bilinear);
- // 再将其贴到resizedImage上指定位置
- _resizedImage.PasteRect(molded, new MyRect(moldRect.Left, moldRect.Top, moldRect.Width, moldRect.Height));
- // 销毁
- roiRectInSrc.Dispose();
- molded.Dispose();
- }
- /// <summary>
- /// 对原始图像进行缩放(用cpp dll中提供的函数)
- /// </summary>
- /// <param name="image"></param>
- /// <param name="imageMetas"></param>
- public void DoResizeCpp(RawImage image, MyRect roiRect, MyRect moldRect)
- {
- // 先在resizedImage上填充背景色
- FillPadValWithCpp(_resizedImage, _padValue);
- // 取出原始图像种的指定范围
- // 注意:由于CalcResizeParams中,当ResizeMode为FitSmallSizeAndCrop时,ROIRect的位置可能会发生改变
- // 所以g.DrawImage时srcRect不要用InputImage里的ROIRect,而是现在的
- var roiRectInSrc = CropRectWithCpp(image, new MyRect(roiRect.Left, roiRect.Top, roiRect.Width, roiRect.Height));
- // 再将其resize成指定尺寸
- var molded = ResizeBilinearWithCpp(roiRectInSrc, moldRect.Width, moldRect.Height);
- // 再将其贴到resizedImage上指定位置
- PasteRectWithCpp(_resizedImage, molded, new MyRect(moldRect.Left, moldRect.Top, moldRect.Width, moldRect.Height));
- // 销毁
- roiRectInSrc.Dispose();
- molded.Dispose();
- }
- /// <summary>
- /// 将原始图像转成单通道的数组
- /// (如果需要做减均值和Scale等操作,也在这一步完成)
- /// </summary>
- public void ExtractRGB24AsGray(int startInd)
- {
- // 计算均值
- float meanR, meanG, meanB, meanImg;
- if (_meanValueType == EnumMeanValueType.CalcMeanImage || _meanValueType == EnumMeanValueType.CalcMeanPerChannel)
- {
- CalcMean(out meanR, out meanG, out meanB, out meanImg);
- }
- else
- {
- meanR = _meanR;
- meanG = _meanG;
- meanB = _meanB;
- meanImg = PixelRGBToGray(meanR, meanG, meanB);
- }
- // 计算方差
- float stdR, stdG, stdB, stdImg;
- if (_scaleValueType == EnumScaleValueType.CalcStdImage || _meanValueType == EnumMeanValueType.CalcMeanPerChannel)
- {
- CalcStd(meanR, meanG, meanB, meanImg, out stdR, out stdG, out stdB, out stdImg);
- }
- else
- {
- stdR = _scaleR;
- stdG = _scaleG;
- stdB = _scaleB;
- stdImg = PixelRGBToGray(stdR, stdG, stdB);
- }
- // 计算最大最小值
- float minR = 0, maxR = 0, minG = 0, maxG = 0, minB = 0, maxB = 0, minImg = 0, maxImg = 0;
- if (_normalizationType != EnumNormalizationType.None)
- {
- CalcMinMax(out minR, out maxR, out minG, out maxG, out minB, out maxB, out minImg, out maxImg);
- if (_meanValueType != EnumMeanValueType.None)
- {
- minImg -= meanImg;
- maxImg -= meanImg;
- }
- if (_scaleValueType != EnumScaleValueType.None)
- {
- minImg /= stdImg;
- maxImg /= stdImg;
- }
- }
- // 进行处理
- byte[] resizedImageDataBuffer = _resizedImage.DataBuffer;
- int resizedImageHeight = _resizedImage.Height;
- int resizedImageWidth = _resizedImage.Width;
- for (int h = 0; h < resizedImageHeight; h++)
- {
- int hIndexOffset = resizedImageWidth * h;
- for (int w = 0; w < resizedImageWidth; w++)
- {
- // Bitmap中通道顺序是BGR,所以srcIndex+2是红色通道的值,srcIndex+1是绿色通道的值,srcIndex是蓝色通道的值
- var srcIndex = hIndexOffset * 3 + 3 * w;
- float bPixelVal = resizedImageDataBuffer[srcIndex];
- float gPixelVal = resizedImageDataBuffer[srcIndex + 1];
- float rPixelVal = resizedImageDataBuffer[srcIndex + 2];
- float gray = PixelRGBToGray(rPixelVal, gPixelVal, bPixelVal);
- if (_meanValueType != EnumMeanValueType.None)
- {
- gray -= meanImg;
- }
- if (_scaleValueType != EnumScaleValueType.None)
- {
- gray /= stdImg;
- }
- if (_normalizationType != EnumNormalizationType.None)
- {
- gray = (gray - minImg) / (maxImg - minImg);
- }
- var dstIndex = startInd + hIndexOffset + w;
- _dataBuffer[dstIndex] = gray;
- }
- }
- }
- /// <summary>
- /// 将原始图像转成单通道的数组(用cpp dll中提供的函数)
- /// (如果需要做减均值和Scale等操作,也在这一步完成)
- /// </summary>
- public void ExtractRGB24AsGrayCpp(int startInd)
- {
- GCHandle hObjectSrc = GCHandle.Alloc(_resizedImage.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataSrc = hObjectSrc.AddrOfPinnedObject();
- StructImageInfo srcImgInfo = new StructImageInfo
- {
- width = _resizedImage.Width,
- height = _resizedImage.Height,
- channel = _resizedImage.Channel,
- pData = pDataSrc,
- };
- GCHandle hObjectDst = GCHandle.Alloc(_dataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- pDataDst = IntPtr.Add(pDataDst, startInd * sizeof(float));
- StructExtractInfo extractInfo = new StructExtractInfo
- {
- meanValueType = (int)_meanValueType,
- meanR = _meanR,
- meanG = _meanG,
- meanB = _meanB,
- scaleValueType = (int)_scaleValueType,
- scaleR = _scaleR,
- scaleG = _scaleG,
- scaleB = _scaleB,
- normalizationType = (int)_normalizationType,
- reverseInputChannels = _reverseInputChannels,
- axisOrder = (int)_axisOrder,
- };
- var ret = ExtractRGB24AsGray(srcImgInfo, pDataDst, extractInfo);
- if (hObjectSrc.IsAllocated)
- {
- hObjectSrc.Free();
- }
- if (hObjectDst.IsAllocated)
- {
- hObjectDst.Free();
- }
- if (ret != 0)
- {
- throw new Exception("Failed at calling cpp func: ExtractRGB24AsGray.(error code: " + ret + ").");
- }
- }
- /// <summary>
- /// 将原始图像转成三维数组
- /// 根据axisOrder决定到底是CHW还是HWC的数据排列顺序
- /// (如果需要做减均值和Scale等操作,也在这一步完成)
- /// </summary>
- public void ExtractRGB24AsColor(int startInd)
- {
- // 计算均值
- float meanR, meanG, meanB, meanImg;
- if (_meanValueType == EnumMeanValueType.CalcMeanImage || _meanValueType == EnumMeanValueType.CalcMeanPerChannel)
- {
- CalcMean(out meanR, out meanG, out meanB, out meanImg);
- }
- else
- {
- meanR = _meanR;
- meanG = _meanG;
- meanB = _meanB;
- meanImg = PixelRGBToGray(meanR, meanG, meanB);
- }
- // 计算方差
- float stdR, stdG, stdB, stdImg;
- if (_scaleValueType == EnumScaleValueType.CalcStdImage || _scaleValueType == EnumScaleValueType.CalcStdPerChannel)
- {
- CalcStd(meanR, meanG, meanB, meanImg, out stdR, out stdG, out stdB, out stdImg);
- }
- else
- {
- stdR = _scaleR;
- stdG = _scaleG;
- stdB = _scaleB;
- stdImg = PixelRGBToGray(stdR, stdG, stdB);
- }
- // 计算最大最小值
- float minR = 0, maxR = 0, minG = 0, maxG = 0, minB = 0, maxB = 0, minImg = 0, maxImg = 0;
- if (_normalizationType != EnumNormalizationType.None)
- {
- CalcMinMax(out minR, out maxR, out minG, out maxG, out minB, out maxB, out minImg, out maxImg);
- if (_meanValueType != EnumMeanValueType.None)
- {
- minR -= meanR;
- maxR -= meanR;
- minG -= meanG;
- maxG -= meanG;
- minB -= meanB;
- maxB -= meanB;
- minImg -= meanImg;
- maxImg -= meanImg;
- }
- if (_scaleValueType != EnumScaleValueType.None)
- {
- minR /= stdR;
- maxR /= stdR;
- minG /= stdG;
- maxG /= stdG;
- minB /= stdB;
- maxB /= stdB;
- minImg /= stdImg;
- maxImg /= stdImg;
- }
- }
- // 准备
- float[] meanValues = new float[3];
- if (_meanValueType == EnumMeanValueType.CalcMeanImage)
- {
- meanValues[0] = meanImg;
- meanValues[1] = meanImg;
- meanValues[2] = meanImg;
- }
- else
- {
- meanValues[0] = meanB;
- meanValues[1] = meanG;
- meanValues[2] = meanR;
- }
- float[] scaleValues = new float[3];
- if (_scaleValueType == EnumScaleValueType.CalcStdImage)
- {
- scaleValues[0] = stdImg;
- scaleValues[1] = stdImg;
- scaleValues[2] = stdImg;
- }
- else
- {
- scaleValues[0] = stdB;
- scaleValues[1] = stdG;
- scaleValues[2] = stdR;
- }
- float[] minValues = new float[3];
- float[] maxValues = new float[3];
- if (_normalizationType == EnumNormalizationType.MinMaxScalingImage)
- {
- minValues[0] = minImg;
- minValues[1] = minImg;
- minValues[2] = minImg;
- maxValues[0] = maxImg;
- maxValues[1] = maxImg;
- maxValues[2] = maxImg;
- }
- else
- {
- minValues[0] = minB;
- minValues[1] = minG;
- minValues[2] = minR;
- maxValues[0] = maxB;
- maxValues[1] = maxG;
- maxValues[2] = maxR;
- }
- // 进行处理
- byte[] resizedImageDataBuffer = _resizedImage.DataBuffer;
- int resizedImageHeight = _resizedImage.Height;
- int resizedImageWidth = _resizedImage.Width;
- int resizedImageSize = resizedImageHeight * resizedImageWidth;
- for (int c = 0; c < 3; c++)
- {
- for (int h = 0; h < resizedImageHeight; h++)
- {
- int hIndexOffset = resizedImageWidth * h;
- for (int w = 0; w < resizedImageWidth; w++)
- {
- var srcIndex = resizedImageWidth * 3 * h + 3 * w + c;
- float gray = resizedImageDataBuffer[srcIndex];
- if (_meanValueType != EnumMeanValueType.None)
- {
- gray = gray - meanValues[c];
- }
- if (_scaleValueType != EnumScaleValueType.None)
- {
- gray = gray / scaleValues[c];
- }
- if (_normalizationType != EnumNormalizationType.None)
- {
- gray = (gray - minValues[c]) / (maxValues[c] - minValues[c]);
- }
- int dstIndex = 0;
- switch (_axisOrder)
- {
- case EnumAxisOrder.CHW:
- if (_reverseInputChannels)
- {
- // 为真,则输出需要是BGR, 正好和Bitmap中一致
- dstIndex = resizedImageSize * c + hIndexOffset + w;
- }
- else
- {
- // 为假,则输出需要是RGB, 则需要转换一下 c' = (2-c)
- dstIndex = resizedImageSize * (2 - c) + hIndexOffset + w;
- }
- break;
- case EnumAxisOrder.HWC:
- if (_reverseInputChannels)
- {
- // 为真,则输出需要时BGR, 正好和Bitmap中一致
- dstIndex = hIndexOffset * 3 + 3 * w + c;
- }
- else
- {
- // 为假,则输出需要是RGB,则需要转换一下,c'= 2-c
- dstIndex = hIndexOffset * 3 + 3 * w + (2 - c);
- }
- break;
- }
- dstIndex += startInd;
- _dataBuffer[dstIndex] = gray;
- }
- }
- }
- }
- /// <summary>
- /// 将原始图像转成三维数组(用cpp dll中提供的函数)
- /// 根据axisOrder决定到底是CHW还是HWC的数据排列顺序
- /// (如果需要做减均值和Scale等操作,也在这一步完成)
- /// </summary>
- public void ExtractRGB24AsColorCpp(int startInd)
- {
- GCHandle hObjectSrc = GCHandle.Alloc(_resizedImage.DataBuffer, GCHandleType.Pinned);
- IntPtr pDataSrc = hObjectSrc.AddrOfPinnedObject();
- StructImageInfo srcImgInfo = new StructImageInfo
- {
- width = _resizedImage.Width,
- height = _resizedImage.Height,
- channel = _resizedImage.Channel,
- pData = pDataSrc,
- };
- GCHandle hObjectDst = GCHandle.Alloc(_dataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- pDataDst = IntPtr.Add(pDataDst, startInd * sizeof(float));
- StructExtractInfo extractInfo = new StructExtractInfo
- {
- meanValueType = (int)_meanValueType,
- meanR = _meanR,
- meanG = _meanG,
- meanB = _meanB,
- scaleValueType = (int)_scaleValueType,
- scaleR = _scaleR,
- scaleG = _scaleG,
- scaleB = _scaleB,
- normalizationType = (int)_normalizationType,
- reverseInputChannels = _reverseInputChannels,
- axisOrder = (int)_axisOrder,
- };
- var ret = ExtractRGB24AsColor(srcImgInfo, pDataDst, extractInfo);
- if (hObjectSrc.IsAllocated)
- {
- hObjectSrc.Free();
- }
- if (hObjectDst.IsAllocated)
- {
- hObjectDst.Free();
- }
- if (ret != 0)
- {
- throw new Exception("Failed at calling cpp func: ExtractRGB24AsColor.(error code: " + ret + ").");
- }
- }
- /// <summary>
- /// 计算均值
- /// </summary>
- /// <param name="meanR"></param>
- /// <param name="meanG"></param>
- /// <param name="meanB"></param>
- /// <param name="meanImg"></param>
- private void CalcMean(out float meanR, out float meanG, out float meanB, out float meanImg)
- {
- meanR = 0;
- meanG = 0;
- meanB = 0;
- int imgSize = _resizedImage.Width * _resizedImage.Height;
- byte[] resizedImageDataBuffer = _resizedImage.DataBuffer;
- for (int ni = 0; ni < imgSize; ni++)
- {
- int offset = 3 * ni;
- meanB += resizedImageDataBuffer[offset];
- meanG += resizedImageDataBuffer[offset + 1];
- meanR += resizedImageDataBuffer[offset + 2];
- }
- meanR /= imgSize;
- meanG /= imgSize;
- meanB /= imgSize;
- meanImg = PixelRGBToGray(meanR, meanG, meanB);
- }
- /// <summary>
- /// 计算方差
- /// </summary>
- /// <param name="stdR"></param>
- /// <param name="stdG"></param>
- /// <param name="stdB"></param>
- /// <param name="stdImg"></param>
- private void CalcStd(float meanR, float meanG, float meanB, float meanImg,
- out float stdR, out float stdG, out float stdB, out float stdImg)
- {
- double sumOfSquareR = 0;
- double sumOfSquareG = 0;
- double sumOfSquareB = 0;
- double sumOfSquareImg = 0;
- int imgSize = _resizedImage.Width * _resizedImage.Height;
- byte[] resizedImageDataBuffer = _resizedImage.DataBuffer;
- for (int ni = 0; ni < imgSize; ni++)
- {
- int offset = 3 * ni;
- byte b = resizedImageDataBuffer[offset];
- byte g = resizedImageDataBuffer[offset + 1];
- byte r = resizedImageDataBuffer[offset + 2];
- sumOfSquareB += Math.Pow(b - meanB, 2);
- sumOfSquareG += Math.Pow(g - meanG, 2);
- sumOfSquareR += Math.Pow(r - meanR, 2);
- sumOfSquareImg += (Math.Pow(r - meanImg, 2) + Math.Pow(g - meanImg, 2) + Math.Pow(b - meanImg, 2));
- }
- stdR = (float)Math.Sqrt(sumOfSquareR / imgSize);
- stdG = (float)Math.Sqrt(sumOfSquareG / imgSize);
- stdB = (float)Math.Sqrt(sumOfSquareB / imgSize);
- stdImg = (float)Math.Sqrt(sumOfSquareImg / (imgSize * 3));
- }
- /// <summary>
- /// 计算最大最小值
- /// </summary>
- /// <param name="minR"></param>
- /// <param name="maxR"></param>
- /// <param name="minG"></param>
- /// <param name="maxG"></param>
- /// <param name="minB"></param>
- /// <param name="maxB"></param>
- /// <param name="minImg"></param>
- /// <param name="maxImg"></param>
- private void CalcMinMax(out float minR, out float maxR, out float minG, out float maxG,
- out float minB, out float maxB, out float minImg, out float maxImg)
- {
- minR = float.MaxValue;
- minG = float.MaxValue;
- minB = float.MaxValue;
- maxR = float.MinValue;
- maxG = float.MinValue;
- maxB = float.MinValue;
- int imgSize = _resizedImage.Width * _resizedImage.Height;
- byte[] resizedImageDataBuffer = _resizedImage.DataBuffer;
- for (int ni = 0; ni < imgSize; ni++)
- {
- int offset = 3 * ni;
- byte b = resizedImageDataBuffer[offset];
- byte g = resizedImageDataBuffer[offset + 1];
- byte r = resizedImageDataBuffer[offset + 2];
- if (r < minR)
- {
- minR = r;
- }
- if (r > maxR)
- {
- maxR = r;
- }
- if (g < minG)
- {
- minG = g;
- }
- if (g > maxG)
- {
- maxG = g;
- }
- if (b < minB)
- {
- minB = b;
- }
- if (b > maxB)
- {
- maxB = b;
- }
- }
- minImg = resizedImageDataBuffer.Min();
- maxImg = resizedImageDataBuffer.Max();
- }
- /// <summary>
- /// 将单个像素的RGB值转换为灰度值
- /// </summary>
- /// <param name="Rvalue"></param>
- /// <param name="Gvalue"></param>
- /// <param name="Bvalue"></param>
- /// <returns></returns>
- private float PixelRGBToGray(float Rvalue, float Gvalue, float Bvalue)
- {
- return (float)0.299 * Rvalue + (float)0.587 * Gvalue + (float)0.114 * Bvalue;
- }
- #endregion
- }
- }
|