/// <summary> /// Converts an ImageData type of the person mask to a color32 array. /// This function does not call Texture2D.apply. which should be called to apply the changes to the texture /// </summary> /// <param name="maskImageData">Contains the mask image data</param> /// <param name="maskColor">the color to set the mask to</param> /// <param name="pixels">The color array to write the person mask on. /// It must fit the image size, or else an error is returned</param> /// <returns>ReturnCode indicating status of the run</returns> public static ReturnCode ConvertPersonMaskToColorArray(MaskImageData maskImageData, Color32 maskColor, bool flipx, bool flipy, ref Color32[] pixels) { CommonDefines.ImageData imageData; ReturnCode rc = maskImageData.GetData(out imageData); if (rc.IsError()) { return(rc); } CommonDefines.ImageFormat iFormat; maskImageData.GetImageFormat(out iFormat); rc = VerifyImageFormat(iFormat, pixels); if (rc.IsError()) { return(rc); } int xStart, xDir, yStart, yDir; SetLoopVars(flipx, flipy, iFormat, out xStart, out xDir, out yStart, out yDir); for (int y = 0; y != iFormat.m_height; ++y) { for (int x = 0; x != iFormat.m_width; ++x) { int pos = (yStart + yDir * y) * iFormat.m_widthStep + xStart + xDir * x; int pixelPos = y * iFormat.m_widthStep + x; pixels[pixelPos] = (imageData.m_dataArr[pos] > 0) ? maskColor : ZERO_COLOR; } } return(ReturnCode.OK_Status); }
/// <summary> /// Converts an ImageData type of the depth or color image to a color32[] and masks it according to the entered person mask. /// This function does not call Texture2D.apply. which should be called to apply the changes to the texture /// </summary> /// <param name="regImage">Contains the regular image data and format</param> /// <param name="maskImage">Contains the person mask image data and format</param> /// <param name="flipx">should the image be flipped horizontally</param> /// <param name="flipy">should the image be flipped vertically</param> /// <param name="depthColor">what is the base color of a depth image</param> /// <param name="pixels">The Color32 Array to write to. mast be in the right size for the wanted operation. /// <returns>ReturnCode indicating status of the run</returns> public static ReturnCode ConvertImageToMaskedColorArray(RegularImageData regImage, MaskImageData maskImage, bool flipx, bool flipy, Color32 depthColor, ref Color32[] pixels) { // get the image format and data CommonDefines.ImageFormat iFormat; regImage.GetImageFormat(out iFormat); CommonDefines.ImageData imageData; ReturnCode rc = regImage.GetData(out imageData); if (rc.IsError()) { return(rc); } // get the mask format and data CommonDefines.ImageFormat maskFormat; maskImage.GetImageFormat(out maskFormat); CommonDefines.ImageData maskedData; rc = maskImage.GetData(out maskedData); if (rc.IsError()) { return(rc); } rc = VerifyImageFormat(iFormat, pixels); if (rc.IsError()) { return(rc); } int imagePos = 0; int pixelPos = 0; int bpp = iFormat.m_bpc; int bppTimeChannels = iFormat.m_channels * bpp; int imagePixelHeight = iFormat.m_height; int imagePixelWidth = iFormat.m_width; int formatWidthStep = iFormat.m_widthStep; int maskHeightRatio = iFormat.m_height / maskFormat.m_height; int maskWidthRatio = iFormat.m_width / maskFormat.m_width; int maskImageWidth = maskFormat.m_width; // parameters for normalizing ushort minVal1 = 0, maxVal1 = 0; ushort minVal2 = 0, maxVal2 = 0; float range1 = 0, range2 = 0; bool isGrayscale = (iFormat.m_channels == 1); bool isDepth = (regImage.GetType() == typeof(DepthImageData)); minVal1 = (ushort)regImage.MinPixelValue; maxVal1 = (ushort)regImage.MaxPixelValue; range1 = maxVal1 - minVal1; if (isDepth) { GetPixelRange((DepthImageData)regImage, maskImage, out minVal2, out maxVal2, out range2); } else // on regualr images we dont want to tint the color { depthColor = WHITE_COLOR; } // get the loop vlues - this handle fliping the image horizontally and verticlly int xStart, xDir, yStart, yDir; SetLoopVars(flipx, flipy, iFormat, out xStart, out xDir, out yStart, out yDir); // iterate through the image for (int yindex = 0; yindex != imagePixelHeight; ++yindex) { for (int xindex = 0; xindex != imagePixelWidth; ++xindex) { int y = yStart + yDir * yindex; int x = xStart + xDir * xindex; // for each pixel get the coresponding pixel in the player mask int maskPos = (y / maskHeightRatio) * maskImageWidth + (x / maskWidthRatio); byte maskVal = maskedData.m_dataArr[maskPos]; // get the pixel in the image imagePos = y * formatWidthStep + x * bppTimeChannels; pixelPos = yindex * imagePixelWidth + xindex; if (maskVal > 0) { // get the image value and normalize if needed if (isGrayscale) { // values are ushorts, get them from a byte[] uint val1 = (uint)((imageData.m_dataArr[imagePos + 1] << 8) + imageData.m_dataArr[imagePos]); // normalize according to the whole image int val = (ushort)((val1 - minVal1) / (float)range1 * ushort.MaxValue); float relativeVal = (float)val / ushort.MaxValue; // we get here only in depth, we normalize according to the specific person and clamp values to [0.1,1] if (range2 != 0) { relativeVal = (maxVal2 - val) / ((float)range2); relativeVal = (relativeVal < 0.1f) ? 0.1f : relativeVal; } else // in normal grayscale image we clamp values to [0,1] { relativeVal = (relativeVal <= 0) ? 1f : relativeVal; } relativeVal = (relativeVal > 1f) ? 1f : relativeVal; pixels[pixelPos].a = depthColor.a; pixels[pixelPos].r = (byte)(depthColor.r * relativeVal); pixels[pixelPos].g = (byte)(depthColor.g * relativeVal); pixels[pixelPos].b = (byte)(depthColor.b * relativeVal); } else { pixels[pixelPos].a = 255; pixels[pixelPos].r = imageData.m_dataArr[imagePos]; pixels[pixelPos].g = (imageData.m_dataArr[imagePos + 1]); pixels[pixelPos].b = (imageData.m_dataArr[imagePos + 2]); } } else { pixels[pixelPos] = ZERO_COLOR; } } } return(ReturnCode.OK_Status); }
/// <summary> /// Converts an ImageData type of the depth or color image to a color32 array and masks it according to the entered person mask. /// This function does not call Texture2D.apply. which should be called to apply the changes to the texture /// </summary> /// <param name="regImage">Contains the regular image data and format</param> /// <param name="maskImage">Contains the person mask image data and format</param> /// <param name="flipx">should the image be flipped horizontally</param> /// <param name="flipy">should the image be flipped vertically</param> /// <param name="pixels">The Color32 Array to write to. mast be in the right size for the wanted operation. /// <returns>ReturnCode indicating status of the run</returns> public static ReturnCode ConvertImageToMaskedColorArray(RegularImageData regImage, MaskImageData maskImage, bool flipx, bool flipy, ref Color32[] pixels) { return(ConvertImageToMaskedColorArray(regImage, maskImage, flipx, flipy, WHITE_COLOR, ref pixels)); }
/// <summary> /// Gets the pixel range for the depth normalization according to mean and two stds around it, and by throwing away all data buckets which /// don't include atleast as much they would need acocording to a uniform distribution according to the bucket amount. /// </summary> /// <param name="width">Width of the image</param> /// <param name="height">Height of the image</param> /// <param name="shortImage">The short image pointer</param> /// <param name="minVal">(output) min value</param> /// <param name="maxVal">(output) max value</param> /// <param name="range">(output) range between the min and max values</param> private static void GetPixelRange(DepthImageData depthImage, MaskImageData maskImage, out ushort minVal, out ushort maxVal, out float range) { for (int i = 0; i < BUCKET_AMOUNT; ++i) { m_bucketList[i].Clear(); } CommonDefines.ImageFormat depthFormat, maskFormat; depthImage.GetImageFormat(out depthFormat); maskImage.GetImageFormat(out maskFormat); int height = depthFormat.m_height; int width = depthFormat.m_width; int formatWidthStep = depthFormat.m_widthStep; int bppTimeChannels = depthFormat.m_bpc * depthFormat.m_channels; int maskHeightRatio = height / maskFormat.m_height; int maskWidthRatio = width / maskFormat.m_width; int maskWidth = maskFormat.m_width; ushort globalMin = (ushort)depthImage.MinPixelValue; ushort globalMax = (ushort)depthImage.MaxPixelValue; float origRange = (float)(globalMax - globalMin); CommonDefines.ImageData maskImageData; maskImage.GetData(out maskImageData); byte[] maskData = maskImageData.m_dataArr; CommonDefines.ImageData depthImageData; depthImage.GetData(out depthImageData); byte[] depthData = depthImageData.m_dataArr; float bucketSize = ushort.MaxValue / BUCKET_AMOUNT; int totalAmount = 0; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int maskPos = (y / maskHeightRatio) * maskWidth + (x / maskWidthRatio); byte maskVal = maskData[maskPos]; int imagePos = y * formatWidthStep + x * bppTimeChannels; if (maskVal > 0) { int val = (int)((depthData[imagePos + 1] << 8) + depthData[imagePos]); float floatVal = (val - globalMin) / origRange; if (floatVal > 1) { floatVal = (floatVal > 1) ? 1 : floatVal; } floatVal = (floatVal < 0) ? 0 : floatVal; val = (int)(floatVal * ushort.MaxValue); if (val > 0) { //int bucketIndex = (int)Math.Min((val / bucketSize), (BUCKET_AMOUNT - 1)); int bucketIndex = (int)((val / bucketSize) < (BUCKET_AMOUNT - 1) ? (val / bucketSize) : (BUCKET_AMOUNT - 1)); ++m_bucketList[bucketIndex].m_amount; m_bucketList[bucketIndex].m_sum += (ulong)val; m_bucketList[bucketIndex].m_ssum += (val / 100f) * (val / 100f); ++totalAmount; } } } } int minBucketAmount = totalAmount / BUCKET_AMOUNT; double cleanedSsum = 0; ulong cleanedSum = 0; uint cleanedAmount = 0; for (int i = 0; i < BUCKET_AMOUNT; ++i) { if (m_bucketList[i].m_amount > minBucketAmount) { cleanedAmount += m_bucketList[i].m_amount; cleanedSum += m_bucketList[i].m_sum; cleanedSsum += m_bucketList[i].m_ssum; } } double average = 0; double std = 0; if (cleanedAmount > 0) { average = cleanedSum / (cleanedAmount * 1.0f); std = Math.Sqrt(((cleanedSsum / (cleanedAmount * 1.0f))) * 10000f - (average * average)); } minVal = (ushort)Math.Max((average - 2f * std), ushort.MinValue); maxVal = (ushort)Math.Min((average + 2f * std), ushort.MaxValue); //maxVal = (ushort)Math.Min((average + 10), ushort.MaxValue); //minVal = (ushort)Math.Max((average - 10), ushort.MinValue); range = (float)(maxVal - minVal); }