/// <summary> /// 拷贝该非托管图片 /// </summary> /// <param name="destImage">将非托管图片拷贝至的目标图片位置</param> /// <remarks><para>The method copies current unmanaged image to the specified image. /// Size and pixel format of the destination image must be exactly the same.</para></remarks> /// <exception cref="InvalidImagePropertiesException">Destination image has different size or pixel format.</exception> public void Copy(UnmanagedImage destImage) { if ( (width != destImage.width) || (height != destImage.height) || (pixelFormat != destImage.pixelFormat)) { throw new InvalidImagePropertiesException("Destination image has different size or pixel format."); } if (stride == destImage.stride) { // copy entire image UnmanagedMemoryHelper.CopyUnmanagedMemory(destImage.imageData, imageData, stride * height); } else { unsafe { int dstStride = destImage.stride; int copyLength = (stride < dstStride) ? stride : dstStride; byte *src = (byte *)imageData.ToPointer(); byte *dst = (byte *)destImage.imageData.ToPointer(); // copy line by line for (int i = 0; i < height; i++) { UnmanagedMemoryHelper.CopyUnmanagedMemory(dst, src, copyLength); dst += dstStride; src += stride; } } } }
/// <summary> /// 从指定的托管内存图片转换成非托管内存图片 /// </summary> /// <param name="imageData">锁定的托管内存图片</param> /// <returns>Returns new unmanaged image, which is a copy of source managed image.</returns> /// <remarks><para>The method creates an exact copy of specified managed image, but allocated /// in unmanaged memory. This means that managed image may be unlocked right after call to this /// method.</para></remarks> /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of source image.</exception> public static UnmanagedImage FromManagedImage(BitmapData imageData) { PixelFormat pixelFormat = imageData.PixelFormat; // check source pixel format if ( (pixelFormat != PixelFormat.Format8bppIndexed) && (pixelFormat != PixelFormat.Format16bppGrayScale) && (pixelFormat != PixelFormat.Format24bppRgb) && (pixelFormat != PixelFormat.Format32bppRgb) && (pixelFormat != PixelFormat.Format32bppArgb) && (pixelFormat != PixelFormat.Format32bppPArgb) && (pixelFormat != PixelFormat.Format48bppRgb) && (pixelFormat != PixelFormat.Format64bppArgb) && (pixelFormat != PixelFormat.Format64bppPArgb)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source image."); } // allocate memory for the image IntPtr dstImageData = System.Runtime.InteropServices.Marshal.AllocHGlobal(imageData.Stride * imageData.Height); UnmanagedImage image = new UnmanagedImage(dstImageData, imageData.Width, imageData.Height, imageData.Stride, pixelFormat); UnmanagedMemoryHelper.CopyUnmanagedMemory(dstImageData, imageData.Scan0, imageData.Stride * imageData.Height); image.mustBeDisposed = true; return(image); }
/// <summary> /// Apply filter to an unmanaged image or its part. /// </summary> /// /// <param name="image">Unmanaged image to apply filter to.</param> /// <param name="rect">Image rectangle for processing by the filter.</param> /// /// <remarks>The method applies the filter directly to the provided source image.</remarks> /// /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception> /// public void ApplyInPlace(UnmanagedImage image, Rectangle rect) { // check pixel format of the source image CheckSourceFormat(image.PixelFormat); // validate rectangle rect.Intersect(new Rectangle(0, 0, image.Width, image.Height)); // process the filter if rectangle is not empty if ((rect.Width | rect.Height) != 0) { // create a copy of the source image int size = image.Stride * image.Height; IntPtr imageCopy = MemoryManager.Alloc(size); UnmanagedMemoryHelper.CopyUnmanagedMemory(imageCopy, image.ImageData, size); // process the filter ProcessFilter( new UnmanagedImage(imageCopy, image.Width, image.Height, image.Stride, image.PixelFormat), image, rect); MemoryManager.Free(imageCopy); } }
/// <summary> /// 将非托管图片转换成托管图片 /// </summary> /// <param name="makeCopy">是否拷贝一份新的非托管内存</param> /// <returns>Returns managed copy of the unmanaged image.</returns> /// <remarks><para>If the <paramref name="makeCopy"/> is set to <see langword="true"/>, then the method /// creates a managed copy of the unmanaged image, so the managed image stays valid even when the unmanaged /// image gets disposed. However, setting this parameter to <see langword="false"/> creates a managed image which is /// just a wrapper around the unmanaged image. So if unmanaged image is disposed, the /// managed image becomes no longer valid and accessing it will generate an exception.</para></remarks> public Bitmap ToManagedImage(bool makeCopy) { Bitmap dstImage = null; if (!makeCopy) { dstImage = new Bitmap(width, height, stride, pixelFormat, imageData); if (pixelFormat == PixelFormat.Format8bppIndexed) { Gimela.Media.Imaging.ImageHelper.SetGrayscalePalette(dstImage); } } else { // create new image of required format dstImage = (pixelFormat == PixelFormat.Format8bppIndexed) ? Gimela.Media.Imaging.ImageHelper.CreateGrayscaleImage(width, height) : new Bitmap(width, height, pixelFormat); // lock destination bitmap data BitmapData dstData = dstImage.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, pixelFormat); int dstStride = dstData.Stride; int lineSize = Math.Min(stride, dstStride); unsafe { byte *dst = (byte *)dstData.Scan0.ToPointer(); byte *src = (byte *)imageData.ToPointer(); if (stride != dstStride) { // copy image for (int y = 0; y < height; y++) { UnmanagedMemoryHelper.CopyUnmanagedMemory(dst, src, lineSize); dst += dstStride; src += stride; } } else { UnmanagedMemoryHelper.CopyUnmanagedMemory(dst, src, stride * height); } } // unlock destination images dstImage.UnlockBits(dstData); } return(dstImage); }
private void InitFromRawPointer(IntPtr rawObjectPtr, bool addRef) { if (!UnmanagedMemoryHelper.ValidateComObject(rawObjectPtr)) { throw new ArgumentException("Expected COM object, but validation failed."); } _typeLibPointer = ComPointer <ITypeLibInternal> .GetObject(rawObjectPtr, addRef); InitCommon(); }
/// <summary> /// 克隆该非托管图片 /// </summary> /// <returns>Returns clone of the unmanaged image.</returns> /// <remarks><para>The method does complete cloning of the object.</para></remarks> public UnmanagedImage Clone() { // allocate memory for the image IntPtr newImageData = System.Runtime.InteropServices.Marshal.AllocHGlobal(stride * height); UnmanagedImage newImage = new UnmanagedImage(newImageData, width, height, stride, pixelFormat); newImage.mustBeDisposed = true; UnmanagedMemoryHelper.CopyUnmanagedMemory(newImageData, imageData, stride * height); return(newImage); }
public void Parse(string fileName) { // FbxObject (root) // |`-- "Objects" // |`-- ... |`-- "Geometry" // |`-- ... |`-- ... |`-- "Vertices" { [0]: double[], ... } // `-- ... |`-- ... |`-- "PolygonVertexIndex" { [0]: int[], ... } // `-- ... |`-- "LayerElementNormal" // |`-- ... |`-- "Normals" { [0]: double[], ... } // `-- ... |`-- ... // `-- ... var Objects = "Objects".ToASCII(); var Geometry = "Geometry".ToASCII(); var Vertices = "Vertices".ToASCII(); var PolygonVertexIndex = "PolygonVertexIndex".ToASCII(); var LayerElementNormal = "LayerElementNormal".ToASCII(); var Normals = "Normals".ToASCII(); UnmanagedMemoryHelper.Initialize(); using (var stream = File.OpenRead(fileName)) using (var fbx = FbxParser.Parse(stream)) { Assert.True(fbx.Nodes.Count > 0); var positions = fbx.Find(Objects) .Find(Geometry) .Find(Vertices) .Properties[0].AsDoubleArray(); var indices = fbx.Find(Objects) .Find(Geometry) .Find(PolygonVertexIndex) .Properties[0].AsInt32Array(); var normals = fbx.Find(Objects) .Find(Geometry) .Find(LayerElementNormal) .Find(Normals) .Properties[0].AsDoubleArray(); Assert.True(positions.Length > 0); Assert.True(indices.Length > 0); Assert.True(normals.Length > 0); } UnmanagedMemoryHelper.AssertResourceReleased(); }
/// <summary> /// Clone image. /// </summary> /// /// <param name="sourceData">Source image data.</param> /// /// <returns>Clones image from source image data. The message does not clone pallete in the /// case if the source image has indexed pixel format.</returns> /// public static Bitmap Clone(BitmapData sourceData) { // get source image size int width = sourceData.Width; int height = sourceData.Height; // create new image Bitmap destination = new Bitmap(width, height, sourceData.PixelFormat); // lock destination bitmap data BitmapData destinationData = destination.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, destination.PixelFormat); UnmanagedMemoryHelper.CopyUnmanagedMemory(destinationData.Scan0, sourceData.Scan0, height * sourceData.Stride); // unlock destination image destination.UnlockBits(destinationData); return(destination); }
// Create motion zones' image private unsafe void CreateMotionZonesFrame() { lock (sync) { // free previous motion zones frame if (zonesFrame != null) { zonesFrame.Dispose(); zonesFrame = null; } // create motion zones frame only in the case if the algorithm has processed at least one frame if ((motionZones != null) && (motionZones.Length != 0) && (videoWidth != 0)) { zonesFrame = UnmanagedImage.Create(videoWidth, videoHeight, PixelFormat.Format8bppIndexed); Rectangle imageRect = new Rectangle(0, 0, videoWidth, videoHeight); // draw all motion zones on motion frame foreach (Rectangle rect in motionZones) { rect.Intersect(imageRect); // rectangle's dimenstion int rectWidth = rect.Width; int rectHeight = rect.Height; // start pointer int stride = zonesFrame.Stride; byte *ptr = (byte *)zonesFrame.ImageData.ToPointer() + rect.Y * stride + rect.X; for (int y = 0; y < rectHeight; y++) { UnmanagedMemoryHelper.SetUnmanagedMemory(ptr, 255, rectWidth); ptr += stride; } } } } }
private void InitFromRawPointer(IntPtr rawObjectPtr, bool addRef) { if (!UnmanagedMemoryHelper.ValidateComObject(rawObjectPtr)) { throw new ArgumentException("Expected COM object, but validation failed."); } // We have to restrict interface requests to VBE hosted ITypeInfos due to a bug in their implementation. // See TypeInfoWrapper class XML doc for details. // VBE provides two implementations of ITypeInfo for each component. Both versions have different quirks and limitations. // We use both versions to try to expose a more complete/accurate version of ITypeInfo. _typeInfoPointer = ComPointer <ITypeInfoInternal> .GetObjectViaAggregation(rawObjectPtr, addRef, queryType : false); _typeInfoAlternatePointer = ComPointer <ITypeInfoInternal> .GetObjectViaAggregation(rawObjectPtr, addRef, queryType : true); // safely test whether the provided ITypeInfo is hosted by the VBE, and thus exposes the VBE extensions HasVBEExtensions = ComHelper.DoesComObjPtrSupportInterface <IVBEComponent>(rawObjectPtr); InitCommon(); DetectUserFormClass(); }
/// <summary> /// 为新的图片创建非托管内存 /// </summary> /// <param name="width">Image width.</param> /// <param name="height">Image height.</param> /// <param name="pixelFormat">Image pixel format.</param> /// <returns>Return image allocated in unmanaged memory.</returns> /// <remarks><para>Allocate new image with specified attributes in unmanaged memory.</para> /// <para><note>The method supports only /// <see cref="System.Drawing.Imaging.PixelFormat">Format8bppIndexed</see>, /// <see cref="System.Drawing.Imaging.PixelFormat">Format16bppGrayScale</see>, /// <see cref="System.Drawing.Imaging.PixelFormat">Format24bppRgb</see>, /// <see cref="System.Drawing.Imaging.PixelFormat">Format32bppRgb</see>, /// <see cref="System.Drawing.Imaging.PixelFormat">Format32bppArgb</see>, /// <see cref="System.Drawing.Imaging.PixelFormat">Format32bppPArgb</see>, /// <see cref="System.Drawing.Imaging.PixelFormat">Format48bppRgb</see>, /// <see cref="System.Drawing.Imaging.PixelFormat">Format64bppArgb</see> and /// <see cref="System.Drawing.Imaging.PixelFormat">Format64bppPArgb</see> pixel formats. /// In the case if <see cref="System.Drawing.Imaging.PixelFormat">Format8bppIndexed</see> /// format is specified, pallete is not not created for the image (supposed that it is /// 8 bpp grayscale image). /// </note></para> /// </remarks> /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format was specified.</exception> /// <exception cref="InvalidImagePropertiesException">Invalid image size was specified.</exception> public static UnmanagedImage Create(int width, int height, PixelFormat pixelFormat) { int bytesPerPixel = 0; // calculate bytes per pixel switch (pixelFormat) { case PixelFormat.Format8bppIndexed: bytesPerPixel = 1; break; case PixelFormat.Format16bppGrayScale: bytesPerPixel = 2; break; case PixelFormat.Format24bppRgb: bytesPerPixel = 3; break; case PixelFormat.Format32bppRgb: case PixelFormat.Format32bppArgb: case PixelFormat.Format32bppPArgb: bytesPerPixel = 4; break; case PixelFormat.Format48bppRgb: bytesPerPixel = 6; break; case PixelFormat.Format64bppArgb: case PixelFormat.Format64bppPArgb: bytesPerPixel = 8; break; default: throw new UnsupportedImageFormatException("Can not create image with specified pixel format."); } // check image size if ((width <= 0) || (height <= 0)) { throw new InvalidImagePropertiesException("Invalid image size specified."); } // calculate stride int stride = width * bytesPerPixel; if (stride % 4 != 0) { stride += (4 - (stride % 4)); } // allocate memory for the image IntPtr imageData = System.Runtime.InteropServices.Marshal.AllocHGlobal(stride * height); UnmanagedMemoryHelper.SetUnmanagedMemory(imageData, 0, stride * height); UnmanagedImage image = new UnmanagedImage(imageData, width, height, stride, pixelFormat); image.mustBeDisposed = true; return(image); }
/// <summary> /// Process new video frame. /// </summary> /// /// <param name="videoFrame">Video frame to process (detect motion in).</param> /// /// <remarks><para>Processes new frame from video source and detects motion in it.</para> /// /// <para>Check <see cref="MotionLevel"/> property to get information about amount of motion /// (changes) in the processed frame.</para> /// </remarks> /// public unsafe void ProcessFrame(UnmanagedImage videoFrame) { lock (sync) { // check background frame if (backgroundFrame == null) { // save image dimension width = videoFrame.Width; height = videoFrame.Height; // alocate memory for background frame backgroundFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); frameSize = backgroundFrame.Stride * height; // convert source frame to grayscale Grayscale.CommonAlgorithms.BT709.Apply(videoFrame, backgroundFrame); return; } // check image dimension if ((videoFrame.Width != width) || (videoFrame.Height != height)) { return; } // check motion frame if (motionFrame == null) { motionFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); // temporary buffer if (suppressNoise) { tempFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); } } // convert current image to grayscale Grayscale.CommonAlgorithms.BT709.Apply(videoFrame, motionFrame); // pointers to background and current frames byte *backFrame; byte *currFrame; int diff; backFrame = (byte *)backgroundFrame.ImageData.ToPointer(); currFrame = (byte *)motionFrame.ImageData.ToPointer(); // 1 - get difference between frames // 2 - threshold the difference for (int i = 0; i < frameSize; i++, backFrame++, currFrame++) { // difference diff = (int)*currFrame - (int)*backFrame; // treshold *currFrame = ((diff >= differenceThreshold) || (diff <= differenceThresholdNeg)) ? (byte)255 : (byte)0; } if (suppressNoise) { // suppress noise and calculate motion amount UnmanagedMemoryHelper.CopyUnmanagedMemory(tempFrame.ImageData, motionFrame.ImageData, frameSize); erosionFilter.Apply(tempFrame, motionFrame); if (keepObjectEdges) { UnmanagedMemoryHelper.CopyUnmanagedMemory(tempFrame.ImageData, motionFrame.ImageData, frameSize); dilatationFilter.Apply(tempFrame, motionFrame); } } // calculate amount of motion pixels pixelsChanged = 0; byte *motion = (byte *)motionFrame.ImageData.ToPointer(); for (int i = 0; i < frameSize; i++, motion++) { pixelsChanged += (*motion & 1); } } }
/// <summary> /// Process new video frame. /// </summary> /// /// <param name="videoFrame">Video frame to process (detect motion in).</param> /// /// <remarks><para>Processes new frame from video source and detects motion in it.</para> /// /// <para>Check <see cref="MotionLevel"/> property to get information about amount of motion /// (changes) in the processed frame.</para> /// </remarks> /// public unsafe void ProcessFrame(UnmanagedImage videoFrame) { lock (sync) { // check background frame if (backgroundFrame == null) { lastTimeMeasurment = DateTime.Now; // save image dimension width = videoFrame.Width; height = videoFrame.Height; // alocate memory for previous and current frames backgroundFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); motionFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); frameSize = motionFrame.Stride * height; // temporary buffer if (suppressNoise) { tempFrame = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed); } // convert source frame to grayscale Grayscale.CommonAlgorithms.BT709.Apply(videoFrame, backgroundFrame); return; } // check image dimension if ((videoFrame.Width != width) || (videoFrame.Height != height)) { return; } // convert current image to grayscale Grayscale.CommonAlgorithms.BT709.Apply(videoFrame, motionFrame); // pointers to background and current frames byte *backFrame; byte *currFrame; int diff; // update background frame if (millisecondsPerBackgroundUpdate == 0) { // update background frame using frame counter as a base if (++framesCounter == framesPerBackgroundUpdate) { framesCounter = 0; backFrame = (byte *)backgroundFrame.ImageData.ToPointer(); currFrame = (byte *)motionFrame.ImageData.ToPointer(); for (int i = 0; i < frameSize; i++, backFrame++, currFrame++) { diff = *currFrame - *backFrame; if (diff > 0) { (*backFrame)++; } else if (diff < 0) { (*backFrame)--; } } } } else { // update background frame using timer as a base // get current time and calculate difference DateTime currentTime = DateTime.Now; TimeSpan timeDff = currentTime - lastTimeMeasurment; // save current time as the last measurment lastTimeMeasurment = currentTime; int millisonds = (int)timeDff.TotalMilliseconds + millisecondsLeftUnprocessed; // save remainder so it could be taken into account in the future millisecondsLeftUnprocessed = millisonds % millisecondsPerBackgroundUpdate; // get amount for background update int updateAmount = (int)(millisonds / millisecondsPerBackgroundUpdate); backFrame = (byte *)backgroundFrame.ImageData.ToPointer(); currFrame = (byte *)motionFrame.ImageData.ToPointer(); for (int i = 0; i < frameSize; i++, backFrame++, currFrame++) { diff = *currFrame - *backFrame; if (diff > 0) { (*backFrame) += (byte)((diff < updateAmount) ? diff : updateAmount); } else if (diff < 0) { (*backFrame) += (byte)((-diff < updateAmount) ? diff : -updateAmount); } } } backFrame = (byte *)backgroundFrame.ImageData.ToPointer(); currFrame = (byte *)motionFrame.ImageData.ToPointer(); // 1 - get difference between frames // 2 - threshold the difference for (int i = 0; i < frameSize; i++, backFrame++, currFrame++) { // difference diff = (int)*currFrame - (int)*backFrame; // treshold *currFrame = ((diff >= differenceThreshold) || (diff <= differenceThresholdNeg)) ? (byte)255 : (byte)0; } if (suppressNoise) { // suppress noise and calculate motion amount UnmanagedMemoryHelper.CopyUnmanagedMemory(tempFrame.ImageData, motionFrame.ImageData, frameSize); erosionFilter.Apply(tempFrame, motionFrame); if (keepObjectEdges) { UnmanagedMemoryHelper.CopyUnmanagedMemory(tempFrame.ImageData, motionFrame.ImageData, frameSize); dilatationFilter.Apply(tempFrame, motionFrame); } } // calculate amount of motion pixels pixelsChanged = 0; byte *motion = (byte *)motionFrame.ImageData.ToPointer(); for (int i = 0; i < frameSize; i++, motion++) { pixelsChanged += (*motion & 1); } } }
/// <summary> /// Fill rectangle on the specified image. /// </summary> /// /// <param name="image">Source image to draw on.</param> /// <param name="rectangle">Rectangle's coordinates to fill.</param> /// <param name="color">Rectangle's color.</param> /// /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception> /// public static unsafe void FillRectangle(UnmanagedImage image, Rectangle rectangle, Color color) { CheckPixelFormat(image.PixelFormat); int pixelSize = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8; // image dimension int imageWidth = image.Width; int imageHeight = image.Height; int stride = image.Stride; // rectangle dimension and position int rectX1 = rectangle.X; int rectY1 = rectangle.Y; int rectX2 = rectangle.X + rectangle.Width - 1; int rectY2 = rectangle.Y + rectangle.Height - 1; // check if rectangle is in the image if ((rectX1 >= imageWidth) || (rectY1 >= imageHeight) || (rectX2 < 0) || (rectY2 < 0)) { // nothing to draw return; } int startX = Math.Max(0, rectX1); int stopX = Math.Min(imageWidth - 1, rectX2); int startY = Math.Max(0, rectY1); int stopY = Math.Min(imageHeight - 1, rectY2); // do the job byte *ptr = (byte *)image.ImageData.ToPointer() + startY * stride + startX * pixelSize; if (image.PixelFormat == PixelFormat.Format8bppIndexed) { // grayscale image byte gray = (byte)(0.2125 * color.R + 0.7154 * color.G + 0.0721 * color.B); int fillWidth = stopX - startX + 1; for (int y = startY; y <= stopY; y++) { UnmanagedMemoryHelper.SetUnmanagedMemory(ptr, gray, fillWidth); ptr += stride; } } else { // color image byte red = color.R; byte green = color.G; byte blue = color.B; int offset = stride - (stopX - startX + 1) * pixelSize; for (int y = startY; y <= stopY; y++) { for (int x = startX; x <= stopX; x++, ptr += pixelSize) { ptr[RGB.R] = red; ptr[RGB.G] = green; ptr[RGB.B] = blue; } ptr += offset; } } }