123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- using System;
- using System.Runtime.InteropServices;
- namespace YOLODetectProcessLib
- {
- /// <summary>
- /// cpp dll 中图像信息的数据结构
- /// </summary>
- public struct StructImageInfo
- {
- public int width;
- public int height;
- public int channel;
- public IntPtr pData;
- }
- /// <summary>
- /// cpp dll 中矩形框的数据结构
- /// </summary>
- public struct StructMyRect
- {
- public int left;
- public int top;
- public int width;
- public int height;
- }
- /// <summary>
- /// cpp dll 中提取前处理数据时所需信息的数据结构
- /// </summary>
- 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;
- }
- /// <summary>
- /// 图像处理过程中的一些辅助的功能函数
- /// </summary>
- public class ImageUtils
- {
- #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 = "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 public
- public static IImage ResizeBilinearWithCpp(IImage 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, dstWidth * 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 static void FillPadValWithCpp(IImage 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.(error code: " + ret + ").");
- }
- }
- public static IImage CropRectWithCpp(IImage image, Rect 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, cropRect.Width * 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.(error code: " + ret + ").");
- }
- return dstImage;
- }
- public static void CropRectWithCpp(IImage image, Rect cropRect, ref byte[] dstImgDataBuffer)
- {
- // 目标图像数据区尺寸是否需要改变?
- int dstChannel = image.Channel;
- int dstWidth = cropRect.Width;
- int dstHeight = cropRect.Height;
- int dstDataLen = dstWidth * dstHeight * dstChannel;
- if (dstImgDataBuffer.Length < dstDataLen)
- {
- Array.Resize(ref dstImgDataBuffer, dstDataLen);
- }
- 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 hObjectDst = GCHandle.Alloc(dstImgDataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- StructImageInfo dstImgInfo = new StructImageInfo
- {
- width = dstWidth,
- height = dstHeight,
- channel = dstChannel,
- 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.(error code: " + ret + ").");
- }
- return;
- }
- public static void PasteRectWithCpp(IImage dstImg, IImage srcImg, Rect 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.(error code: " + ret + ").");
- }
- }
- public static IImage ResizeBilinear(IImage image, int dstWidth, int dstHeight)
- {
- byte[] dstDataBuffer = new byte[dstWidth * dstHeight * image.Channel];
- ResizeBilinear(image, dstWidth, dstHeight, ref dstDataBuffer);
- return new RawImage(dstDataBuffer, dstWidth, dstHeight, image.Channel, dstWidth * image.Channel);
- }
- public static void FillPadVal(IImage image, byte[] padValue)
- {
- if (padValue == null)
- {
- throw new ArgumentNullException("padValue");
- }
- int channel = image.Channel;
- byte[] dataBuffer = image.DataBuffer;
- if (padValue.Length != channel)
- {
- throw new ArgumentException("padValue", "Length of the padValue should equal to Channel.");
- }
- if (dataBuffer == null)
- {
- throw new ArgumentNullException("image.DataBuffer");
- }
- int imageSize = image.Width * image.Height;
- for (int ni = 0; ni < imageSize; ni++)
- {
- Buffer.BlockCopy(padValue, 0, dataBuffer, ni * channel, channel);
- }
- }
- public static IImage CropRect(IImage image, Rect cropRect)
- {
- byte[] croppedDataBuffer = new byte[cropRect.Width * cropRect.Height * image.Channel];
- CropRect(image, cropRect, ref croppedDataBuffer);
- return new RawImage(croppedDataBuffer, cropRect.Width, cropRect.Height, image.Channel, cropRect.Width * image.Channel);
- }
- public static void PasteRect(IImage dstImg, IImage srcImg, Rect pasteRect)
- {
- int dstRectLeft = pasteRect.Left;
- int dstRectRight = pasteRect.Right;
- int dstRectTop = pasteRect.Top;
- int dstRectBottom = pasteRect.Bottom;
- int dstRectWidth = pasteRect.Width;
- int dstRectHeight = pasteRect.Height;
- int width = dstImg.Width;
- int height = dstImg.Height;
- int channel = dstImg.Channel;
- int stride = dstImg.Stride;
- byte[] dataBuffer = dstImg.DataBuffer;
- if (dstRectLeft < 0 || dstRectLeft > width - 1)
- {
- throw new ArgumentOutOfRangeException("dstRect.Left", "Left of the paste dstRect is out of the image.");
- }
- if (dstRectRight < 0 || dstRectRight > width)
- {
- throw new ArgumentOutOfRangeException("dstRect.Right", "Right of the paste dstRect is out of the image.");
- }
- if (dstRectTop < 0 || dstRectTop > height - 1)
- {
- throw new ArgumentOutOfRangeException("dstRect.Top", "Top of the paste dstRect is out of the image.");
- }
- if (dstRectBottom < 0 || dstRectBottom > height)
- {
- throw new ArgumentOutOfRangeException("dstRect.Bottom", "Right of the paste dstRect is out of the image.");
- }
- if (srcImg == null)
- {
- throw new ArgumentNullException("srcImg");
- }
- if (srcImg.Channel != channel)
- {
- throw new ArgumentException("srcImg.Channel", "The channel of srcImg should be equal to the channel of this image.");
- }
- if (srcImg.Width != dstRectWidth)
- {
- throw new ArgumentException("srcImg.Width", "The Width of srcImg should be equal to the width of the dstRect.");
- }
- if (srcImg.Height != dstRectHeight)
- {
- throw new ArgumentException("srcImg.Height", "The Height of srcImg should be equal to the height of the dstRect.");
- }
- if (dataBuffer == null)
- {
- throw new ArgumentNullException("dstImg.DataBuffer");
- }
- // 如果rect的尺寸就是整幅图的尺寸,就直接整幅图clone即可,不需要一行一行复制
- if (dstRectLeft == 0 && dstRectTop == 0 && dstRectWidth == width && dstRectHeight == height)
- {
- Buffer.BlockCopy(srcImg.DataBuffer, 0, dataBuffer, 0, width * height * channel);
- return;
- }
- byte[] srcImgDataBuffer = srcImg.DataBuffer;
- int rectRowCopyLen = dstRectWidth * channel;
- int rectCopyOffset = dstRectTop * width * channel + dstRectLeft * channel;
- int rowCopyOffset = width * channel;
- for (int nh = 0; nh < dstRectHeight; nh++)
- {
- Buffer.BlockCopy(srcImgDataBuffer, nh * rectRowCopyLen,
- dataBuffer, rectCopyOffset + nh * rowCopyOffset, rectRowCopyLen);
- }
- return;
- }
- public static void ResizeBilinear(IImage image, int dstWidth, int dstHeight, ref byte[] dstDataBuffer)
- {
- int width = image.Width;
- int height = image.Height;
- int channel = image.Channel;
- byte[] dataBuffer = image.DataBuffer;
- int dstDataLen = dstWidth * dstHeight * channel;
- if (dstDataBuffer.Length < dstDataLen)
- {
- Array.Resize(ref dstDataBuffer, dstDataLen);
- }
- float scale_x = (float)width / dstWidth;
- float scale_y = (float)height / dstHeight;
- int dstStep = dstWidth * channel;
- int srcStep = width * channel;
- float fy, fx;
- int sy, sx;
- short[] cbufy = new short[2];
- short[] cbufx = new short[2];
- int nh, nw, nc;
- for (nh = 0; nh < dstHeight; ++nh)
- {
- fy = (float)((nh + 0.5) * scale_y - 0.5);
- sy = Convert.ToInt32(Math.Floor(fy));
- fy -= sy;
- sy = Math.Min(sy, height - 2);
- sy = Math.Max(0, sy);
- cbufy[0] = Convert.ToInt16((1 - fy) * 2048);
- cbufy[1] = Convert.ToInt16(2048 - cbufy[0]);
- for (nw = 0; nw < dstWidth; ++nw)
- {
- fx = (float)((nw + 0.5) * scale_x - 0.5);
- sx = Convert.ToInt16(Math.Floor(fx));
- fx -= sx;
- if (sx < 0)
- {
- fx = 0;
- sx = 0;
- }
- if (sx >= width - 2)
- {
- fx = 0;
- sx = width - 2;
- }
- cbufx[0] = Convert.ToInt16((1 - fx) * 2048);
- cbufx[1] = Convert.ToInt16(2048 - cbufx[0]);
- for (nc = 0; nc < channel; ++nc)
- {
- dstDataBuffer[nh * dstStep + nw * channel + nc] = Convert.ToByte((
- dataBuffer[sy * srcStep + sx * channel + nc] * cbufx[0] * cbufy[0] +
- dataBuffer[(sy + 1) * srcStep + sx * channel + nc] * cbufx[0] * cbufy[1] +
- dataBuffer[sy * srcStep + (sx + 1) * channel + nc] * cbufx[1] * cbufy[0] +
- dataBuffer[(sy + 1) * srcStep + (sx + 1) * channel + nc] * cbufx[1] * cbufy[1]) >> 22);
- }
- }
- }
- }
- public static void ResizeBilinearWithCpp(IImage image, int dstWidth, int dstHeight, ref byte[] dstImgDataBuffer)
- {
- // 目标图像数据区尺寸是否需要改变?
- int dstChannel = image.Channel;
- int dstDataLen = dstWidth * dstHeight * dstChannel;
- if (dstImgDataBuffer.Length < dstDataLen)
- {
- Array.Resize(ref dstImgDataBuffer, dstDataLen);
- }
- 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 hObjectDst = GCHandle.Alloc(dstImgDataBuffer, GCHandleType.Pinned);
- IntPtr pDataDst = hObjectDst.AddrOfPinnedObject();
- StructImageInfo dstImgInfo = new StructImageInfo
- {
- width = dstWidth,
- height = dstHeight,
- channel = dstChannel,
- 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;
- }
- public static void CropRect(IImage image, Rect cropRect, ref byte[] dstDataBuffer)
- {
- if (cropRect.IsEmpty())
- {
- return;
- }
- int rectLeft = cropRect.Left;
- int rectRight = cropRect.Right;
- int rectTop = cropRect.Top;
- int rectBottom = cropRect.Bottom;
- int rectWidth = cropRect.Width;
- int rectHeight = cropRect.Height;
- int width = image.Width;
- int height = image.Height;
- int channel = image.Channel;
- int stride = image.Stride;
- byte[] dataBuffer = image.DataBuffer;
- if (rectLeft < 0 || rectLeft > width - 1)
- {
- throw new ArgumentOutOfRangeException("rect.Left", "Left of the crop rect is out of the image.");
- }
- if (rectRight < 0 || rectRight > width)
- {
- throw new ArgumentOutOfRangeException("rect.Right", "Right of the crop rect is out of the image.");
- }
- if (rectTop < 0 || rectTop > height - 1)
- {
- throw new ArgumentOutOfRangeException("rect.Top", "Top of the crop rect is out of the image.");
- }
- if (rectBottom < 0 || rectBottom > height)
- {
- throw new ArgumentOutOfRangeException("rect.Bottom", "Right of the crop rect is out of the image.");
- }
- // 目标图像的尺寸是否需要改变
- int dstDataLen = rectWidth * rectHeight * channel;
- if (dstDataBuffer.Length < dstDataLen)
- {
- Array.Resize(ref dstDataBuffer, dstDataLen);
- }
- // 如果rect的尺寸就是整幅图的尺寸,就直接整幅图clone即可,不需要一行一行复制
- if (rectLeft == 0 && rectTop == 0 && rectWidth == width && rectHeight == height)
- {
- Buffer.BlockCopy(dataBuffer, 0, dstDataBuffer, 0, image.DataBufferSize);
- }
- int rectRowCopyLen = rectWidth * channel;
- int rectCopyOffset = rectTop * width * channel + rectLeft * channel;
- for (int nh = 0; nh < rectHeight; nh++)
- {
- Buffer.BlockCopy(dataBuffer, rectCopyOffset + nh * stride,
- dstDataBuffer, nh * rectRowCopyLen, rectRowCopyLen);
- }
- }
- #endregion
- }
- }
|