private ICanvasImage CreateDiscreteTransfer() { var discreteTransferEffect = new DiscreteTransferEffect { Source = bitmapTiger }; float[][] tables = { new float[] { 0, 1 }, new float[] { 1, 0 }, new float[] { 0,0.5f, 1 }, }; // Animation switches between different quantisation color transfer tables. animationFunction = elapsedTime => { int t = (int)(elapsedTime * 2); discreteTransferEffect.RedTable = tables[t % tables.Length]; discreteTransferEffect.GreenTable = tables[(t / tables.Length) % tables.Length]; discreteTransferEffect.BlueTable = tables[(t / tables.Length / tables.Length) % tables.Length]; }; return(discreteTransferEffect); }
private static ICanvasImage CreateDiscreteTranferEffect(ICanvasImage canvasImage) { var ef = new DiscreteTransferEffect { Source = canvasImage, RedTable = new float[] { 1, 0 }, GreenTable = new float[] { 1, 0 }, BlueTable = new float[] { 0, 1 }, }; return(ef); }
private ICanvasImage CreateDiscreteTransfer() { var discreteTransferEffect = new DiscreteTransferEffect { Source = bitmapTiger }; float[][] tables = { new float[] { 0, 1 }, new float[] { 1, 0 }, new float[] { 0, 0.5f, 1 }, }; // Animation switches between different quantisation color transfer tables. animationFunction = elapsedTime => { int t = (int)(elapsedTime * 2); discreteTransferEffect.RedTable = tables[t % tables.Length]; discreteTransferEffect.GreenTable = tables[(t / tables.Length) % tables.Length]; discreteTransferEffect.BlueTable = tables[(t / tables.Length / tables.Length) % tables.Length]; }; return discreteTransferEffect; }
async Task GenerateIcon(AppInfo appInfo, IconInfo iconInfo, StorageFolder folder) { // Draw the icon image into a command list. var commandList = new CanvasCommandList(device); using (var ds = commandList.CreateDrawingSession()) { appInfo.DrawIconImage(ds, iconInfo); } ICanvasImage iconImage = commandList; // Rasterize into a rendertarget. var renderTarget = new CanvasRenderTarget(device, iconInfo.Width, iconInfo.Height, 96); using (var ds = renderTarget.CreateDrawingSession()) { // Initialize with the appropriate background color. ds.Clear(iconInfo.TransparentBackground ? Colors.Transparent : appInfo.BackgroundColor); // Work out where to position the icon image. var imageBounds = iconImage.GetBounds(ds); imageBounds.Height *= 1 + iconInfo.BottomPadding; float scaleUpTheSmallerIcons = Math.Max(1, 1 + (60f - iconInfo.Width) / 50f); float imageScale = appInfo.ImageScale * scaleUpTheSmallerIcons; var transform = Matrix3x2.CreateTranslation((float)-imageBounds.X, (float)-imageBounds.Y) * Utils.GetDisplayTransform(renderTarget.Size.ToVector2(), new Vector2((float)imageBounds.Width, (float)imageBounds.Height)) * Matrix3x2.CreateScale(imageScale, renderTarget.Size.ToVector2() / 2); if (iconInfo.Monochrome) { // Optionally convert to monochrome. iconImage = new DiscreteTransferEffect { Source = new Transform2DEffect { Source = new LuminanceToAlphaEffect { Source = iconImage }, TransformMatrix = transform }, RedTable = new float[] { 1 }, GreenTable = new float[] { 1 }, BlueTable = new float[] { 1 }, AlphaTable = new float[] { 0, 1 } }; } else { ds.Transform = transform; // Optional shadow effect. if (appInfo.AddShadow) { var shadow = new ShadowEffect { Source = iconImage, BlurAmount = 12, }; ds.DrawImage(shadow); } } // draw the main icon image. ds.DrawImage(iconImage); } // Save to a file. using (var stream = await folder.OpenStreamForWriteAsync(iconInfo.Filename, CreationCollisionOption.ReplaceExisting)) { await renderTarget.SaveAsync(stream.AsRandomAccessStream(), CanvasBitmapFileFormat.Png); } }
void CreateEffects() { // The Game of Life is a cellular automaton with very simple rules. // Each cell (pixel) can be either alive (white) or dead (black). // The state is updated by: // // - for each cell, count how many of its 8 neighbors are alive // - if less than two, the cell dies from loneliness // - if exactly two, the cell keeps its current state // - if exactly three, the cell become alive // - if more than three, the cell dies from overcrowding // Step 1: use a convolve matrix to count how many neighbors are alive. This filter // also includes the state of the current cell, but with a lower weighting. The result // is an arithmetic encoding where (value / 2) indicates how many neighbors are alive, // and (value % 2) is the state of the cell itself. This is divided by 18 to make it // fit within 0-1 color range. countNeighborsEffect = new ConvolveMatrixEffect { KernelMatrix = new float[] { 2, 2, 2, 2, 1, 2, 2, 2, 2 }, Divisor = 18, BorderMode = EffectBorderMode.Hard, }; // Step 2: use a color transfer table to map the different states produced by the // convolve matrix to whether the cell should live or die. Each pair of entries in // this table corresponds to a certain number of live neighbors. The first of the // pair is the result if the current cell is dead, or the second if it is alive. float[] transferTable = { 0, 0, // 0 live neighbors -> dead cell 0, 0, // 1 live neighbors -> dead cell 0, 1, // 2 live neighbors -> cell keeps its current state 1, 1, // 3 live neighbors -> live cell 0, 0, // 4 live neighbors -> dead cell 0, 0, // 5 live neighbors -> dead cell 0, 0, // 6 live neighbors -> dead cell 0, 0, // 7 live neighbors -> dead cell 0, 0, // 8 live neighbors -> dead cell }; liveOrDieEffect = new DiscreteTransferEffect { Source = countNeighborsEffect, RedTable = transferTable, GreenTable = transferTable, BlueTable = transferTable, }; // Step 3: the algorithm is implemented in terms of white = live, // black = dead, but we invert these colors before displaying the // result, just 'cause I think it looks better that way. invertEffect = new LinearTransferEffect { RedSlope = -1, RedOffset = 1, GreenSlope = -1, GreenOffset = 1, BlueSlope = -1, BlueOffset = 1, }; // Step 4: insert our own DPI compensation effect to stop the system trying to // automatically convert DPI for us. The Game of Life simulation always works // in pixels (96 DPI) regardless of display DPI. Normally, the system would // handle this mismatch automatically and scale the image up as needed to fit // higher DPI displays. We don't want that behavior here, because it would use // a linear filter while we want nearest neighbor. So we insert a no-op DPI // converter of our own. This overrides the default adjustment by telling the // system the source image is already the same DPI as the destination canvas // (even though it really isn't). We'll handle any necessary scaling later // ourselves, using Transform2DEffect to control the interpolation mode. var dpiCompensationEffect = new DpiCompensationEffect { Source = invertEffect, SourceDpi = new Vector2(canvas.Dpi), }; // Step 5: a transform matrix scales up the simulation rendertarget and moves // it to the right part of the screen. This uses nearest neighbor filtering // to avoid unwanted blurring of the cell shapes. transformEffect = new Transform2DEffect { Source = dpiCompensationEffect, InterpolationMode = CanvasImageInterpolation.NearestNeighbor, }; }
public void ProcessFrame(ProcessVideoFrameContext context) { CanvasRenderTarget rt = new CanvasRenderTarget(canvasDevice, context.OutputFrame.Direct3DSurface.Description.Width, context.OutputFrame.Direct3DSurface.Description.Height, 96.0f); using (CanvasBitmap input = CanvasBitmap.CreateFromDirect3D11Surface(canvasDevice, context.InputFrame.Direct3DSurface)) using (CanvasDrawingSession ds = rt.CreateDrawingSession()) { TimeSpan time = context.InputFrame.RelativeTime.HasValue ? context.InputFrame.RelativeTime.Value : new TimeSpan(); float dispX = (float)Math.Cos(time.TotalSeconds) * 75f; float dispY = (float)Math.Sin(time.TotalSeconds) * 75f; ds.Clear(Colors.Black); //var posterizeEffect = new PosterizeEffect() //{ // Source = input, // BlueValueCount = 2, // RedValueCount = 2, // GreenValueCount = 2, //}; var transformEffect = new Transform2DEffect() { Source = input, TransformMatrix = new System.Numerics.Matrix3x2(-1, 0, 0, 1, rt.SizeInPixels.Width, 0), }; var discreteTransferEffect = new DiscreteTransferEffect() { Source = transformEffect, RedTable = new float[] { 0.0f, 1.0f, 1.0f, 1.0f }, GreenTable = new float[] { 0.0f, 1.0f, 1.0f, 1.0f }, BlueTable = new float[] { 0.0f, 1.0f, 1.0f, 1.0f }, AlphaDisable = true, }; var dispMap = new ConvolveMatrixEffect() { KernelMatrix = new float[] { 0, +1, 0, +1, -4, +1, 0, +1, 0, }, Source = discreteTransferEffect, Divisor = 0.2f, }; var modEffect = new ArithmeticCompositeEffect() { Source1 = dispMap, Source2 = dispMap, MultiplyAmount = 1, }; //var finalPosterizeEffect = new PosterizeEffect() //{ // Source = modEffect, // BlueValueCount = 2, // RedValueCount = 2, // GreenValueCount = 2, //}; //var dispMap = new EdgeDetectionEffect() //{ // Source = greyScaleEffect, // Mode = EdgeDetectionEffectMode.Sobel, //}; Rect src = new Rect(rt.SizeInPixels.Width / 3, rt.SizeInPixels.Height / 3, rt.SizeInPixels.Width / 3, rt.SizeInPixels.Height / 3); //ds.DrawImage(input, bottomLeft); //ds.DrawImage(discreteTransferEffect, bottomRight, src); //ds.DrawImage(dispMap, topLeft, src); ds.DrawImage(modEffect, src, src); } int centerX = 0; int centerY = 0; int cubletWidth = 0; int cubletHeight = 0; int analysisAreaX = (int)rt.SizeInPixels.Width * 3 / 10; int analysisWidth = (int)rt.SizeInPixels.Width * 4 / 10; byte[] analysisHorzBytes = rt.GetPixelBytes(analysisAreaX, (int)rt.SizeInPixels.Height / 2, analysisWidth, 1); int analysisAreaY = (int)rt.SizeInPixels.Height * 3 / 10; int analysisHeight = (int)rt.SizeInPixels.Height * 4 / 10; byte[] analysisVertBytes = rt.GetPixelBytes((int)rt.SizeInPixels.Width / 2, analysisAreaY, 1, analysisHeight); int foundLeft = 0; for (int i = 0; i < analysisWidth / 2; i++) { byte b = analysisHorzBytes[4 * (analysisWidth / 2 - i) + 0]; byte g = analysisHorzBytes[4 * (analysisWidth / 2 - i) + 1]; byte r = analysisHorzBytes[4 * (analysisWidth / 2 - i) + 2]; if ((r > 100 || g > 100 || b > 50) && foundLeft == 0) { foundLeft = i; } } int foundRight = 0; for (int i = 0; i < analysisWidth / 2; i++) { byte r = analysisHorzBytes[4 * (analysisWidth / 2 + i) + 0]; byte g = analysisHorzBytes[4 * (analysisWidth / 2 + i) + 1]; byte b = analysisHorzBytes[4 * (analysisWidth / 2 + i) + 2]; if ((r > 100 || g > 100 || b > 50) && foundRight == 0) { foundRight = i; } } int foundTop = 0; for (int i = 0; i < analysisHeight / 2; i++) { byte r = analysisVertBytes[4 * (analysisHeight / 2 - i) + 0]; byte g = analysisVertBytes[4 * (analysisHeight / 2 - i) + 1]; byte b = analysisVertBytes[4 * (analysisHeight / 2 - i) + 2]; if ((r > 100 || g > 100 || b > 50) && foundTop == 0) { foundTop = i; } } int foundBottom = 0; for (int i = 0; i < analysisHeight / 2; i++) { byte r = analysisVertBytes[4 * (analysisHeight / 2 + i) + 0]; byte g = analysisVertBytes[4 * (analysisHeight / 2 + i) + 1]; byte b = analysisVertBytes[4 * (analysisHeight / 2 + i) + 2]; if ((r > 100 || g > 100 || b > 50) && foundBottom == 0) { foundBottom = i; } } centerX = (-foundLeft + foundRight) / 2 + (int)rt.SizeInPixels.Width / 2; centerY = (-foundTop + foundBottom) / 2 + (int)rt.SizeInPixels.Height / 2; cubletWidth = (int)((foundLeft + foundRight) * 1.2f); cubletHeight = (int)((foundTop + foundBottom) * 1.2f); // No 2d arrays in WinRT components? Boo. // "Error C1113 #using failed on 'rubikscuberecognitionwinrt.winmd' RubiksCubeRecognitionLib Vector2[] cubletCenters = new Vector2[3 * 3]; cubletCenters[1 * 3 + 1] = new Vector2(centerX, centerY); cubletCenters[1 * 3 + 0] = new Vector2(centerX, centerY - cubletHeight); cubletCenters[1 * 3 + 2] = new Vector2(centerX, centerY + cubletHeight); cubletCenters[0 * 3 + 1] = new Vector2(centerX - cubletWidth, centerY); cubletCenters[0 * 3 + 0] = new Vector2(centerX - cubletWidth, centerY - cubletHeight); cubletCenters[0 * 3 + 2] = new Vector2(centerX - cubletWidth, centerY + cubletHeight); cubletCenters[2 * 3 + 1] = new Vector2(centerX + cubletWidth, centerY); cubletCenters[2 * 3 + 0] = new Vector2(centerX + cubletWidth, centerY - cubletHeight); cubletCenters[2 * 3 + 2] = new Vector2(centerX + cubletWidth, centerY + cubletHeight); cubeletColorsMutex.WaitOne(); using (CanvasBitmap input = CanvasBitmap.CreateFromDirect3D11Surface(canvasDevice, context.InputFrame.Direct3DSurface)) using (CanvasRenderTarget output = CanvasRenderTarget.CreateFromDirect3D11Surface(canvasDevice, context.OutputFrame.Direct3DSurface)) using (CanvasDrawingSession ds = output.CreateDrawingSession()) { var transformEffect = new Transform2DEffect() { Source = input, TransformMatrix = new System.Numerics.Matrix3x2(-1, 0, 0, 1, output.SizeInPixels.Width, 0), }; Rect src = new Rect(0, 0, output.SizeInPixels.Width, output.SizeInPixels.Height); ds.DrawImage(transformEffect, src, src); // Draw a crosshair on the screen ds.FillRectangle(new Rect(output.SizeInPixels.Width / 2 - 3, output.SizeInPixels.Height / 4, 6, output.SizeInPixels.Height / 2), Colors.Gray); ds.FillRectangle(new Rect(output.SizeInPixels.Width / 4, output.SizeInPixels.Height / 2 - 3, output.SizeInPixels.Width / 2, 6), Colors.Gray); if (true) { for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { int sampleWidth = 2; byte[] cubletBytes = input.GetPixelBytes((int)cubletCenters[(2 - x) * 3 + y].X - sampleWidth / 2, (int)cubletCenters[(2 - x) * 3 + y].Y - sampleWidth / 2, sampleWidth, sampleWidth); int totalR = 0; int totalG = 0; int totalB = 0; for (int i = 0; i < sampleWidth * sampleWidth; i++) { totalB += cubletBytes[4 * i + 0]; totalG += cubletBytes[4 * i + 1]; totalR += cubletBytes[4 * i + 2]; } cubletColors[x * 3 + y] = Color.FromArgb(255, (byte)(totalR / (sampleWidth * sampleWidth)), (byte)(totalG / (sampleWidth * sampleWidth)), (byte)(totalB / (sampleWidth * sampleWidth))); } } for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { ds.FillRectangle((float)cubletCenters[x * 3 + y].X - 12, (float)cubletCenters[x * 3 + y].Y - 12, 24, 24, Colors.Black); ds.FillRectangle((float)cubletCenters[x * 3 + y].X - 10, (float)cubletCenters[x * 3 + y].Y - 10, 20, 20, cubletColors[x * 3 + y]); } } } } cubeletColorsMutex.ReleaseMutex(); }