public static YCbCrImage RgbToYCbCr(RGBImage rgbImage) { Stopwatch stopwatch = Stopwatch.StartNew(); ColorChannel luminance = new ColorChannel(rgbImage.GetWidth(), rgbImage.GetHeight()); ColorChannel cbChannel = new ColorChannel(rgbImage.GetWidth(), rgbImage.GetHeight()); ColorChannel crChannel = new ColorChannel(rgbImage.GetWidth(), rgbImage.GetHeight()); int height = rgbImage.GetHeight(); if (height < 192) { for (int y = 0; y < rgbImage.GetHeight(); y++) { for (int x = 0; x < rgbImage.GetWidth(); x++) { YCbCr converted = ConvertRgbtoYCbCr(rgbImage.GetRGBAt(x, y)); luminance.SetPixel(x, y, converted.GetLuminanceChannel()); cbChannel.SetPixel(x, y, converted.GetCbChannel()); crChannel.SetPixel(x, y, converted.GetCrChannel()); } } } else { int threadCount = 16; if (height < 500) { threadCount = 4; } else if (height < 1000) { threadCount = 8; } CountdownEvent e = new CountdownEvent(1); for (int i = 0; i < height; i += height / threadCount) { e.AddCount(); ThreadPool.QueueUserWorkItem( state => { object[] inp = state as object[]; //Console.WriteLine($"Thread with row {(int) inp[0]} to row {(int) inp[1]} started..."); int upper = (int)inp[1]; for (int row = (int)inp[0]; row < upper; row++) { for (int x = 0; x < rgbImage.GetWidth(); x++) { YCbCr converted = ConvertRgbtoYCbCr(rgbImage.GetRGBAt(x, row)); luminance.SetPixel(x, row, converted.GetLuminanceChannel()); cbChannel.SetPixel(x, row, converted.GetCbChannel()); crChannel.SetPixel(x, row, converted.GetCrChannel()); } } e.Signal(); }, new object[] { i, i + (height / threadCount) }); } e.Signal(); e.Wait(); } Console.WriteLine("Finished RGB to YCbCr conversion in " + stopwatch.ElapsedMilliseconds / 1000d + " seconds"); stopwatch.Stop(); return(new YCbCrImage(luminance, cbChannel, crChannel, rgbImage.GetOriginalWidth(), rgbImage.GetOriginalHeight())); }