I'm trying to use Win2D/C# to project an image using a overhead projector and I need to use a Win2D effect to do Keystone Correction (pre-warp the image) as the final step.
Basically I'm drawing a rectangle, then trying to use a Transform3DEffect to warp it before rendering. I can't figure out what Matrix transformation combination to use to get it to work. Doing a full camera projection seems like overkill since I only need warping in one direction (see image below). What transforms should I use?
Using an Image like following, can get you a similar effect.
https://i.sstatic.net/5QnEm.png
I am unsure what results in the "bending".
Code for creating the displacement map (with GDI+, because you can set pixels fast). The LockBitmap you can find here
static void DrawDisplacement(int width, int height, LockBitmap lbmp)
{
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
int roff = (int)((((width >> 1) - x) / (float)(width >> 1)) * ((height - y) / (float)height) * 127);
int goff = 0;
lbmp.SetPixel(x, y, Color.FromArgb(127 - roff, 127 - goff, 0));
}
}
Drawing in Win2D looks something like this, where displacementImage is the loaded file and offscreen, is a 'CanvasRenderTarget' on which I drew the grid.
//Scaling for fitting the image to the content
ICanvasImage scaledDisplacement = new Transform2DEffect
{
BorderMode = EffectBorderMode.Hard,
Source = displacementImage,
TransformMatrix = Matrix3x2.CreateScale((float) (sender.Size.Width / displacementImage.Bounds.Width), (float) (sender.Size.Height / displacementImage.Bounds.Height)),
Sharpness = 1f,
BufferPrecision = CanvasBufferPrecision.Precision32Float,
InterpolationMode = CanvasImageInterpolation.HighQualityCubic,
};
//Blurring, for a better result
ICanvasImage displacement = new GaussianBlurEffect
{
BorderMode = EffectBorderMode.Hard,
Source = scaledDisplacement,
BufferPrecision = CanvasBufferPrecision.Precision32Float,
BlurAmount = 2,
Optimization = EffectOptimization.Quality,
};
ICanvasImage graphicsEffect = new DisplacementMapEffect
{
Source = offscreen,
Displacement = displacement,
XChannelSelect = EffectChannelSelect.Red,
YChannelSelect = EffectChannelSelect.Green,
Amount = 800,//change for more or less displacement
BufferPrecision = CanvasBufferPrecision.Precision32Float,
};