private static (PixelZone[] zones, PixelZonesTotals zoneTotals) SetupPixelZones(int width, int height, int rows, int columns) { var zoneTotals = new PixelZonesTotals(columns * rows); var zones = new PixelZone[columns * rows]; if (zones.Length == 0) { throw new Exception("0 Light zones created"); } var row = 0; for (var i = 0; i < zones.Length; ++i) { var col = i % columns; var xMin = (width / (double)columns) * col; //If we are in the last column just set the bottom right to screen width so we dont get weird rounding where edge is not included var xMax = col == columns - 1 ? width : (width / (double)columns) * (col + 1); var yMin = (height / (double)rows) * row; //If we are in the last row just set the bottom right to screen height so we dont get weird rounding where edge is not included var yMax = row == rows - 1 ? height : (height / (double)rows) * (row + 1); zones[i] = new PixelZone(row, col, (int)Math.Ceiling(xMin), (int)Math.Ceiling(xMax), (int)Math.Ceiling(yMin), (int)Math.Ceiling(yMax), width * 4, 4, zoneTotals, i); if (col == columns - 1) { row += 1; } } return(zones, zoneTotals); }
public async Task PostRead(PixelZone[] zones, PixelZonesTotals zoneTotals, long frame) { (MemoryStream image, MemoryStream blurImage)images = (null, null); var columns = zones.OrderByDescending(x => x.Column).First().Column + 1; var rows = zones.OrderByDescending(x => x.Row).First().Row + 1; //Pre allocate the memory stream for images since it will be the same size every time if (_smallImageMemStream == null) { _smallImageMemStream = new MemoryStream(columns * rows * 3); } var newWidth = (int)Math.Floor(columns * _config.Model.zoneProcessSettings.resizeScale); var newHeight = (int)Math.Floor(rows * _config.Model.zoneProcessSettings.resizeScale); if (_blurImageMemStream == null) { _blurImageMemStream = new MemoryStream(newWidth * newHeight * 3); } try { var start = DateTime.UtcNow; var time = start; zoneTotals.CalculateAverages(); //This is for debug purpose so I can just dump out the zones as pixels //using (var smallImage = ImageHandler.CreateSmallImageFromZones(zones, columns, rows)) //{ // var path = Path.Combine(_config.Model.imageDumpLocation, $"{frame.ToString().PadLeft(6, '0')}_small.png"); // using var writeStream = File.OpenWrite(path); // smallImage.Write(writeStream, MagickFormat.Png); //} time = DateTime.UtcNow; images = BitmapProcessor.PreparePostBitmap(zones, columns, rows, newWidth, newHeight, _config.Model.zoneProcessSettings.resizeFilter, _config.Model.zoneProcessSettings.resizeSigma, _smallImageMemStream, _blurImageMemStream); //Console.WriteLine($"PreparePostBitmap Time: {(DateTime.UtcNow - time).TotalMilliseconds}"); if (images.image == null) { Console.WriteLine($"f:{frame} Image is null. Check log"); return; } Rgb24 avgColor; unsafe { int totalR = 0; int totalG = 0; int totalB = 0; for (var i = 0; i < zones.Length; ++i) { totalR += zoneTotals.AvgR[i]; totalG += zoneTotals.AvgG[i]; totalB += zoneTotals.AvgB[i]; } avgColor = new Rgb24((byte)Math.Clamp(totalR / zones.Length, 0, 255), (byte)Math.Clamp(totalG / zones.Length, 0, 255), (byte)Math.Clamp(totalB / zones.Length, 0, 255)); } time = DateTime.UtcNow; var processingTasks = new List <Task>(); if (_config.Model.hueSettings.useHue) { if (_config.Model.hueSettings.hueType == HueType.Basic) { processingTasks.Add(Task.Run(() => _hueClient.ChangeLightColorBasic(avgColor))); } else if (_config.Model.hueSettings.hueType == HueType.Entertainment) { if (_hueImageMemStream == null) { _hueImageMemStream = new MemoryStream(newWidth * newHeight * 3); } _hueImageMemStream.Seek(0, SeekOrigin.Begin); _blurImageMemStream.Seek(0, SeekOrigin.Begin); await _blurImageMemStream.CopyToAsync(_hueImageMemStream); processingTasks.Add(Task.Run(() => { _hueClient.UpdateEntertainmentGroupFromImage(_hueImageMemStream, newWidth, newHeight); })); } } if (_config.Model.lightStripSettings.useLightStrip) { if (_lstripImageMemStream == null) { _lstripImageMemStream = new MemoryStream(newWidth * newHeight * 3); } _lstripImageMemStream.Seek(0, SeekOrigin.Begin); _blurImageMemStream.Seek(0, SeekOrigin.Begin); await _blurImageMemStream.CopyToAsync(_lstripImageMemStream); processingTasks.Add(Task.Run(() => { _stripLighter.UpdateFromImage(_lstripImageMemStream, newWidth, newHeight, frame); })); } //Console.WriteLine($"PostRead ChangeLightColor Time: {(DateTime.UtcNow - time).TotalMilliseconds}"); if (!_config.Model.ffmpegCaptureSettings.useFFMpeg && (_config.Model.rgbDeviceSettings.useKeyboards || _config.Model.rgbDeviceSettings.useMice)) { if (_rgbImageMemStream == null) { _rgbImageMemStream = new MemoryStream(newWidth * newHeight * 3); } _rgbImageMemStream.Seek(0, SeekOrigin.Begin); _blurImageMemStream.Seek(0, SeekOrigin.Begin); await _blurImageMemStream.CopyToAsync(_rgbImageMemStream); processingTasks.Add(Task.Run(() => { _rgbLighter.UpdateFromImage(avgColor, _rgbImageMemStream, newWidth, newHeight); })); } if (_config.Model.dumpPngs) { try { time = DateTime.UtcNow; var path = Path.Combine(_config.Model.imageDumpLocation, $"{frame.ToString().PadLeft(6, '0')}.png"); //_ = ImageHandler.WriteImageToFile(images.image, columns, rows, path, width, height); _ = ImageHandler.WriteImageToFile(images.blurImage, newWidth, newHeight, path, pixelFormat: PixelFormat.Rgb24); //Console.WriteLine($"PostRead writeStream Time: {(DateTime.UtcNow - time).TotalMilliseconds}"); } catch (Exception ex) { _ = Task.Run(() => _logger.WriteLog(ex.ToString())); } } await Task.WhenAll(processingTasks); //Console.WriteLine($"PostRead Total Time: {(DateTime.UtcNow - start).TotalMilliseconds}"); } catch (Exception ex) { _ = Task.Run(() => _logger.WriteLog(ex.ToString())); } finally { _blurImageMemStream?.Seek(0, SeekOrigin.Begin); _smallImageMemStream?.Seek(0, SeekOrigin.Begin); _hueImageMemStream?.Seek(0, SeekOrigin.Begin); _rgbImageMemStream?.Seek(0, SeekOrigin.Begin); _lstripImageMemStream?.Seek(0, SeekOrigin.Begin); } }