public static unsafe UnmanagedImage GetChannelAsImage(this UnmanagedImage image, RGBA channel) { var c = (short)channel; var pb = image.GetPixelFormatSizeInBytes(); if (c < 0 || c >= pb) { throw new ArgumentOutOfRangeException(nameof(c)); } var wb = pb * image.Width; var pad = image.Stride - wb; var result = UnmanagedImage.Create(image.Width, image.Height, PixelFormat.Format8bppIndexed); var d = (byte *)image.ImageData + c; var e = (byte *)result.ImageData; for (var dT0 = d + (image.Stride * image.Height); d < dT0; d += pad) { for (var dToLine = d + wb; d < dToLine; d += pb, e++) { *e = *d; } } return(result); }
public static unsafe int[] Subtract(this UnmanagedImage image1, [NotNull] UnmanagedImage image2) { ImageCheck.CheckSameSize(image1, image2); var w = image1.Width; var h = image1.Height; var s = image1.Stride; var dt1 = (byte *)image1.ImageData; var dt2 = (byte *)image2.ImageData; var dt1To = dt1 + (h * s); var wb = w * image1.GetPixelFormatSizeInBytes(); var result = new int[wb * h]; var j = 0; for (; dt1 < dt1To; dt1 += s, dt2 += s) { for (var i = 0; i < wb; i++) { result[j++] = dt1[i] - dt2[i]; } } return(result); }
/// <summary> /// Converts a rgb image to an rgba image. /// </summary> /// <param name="image"></param> /// <returns></returns> public static unsafe float[] ToFloats(UnmanagedImage image) { const float alpha = 255; const int pwR = 4; var pwI = image.GetPixelFormatSizeInBytes(); var w = image.Width; var h = image.Height; var s = w * 4; var result = new float[s * h]; var dtI = (byte *)image.ImageData; var wpR = w * pwR; var paddI = image.Stride - (w * pwI); var i = 0; switch (image.PixelFormat) { case PixelFormat.Format32bppRgb: case PixelFormat.Format24bppRgb: for (var dtrTo = h * s; i < dtrTo; dtI += paddI) { for (var dtrLineTo = i + wpR; i < dtrLineTo; dtI += pwI, i += pwR) { result[i + RGB_R_CL] = dtI[RGB_R]; result[i + RGB_G_CL] = dtI[RGB_G]; result[i + RGB_B_CL] = dtI[RGB_B]; result[i + RGB_A_CL] = alpha; } } break; case PixelFormat.Format32bppArgb: for (var dtrTo = h * s; i < dtrTo; dtI += paddI) { for (var dtrLineTo = i + wpR; i < dtrLineTo; dtI += pwI, i += pwR) { result[i + RGB_R_CL] = dtI[RGB_R]; result[i + RGB_G_CL] = dtI[RGB_G]; result[i + RGB_B_CL] = dtI[RGB_B]; result[i + RGB_A_CL] = dtI[RGB_A]; } } break; default: throw new BadImageFormatException(nameof(image)); } return(result); }
private static unsafe void IntegrateImage(UnmanagedImage srcImg, float[] sumData, float xFocus, float yFocus, float norm) { var srcFactorX0 = ((float)Math.Floor(xFocus) + 1) - xFocus; var srcFactorY0 = ((float)Math.Floor(yFocus) + 1) - yFocus; var src00 = srcFactorX0 * srcFactorY0 * norm; var src10 = (1 - srcFactorX0) * srcFactorY0 * norm; var src01 = srcFactorX0 * (1 - srcFactorY0) * norm; var src11 = (1 - srcFactorX0) * (1 - srcFactorY0) * norm; var pixelBytes = srcImg.GetPixelFormatSizeInBytes(); var stride = srcImg.Stride; var d = (byte *)srcImg.ImageData; var desXMin = Math.Max(-(int)Math.Ceiling(xFocus) + 1, 0); var desYMin = Math.Max(-(int)Math.Ceiling(yFocus) + 1, 0); var desXMax = (int)Math.Ceiling(srcImg.Width - Math.Max(xFocus, -1) - 1); var desYMax = (int)Math.Ceiling(srcImg.Height - Math.Max(yFocus, -1) - 1); var desIMin = desXMin * pixelBytes; var desIMax = desXMax * pixelBytes; var srcI = ((int)Math.Floor(yFocus) * stride) + ((int)Math.Floor(xFocus) * pixelBytes); Parallel.For( desYMin, desYMax, Preferences.PoOne, y => { int iEx; var i = (iEx = y * stride) + desIMin; iEx += desIMax; for (; i < iEx; i += pixelBytes) { var srcI0 = i + srcI; var srcI1 = srcI0 + pixelBytes; var srcI2 = srcI0 + stride; var srcI3 = srcI2 + pixelBytes; for (var bit = 0; bit < pixelBytes; bit++) { sumData[i + bit] += (src00 * d[srcI0 + bit]) + (src10 * d[srcI1 + bit]) + (src01 * d[srcI2 + bit]) + (src11 * d[srcI3 + bit]); } } } ); }
private static unsafe void DoRgb2Lab(UnmanagedImage srcImage, UnmanagedImage dstImage) { var pb = srcImage.GetPixelFormatSizeInBytes(); var hasAlpha = pb == 4; var srcPtr = (byte *)srcImage.ImageData; var dstPtr = (byte *)dstImage.ImageData; var line = srcImage.Width * pb; var padd = srcImage.Stride - line; if (hasAlpha) { for (var srcPtrTo = srcPtr + (srcImage.Stride * srcImage.Height); srcPtr < srcPtrTo; srcPtr += padd, dstPtr += padd) { for (var srcLineTo = srcPtr + line; srcPtr < srcLineTo; srcPtr += pb, dstPtr += pb) { Rgb2Lab( srcPtr[RGB_R], srcPtr[RGB_G], srcPtr[RGB_B], out dstPtr[LAB_L], out dstPtr[LAB_A], out dstPtr[LAB_B] ); dstPtr[RGB_A] = srcPtr[RGB_A]; } } } else { for (var srcPtrTo = srcPtr + (srcImage.Stride * srcImage.Height); srcPtr < srcPtrTo; srcPtr += padd, dstPtr += padd) { for (var srcLineTo = srcPtr + line; srcPtr < srcLineTo; srcPtr += pb, dstPtr += pb) { Rgb2Lab( srcPtr[RGB_R], srcPtr[RGB_G], srcPtr[RGB_B], out dstPtr[LAB_L], out dstPtr[LAB_A], out dstPtr[LAB_B] ); } } } }
public static unsafe void CopyFrom(this UnmanagedImage image, float[] src, float factor) { var ptr = (byte *)image.ImageData; var l = image.Width + image.GetPixelFormatSizeInBytes(); var n = Math.Min(l * image.Height, src.Length); var padd = image.Stride - l; for (var i = 0; i < n;) { ptr[i++] = (src[i] * factor).ToBase256(); if (i % l == 0) // shift pointer by it's padding width at the end of line { ptr += padd; } } }
public static void Draw(this UnmanagedImage thisImage, UnmanagedImage srcImage, int x, int y) { if (srcImage.PixelFormat != thisImage.PixelFormat) { throw new InvalidOperationException( "Different image formats: '" + srcImage.PixelFormat + "' and '" + thisImage.PixelFormat + "'." ); } var pixelBytes = srcImage.GetPixelFormatSizeInBytes(); x *= pixelBytes; var sS = srcImage.Stride; var sD = thisImage.Stride; var nSrc = Math.Min(srcImage.Height, thisImage.Height - y) * sS; // bottom clip var srcClipStride = Math.Min( srcImage.Width * pixelBytes, (thisImage.Width * pixelBytes) - x ); // right clip var iSrc = 0; var iDst = x + ((y - 1) * sD); //y-1 because increment before use if (y < 0) { // top clip iSrc -= y * sS; iDst -= y * sD; } if (x < 0) { // left clip srcClipStride += x; iSrc -= x; //nSrc -= x; // TODO: required? iDst -= x; // x = 0 } Debug.Assert(srcClipStride >= 0 && iSrc < nSrc, "There is always a intersect."); var d = srcImage.ImageData; var e = thisImage.ImageData; for (; iSrc < nSrc; iSrc += sS) { MarshalX.Copy(e + (iDst += sD), d + iSrc, srcClipStride); } }
/// <summary> /// Converts a rgb image to an rgba image. /// </summary> /// <param name="data"></param> /// <param name="outImage"></param> /// <returns></returns> public static unsafe void CreateFromFloats(float[] data, UnmanagedImage outImage) { const int pwI = 4; var w = outImage.Width; var h = outImage.Height; var sDt = w * 4; var pwR = outImage.GetPixelFormatSizeInBytes(); var dtR = (byte *)outImage.ImageData; var wpI = w * pwI; var paddR = outImage.Stride - (w * pwR); if (pwR == 4) // apply alpha to? { for (int i = 0, iTo = h * sDt; i < iTo; dtR += paddR) { for (var iToLine = i + wpI; i < iToLine; dtR += pwR, i += pwI) { dtR[RGB_R] = data[i + RGB_R_CL].ClampToByte(); dtR[RGB_G] = data[i + RGB_G_CL].ClampToByte(); dtR[RGB_B] = data[i + RGB_B_CL].ClampToByte(); dtR[RGB_A] = data[i + RGB_A_CL].ClampToByte(); } } } else { for (int i = 0, iTo = h * sDt; i < iTo; dtR += paddR) { for (var iToLine = i + wpI; i < iToLine; dtR += pwR, i += pwI) { dtR[RGB_R] = data[i + RGB_R_CL].ClampToByte(); dtR[RGB_G] = data[i + RGB_G_CL].ClampToByte(); dtR[RGB_B] = data[i + RGB_B_CL].ClampToByte(); } } } }
public static unsafe void Colorize(UnmanagedImage image, Rectangle rect, int usedChannel) { var pb = image.GetPixelFormatSizeInBytes(); if (usedChannel < 0 || usedChannel >= pb) { throw new ArgumentException(nameof(usedChannel)); } var d = (byte *)image.ImageData + (rect.Y * image.Stride) + (rect.X * pb) + usedChannel; var wd = Math.Min(rect.Width, image.Width - rect.X) * pb; var dPad = image.Stride - wd; for (var dTo = d + (Math.Min(rect.Height, image.Height - rect.Y) * image.Stride); d < dTo; d += dPad) { for (var dToLn = d + wd; d < dToLn; d += pb) { *d = byte.MaxValue; } } }
public static void CopyTo(this UnmanagedImage srcImage, ref byte[] dstArray) { var wb = srcImage.Width * srcImage.GetPixelFormatSizeInBytes(); var s = srcImage.Stride; var nj = wb * srcImage.Height; if (dstArray == null || dstArray.Length < nj) { dstArray = new byte[nj]; } int i = 0, j = 0; if (nj >= dstArray.Length) { nj -= wb; for (; j < nj; i += s, j += wb) { Marshal.Copy(srcImage.ImageData + i, dstArray, j, wb); } Marshal.Copy(srcImage.ImageData + i, dstArray, j, dstArray.Length - j); } else { var ni = s * (srcImage.Height - 1); for (; i < ni; i += s, j += wb) { Marshal.Copy(srcImage.ImageData + i, dstArray, j, wb); } Marshal.Copy(srcImage.ImageData + i, dstArray, j, i = (ni + wb) - i); Array.Clear(dstArray, j += i, dstArray.Length - j); } }
public static unsafe void Lab2Rgb(UnmanagedImage srcImage, UnmanagedImage dstImage) { if (srcImage == null || dstImage == null) { throw new NullReferenceException(srcImage == null ? nameof(srcImage) : nameof(dstImage)); } var bytesPerPixel = srcImage.GetPixelFormatSizeInBytes(); var hasAlpha = bytesPerPixel == 4; if (bytesPerPixel != 3 && !hasAlpha) { throw new NotSupportedException(nameof(bytesPerPixel) + " != 4"); } var srcPtr = (byte *)srcImage.ImageData; var dstPtr = (byte *)dstImage.ImageData; var line = srcImage.Width * bytesPerPixel; var padd = srcImage.Stride - line; if (hasAlpha) { for (var srcPtrTo = srcPtr + (srcImage.Stride * srcImage.Height); srcPtr < srcPtrTo; srcPtr += padd, dstPtr += padd) { for (var srcLineTo = srcPtr + line; srcPtr < srcLineTo; srcPtr += bytesPerPixel, dstPtr += bytesPerPixel) { Lab2Rgb( srcPtr[LAB_L], srcPtr[LAB_A], srcPtr[LAB_B], out dstPtr[RGB_R], out dstPtr[RGB_G], out dstPtr[RGB_B] ); dstPtr[RGB_A] = srcPtr[RGB_A]; } } } else { for (var srcPtrTo = srcPtr + (srcImage.Stride * srcImage.Height); srcPtr < srcPtrTo; srcPtr += padd, dstPtr += padd) { for (var srcLineTo = srcPtr + line; srcPtr < srcLineTo; srcPtr += bytesPerPixel, dstPtr += bytesPerPixel) { Lab2Rgb( srcPtr[LAB_L], srcPtr[LAB_A], srcPtr[LAB_B], out dstPtr[RGB_R], out dstPtr[RGB_G], out dstPtr[RGB_B] ); } } } }
public static int GetLineForward(this UnmanagedImage image) => image.Stride - (image.Width * image.GetPixelFormatSizeInBytes());
public static int GetNumBytes(this UnmanagedImage image) => image.Width * image.GetPixelFormatSizeInBytes() * image.Height;
public static int GetBytesPerPixel(this UnmanagedImage image) => image.GetPixelFormatSizeInBytes();
static unsafe void VerticalBoxBlur(ref UnmanagedImage image, Rectangle rect, IntRange kernelSizeRange) { int pixelSize = image.GetPixelFormatSizeInBytes(); int startY = rect.Top; int stopY = startY + rect.Height; int startX = rect.Left * pixelSize; int stopX = startX + rect.Width * pixelSize; byte *basePtr = (byte *)image.ImageData.ToPointer(); if (image.PixelFormat == PixelFormat.Format8bppIndexed || image.PixelFormat == PixelFormat.Format24bppRgb || image.PixelFormat == PixelFormat.Format32bppArgb || image.PixelFormat == PixelFormat.Format32bppRgb) { int offset = image.Stride - (stopX - startX); // align pointer to the first pixel to process var ptr = basePtr + (startY * image.Stride + rect.Left * pixelSize); for (int y = startY; y < stopY; y++) { for (int x = startX; x < stopX; x++, ptr++) { int sum = 0; for (int yFilter = kernelSizeRange.Min; yFilter < kernelSizeRange.Max; yFilter++) { int yBound = y + yFilter; //Only if in bounds if (yBound < 0 || yBound >= image.Height) { continue; } sum += ptr[yFilter * image.Stride]; } *ptr = (byte)(sum / kernelSizeRange.Length); } ptr += offset; } } else // 16bpp per channel (ushort*) { // align pointer to the first pixel to process basePtr += (startY * image.Stride + rect.Left * pixelSize * 2); for (int y = startY; y < stopY; y++) { ushort *ptr = (ushort *)(basePtr); for (int x = startX; x < stopX; x++, ptr++) { int sum = 0; for (int yFilter = kernelSizeRange.Min; yFilter < kernelSizeRange.Max; yFilter++) { int yBound = y + yFilter; //Only if in bounds if (yBound < 0 || yBound >= image.Height) { continue; } sum += ptr[yFilter * image.Stride / 2]; } *ptr = (ushort)(sum / kernelSizeRange.Length); } basePtr += image.Stride; } } }