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()));
        }