/// <summary> /// Converts a byte array from BGR to RGB. /// </summary> static byte[] EncodingConversion(ImageMsg image, bool convertBGR = true, bool flipY = true) { // Number of channels in this encoding int channels = image.GetNumChannels(); if (!image.EncodingRequiresBGRConversion()) { convertBGR = false; } // If no modifications are necessary, return original array if (!convertBGR && !flipY) { return(image.data); } int channelStride = image.GetBytesPerChannel(); int pixelStride = channelStride * channels; int rowStride = pixelStride * (int)image.width; if (flipY) { ReverseInBlocks(image.data, rowStride, (int)image.height); } if (convertBGR) { // given two channels, we swap R with G (distance = 1). // given three or more channels, we swap R with B (distance = 2). int swapDistance = channels == 2 ? channelStride : channelStride * 2; int dataLength = (int)image.width * (int)image.height * pixelStride; if (channelStride == 1) { // special case for the 1-byte-per-channel formats: avoid the inner loop for (int pixelIndex = 0; pixelIndex < dataLength; pixelIndex += pixelStride) { int swapB = pixelIndex + swapDistance; byte temp = image.data[pixelIndex]; image.data[pixelIndex] = image.data[swapB]; image.data[swapB] = temp; } } else { for (int pixelIndex = 0; pixelIndex < dataLength; pixelIndex += pixelStride) { int channelEndByte = pixelIndex + channelStride; for (int byteIndex = pixelIndex; byteIndex < channelEndByte; byteIndex++) { int swapB = byteIndex + swapDistance; byte temp = image.data[byteIndex]; image.data[byteIndex] = image.data[swapB]; image.data[swapB] = temp; } } } } return(image.data); }
public static void DebayerConvert(this ImageMsg image, bool flipY = true) { int channelStride = image.GetBytesPerChannel(); int width = (int)image.width; int height = (int)image.height; int rowStride = width * channelStride; int dataSize = rowStride * height; int finalPixelStride = channelStride * 4; int[] reorderIndices; switch (image.encoding) { case "bayer_rggb8": reorderIndices = new int[] { 0, 1, width + 1 }; break; case "bayer_bggr8": reorderIndices = new int[] { width + 1, 1, 0 }; break; case "bayer_gbrg8": reorderIndices = new int[] { width, 0, 1 }; break; case "bayer_grbg8": reorderIndices = new int[] { 1, 0, width }; break; case "bayer_rggb16": reorderIndices = new int[] { 0, 1, 2, 3, rowStride + 2, rowStride + 3 }; break; case "bayer_bggr16": reorderIndices = new int[] { rowStride + 2, rowStride + 3, 2, 3, 0, 1 }; break; case "bayer_gbrg16": reorderIndices = new int[] { rowStride, rowStride + 1, 0, 1, 2, 3 }; break; case "bayer_grbg16": reorderIndices = new int[] { 2, 3, 0, 1, rowStride, rowStride + 1 }; break; default: return; } if (flipY) { ReverseInBlocks(image.data, rowStride * 2, (int)image.height / 2); } if (s_ScratchSpace == null || s_ScratchSpace.Length < rowStride * 2) { s_ScratchSpace = new byte[rowStride * 2]; } int rowStartIndex = 0; while (rowStartIndex < dataSize) { Buffer.BlockCopy(image.data, rowStartIndex, s_ScratchSpace, 0, rowStride * 2); int pixelReadIndex = 0; int pixelWriteIndex = rowStartIndex; while (pixelReadIndex < rowStride) { for (int Idx = 0; Idx < reorderIndices.Length; ++Idx) { image.data[pixelWriteIndex + Idx] = s_ScratchSpace[pixelReadIndex + reorderIndices[Idx]]; } image.data[pixelWriteIndex + reorderIndices.Length] = 255; if (channelStride == 2) { image.data[pixelWriteIndex + reorderIndices.Length + 1] = 255; } pixelReadIndex += channelStride * 2; pixelWriteIndex += finalPixelStride; } rowStartIndex += rowStride * 2; } image.width = image.width / 2; image.height = image.height / 2; image.encoding = channelStride == 1 ? "rgba8" : "rgba16"; image.step = (uint)(channelStride * image.width); }