Extended image content processor: grayscale transformation and processor parameter problems
You want to extend the image processor to process the color of each independent pixel. You also want to change the processor parameters from the XNA main project.
Solution
In the previous tutorial, you learned how to extend the content processor so that you can process and change the value of an independent pixel.
All public variables declared in the Processor class can be set in the material property panel.
Working Principle
The initial initialization steps have been explained in 3-9 of the tutorial. Copy the following code to process all images in an image file (some image files, such as texCube, contain multiple images ):
namespace GrayContentPipeline{ [ContentProcessor(DisplayName = "GrayScaleProcessor")] public class ExtentedTextureProcessor : TextureProcessor { public override TextureContent Process(TextureContent input, ContentProcessorContext context) { TextureContent texContent = base.Process(input, context); texContent.ConvertBitmapType(typeof(PixelBitmapContent<Color>)); for (int face = 0; face < input.Faces.Count; face++) { MipmapChain mipChain = input.Faces[face]; for (int mipLevel = 0; mipLevel < mipChain.Count; mipLevel++) { ... } } return texContent; } }}
In an internal loop, you process all faces of the image. First, convert the current face into a PixelBitmapContent object so that you can process each pixel independently. You can create the second PixelBitmapContent object immediately and store the new color in the second one:
PixelBitmapContent<Color> oldImage = (PixelBitmapContent<Color>)input.Faces[face][mipLevel]; PixelBitmapContent<Vector4> grayImage = new PixelBitmapContent<Vector4>(oldImage.Width, oldImage.Height);
Note:In this example, you can simply overwrite the old color value with the new color value. However, for many image processing technologies, in order to calculate the new color of pixels, you often need to access the original color of the surrounding pixels, if you can separate a new image from the old image, there will be no problem.
As you can see, you can freely define the color format you want to accept. In this example, the format of the original Color you want to read is Color, but the new Color format is Vector4.
Next, you traverse all the pixels of the image and obtain the original color:
for (int x = 0; x < oldImage.Width; x++) for (int y = 0; y < oldImage.Height; y++) { Color oldColor = oldImage.GetPixel(x, y); }
Once you know the original color, you can define the corresponding gray color. Do not simply average the three color channels, because human eyes are more sensitive to green. Each color channel uses an integer between 0 and 255. However, when you create a new color, you need to use a floating point between 0 and 1 to represent the color value. This means you need to divide the initial color value by 255:
Color oldColor = oldImage.GetPixel(x, y); float grayValue = oldColor.R * 0.299f / 255.0f; grayValue += oldColor.G * 0.596f / 255.0f; grayValue += oldColor.B * 0.211f / 255.0f; float alpha = oldColor.A / 255.0f; Vector4 grayColor = new Vector4(grayValue, grayValue, grayValue, alpha); grayImage.SetPixel(x, y, newColor);
This can replace all pixels of the image with the corresponding gray color. After two cycles, make sure that the new color is copied to the current image face:
input.Faces[face][mipLevel] = grayImage;
Debug content Processor
You often need to debug the content pipeline. This is more difficult than debugging common projects, because breakpoints are often ignored during compilation, and you have to manually connect a debugger to the content project. For example, you can use the following code to debug pixels in the image center of a Project:
if ((x == oldImage.Width / 2) && (y == oldImage.Height / 2)) { System.Diagnostics.Debugger.Launch(); }
When compiling a project, Visual Studio reminds you to specify which debugger to use and select New Instance of Visual Studio.
Once the Debugger starts running, you can call System. Diagnostics. Debugger. Break () wherever you want to insert a breakpoint ().
Define processor Parameters
By adding a common variable in, you can make your processor more flexible. For example, add the following code to the top of the Processor class: public float interpolation = 0.8f; when compiling a project, you can set this value from the XNA main project, as shown in 3-15.
Figure 3-15 set custom processor Parameters
You can use this variable anywhere in the content processor. In this example, we can use this variable to perform interpolation between a common color-based image and a new gray-scale image. If the value of interpolation is 0, the colored pixels are stored in the new image. If the value is 1, The grayscale image is stored.
Vector4 grayColor = new Vector4(grayValue, grayValue, grayValue, alpha); Vector4 origColor = oldColor.ToVector4(); Vector4 newColor = Vector4.Lerp(origColor, grayColor, interpolation); grayImage.SetPixel(x, y, newColor);
Code
The complete code of the grayscale image processor is as follows:
namespace GrayContentPipeline { [ContentProcessor(DisplayName = "GrayScaleProcessor")] public class ExtentedTextureProcessor : TextureProcessor { private float interpolation = 0.8f; public float Interpolation { get { return interpolation; } set { interpolation = value; } } public override TextureContent Process(TextureContent input, ContentProcessorContext context) { TextureContent texContent = base.Process(input, context); texContent.ConvertBitmapType(typeof(PixelBitmapContent<Color>)); for (int face = 0; face < input.Faces.Count; face++) { MipmapChain mipChain = input.Faces[face]; for (int mipLevel = 0; mipLevel < mipChain.Count; mipLevel++) { PixelBitmapContent<Color> oldImage = PixelBitmapContent<Color>)input.Faces[face][mipLevel]; PixelBitmapContent<Vector4> grayImage = new PixelBitmapContent<Vector4> (oldImage.Width, oldImage.Height); for (int x = 0; x < oldImage.Width; x++) for (int y = 0; y < oldImage.Height; y++) { Color oldColor = oldImage.GetPixel(x, y); float grayValue = oldColor.R * 0.299f / 255.0f; grayValue += oldColor.G * 0.596f / 255.0f; grayValue += oldColor.B * 0.211f / 255.0f; float alpha = oldColor.A / 255.0f; Vector4 grayColor = new Vector4(grayValue,grayValue, grayValue, alpha); Vector4 origColor = oldColor.ToVector4(); Vector4 newColor = Vector4.Lerp(origColor, grayColor, interpolation); grayImage.SetPixel(x, y, newColor); } input.Faces[face][mipLevel] = grayImage; } } return texContent; } }}