protected override void DoCompareFrames(FrameTransition transition)
        {
            RGBData frame1 = transition.Frame1;
            RGBData frame2 = transition.Frame2;
            int     index  = transition.Index;

            if (outputImageData == null)
            {
                outputImageData = new ImageData(new Bitmap(frames, frame1.Rows * 3));
                outputImageData.Lock();
            }

            for (int i = 0; i < frame1.Rows; i++)
            {
                outputImageData.Data.SetR(counter, i, frame1.GetR(frame1.Columns / 4, i));
                outputImageData.Data.SetG(counter, i, frame1.GetG(frame1.Columns / 4, i));
                outputImageData.Data.SetB(counter, i, frame1.GetB(frame1.Columns / 4, i));

                outputImageData.Data.SetR(counter, i + frame1.Rows, frame1.GetR(frame1.Columns / 2, i));
                outputImageData.Data.SetG(counter, i + frame1.Rows, frame1.GetG(frame1.Columns / 2, i));
                outputImageData.Data.SetB(counter, i + frame1.Rows, frame1.GetB(frame1.Columns / 2, i));

                outputImageData.Data.SetR(counter, i + frame1.Rows * 2, frame1.GetR(frame1.Columns * 3 / 4, i));
                outputImageData.Data.SetG(counter, i + frame1.Rows * 2, frame1.GetG(frame1.Columns * 3 / 4, i));
                outputImageData.Data.SetB(counter, i + frame1.Rows * 2, frame1.GetB(frame1.Columns * 3 / 4, i));
            }
        }
        public Task <double[]> Calculate(IVideoData data)
        {
            Func <double[]> func = () =>
            {
                frameCount = data.FrameCount;
                DoInitialize(frameCount);

                completed    = 0;
                maxFrameLock = new Semaphore(maxOpenFrames, maxOpenFrames);
                completeLock = new Semaphore(1, 1);
                completeLock.WaitOne();
                data.CurrentFrame = 0;

                RGBData   frame1 = null;
                ImageData data1  = data.GetNextFrame();
                if (data1 != null)
                {
                    data1.Lock();
                    frame1 = data1.Data;
                }

                RGBData   frame2 = null;
                ImageData data2  = data.GetNextFrame();
                if (data2 != null)
                {
                    data2.Lock();
                    frame2 = data2.Data;
                }

                int counter = 0;
                while (data2 != null)
                {
                    maxFrameLock.WaitOne();
                    FrameTransition frameTransition = new FrameTransition(frame1, frame2, counter++);

                    ThreadPool.QueueUserWorkItem(new WaitCallback((state) =>
                    {
                        DoCompareFrames(frameTransition);

                        maxFrameLock.Release();

                        Interlocked.Increment(ref completed);
                        if (completed >= frameCount - 1)
                        {
                            completeLock.Release();
                        }
                    }));

                    frame1 = frame2;

                    data2 = data.GetNextFrame();
                    if (data2 != null)
                    {
                        data2.Lock();
                        frame2 = data2.Data;
                    }
                }

                completeLock.WaitOne();
                double[] results = DoComputeData();
                completeLock.Release();

                return(results);
            };

            return(Task <double[]> .Run(func));
        }