public Bitmap RenderFrame(LinePairCollection lines, Bitmap startImage, Bitmap endImage, double percent)
 {
     using (FastBitmap fastStartImage = new FastBitmap(startImage))
         using (FastBitmap fastEndImage = new FastBitmap(endImage)) {
             return(RenderFrame(lines, fastStartImage, fastEndImage, percent));
         }
 }
Пример #2
0
        private void ConfigurePictureBoxes(LinePairCollection lines, Image startImage, Image endImage)
        {
            // The lines collection stores the line pairs.  Configure the start image to selec the 0th line from each pair.
            pbStartImage.LinePairs   = _lines;
            pbStartImage.ImageNumber = 0;
            pbStartImage.Image       = startImage;

            // ... and configure the start image to selec the 0th line from each pair.
            pbEndImage.LinePairs   = _lines;
            pbEndImage.ImageNumber = 1;
            pbEndImage.Image       = endImage;

            if (autoSizeToolStripMenuItem.Checked)
            {
                pbStartImage.Dock     = DockStyle.None;
                pbStartImage.SizeMode = PictureBoxSizeMode.AutoSize;
                pbEndImage.Dock       = DockStyle.None;
                pbEndImage.SizeMode   = PictureBoxSizeMode.AutoSize;
            }
            else if (zoomToolStripMenuItem.Checked)
            {
                pbStartImage.Dock     = DockStyle.Fill;
                pbStartImage.SizeMode = PictureBoxSizeMode.Zoom;
                pbEndImage.Dock       = DockStyle.Fill;
                pbEndImage.SizeMode   = PictureBoxSizeMode.Zoom;
            }

            btnMorph.Enabled = pbStartImage.Image != null && pbEndImage.Image != null;

            pbStartImage.Refresh();
            pbEndImage.Refresh();
        }
        /// <summary>Create the morphed images and video.</summary>
        public void Render(IImageWriter imageWriter, LinePairCollection lines, Bitmap startImageBmp, Bitmap endImageBmp)
        {
            _curFrame = 0;
            double percentagePerFrame = 1.0 / (_options.NumberOfOutputFrames - 1);

            using (Bitmap clonedStart = Utilities.CreateNewBitmapFrom(startImageBmp))
                using (Bitmap clonedEnd = Utilities.CreateNewBitmapFrom(endImageBmp)) {
                    // Write out the starting picture
                    imageWriter.AddFrame(clonedStart);
                    _curFrame = 1;
                    UpdateProgressChanged();

                    using (FastBitmap startImage = new FastBitmap(startImageBmp))
                        using (FastBitmap endImage = new FastBitmap(endImageBmp)) {
                            for (int i = 1; i < _options.NumberOfOutputFrames - 1; i++)
                            {
                                _cancellationToken.ThrowIfCancellationRequested();
                                using (Bitmap frame = RenderFrame(lines, startImage, endImage, percentagePerFrame * i)) {
                                    imageWriter.AddFrame(frame);
                                }
                                _curFrame++;
                                UpdateProgressChanged();
                            }
                        }

                    imageWriter.AddFrame(clonedEnd);
                    _curFrame++;
                    UpdateProgressChanged();
                }
        }
        /// <summary>Gets the X location of a point in the source image for a point X' in the target image.</summary>
        /// <param name="p">The point whose preimage location we need.</param>
        /// <param name="pairs">The morph line pairs used to translate the point.</param>
        /// <returns>The point in the original image.</returns>
        private PointF GetPreimageLocation(PointF p, LinePairCollection pairs)
        {
            if (pairs.Count == 0)
            {
                return(p);
            }

            // Grab settings
            double constA = _options.ConstA;
            double constB = _options.ConstB;
            double constP = _options.ConstP;

            PointF dSum      = PointF.Empty;
            double weightSum = 0;

            foreach (var pair in pairs)
            {
                PointF srcStart = pair.Item1.Item1, srcEnd = pair.Item1.Item2;
                PointF destStart = pair.Item2.Item1, destEnd = pair.Item2.Item2;
                if (srcStart == srcEnd || destStart == destEnd)
                {
                    continue;
                }

                PointF PQ     = SubPoints(destEnd, destStart);
                double length = NormalizePoint(PQ);
                PointF PpQp   = SubPoints(srcEnd, srcStart);
                PointF PX     = SubPoints(p, destStart);

                double u = DotProduct(PX, PQ) / (length * length);
                double v = DotProduct(PX, FlipPerpendicular(PQ)) / length;

                PointF Xp = AddPoints(
                    AddPoints(srcStart, ScalePoint(PpQp, u)),
                    ScalePoint(FlipPerpendicular(PpQp), v / NormalizePoint(PpQp)));

                // Compute shortest distance from X to the line segment PQ
                double dist;
                if (u < 0)
                {
                    dist = NormalizePoint(SubPoints(p, destStart));
                }
                else if (u > 1)
                {
                    dist = NormalizePoint(SubPoints(p, destEnd));
                }
                else
                {
                    dist = Math.Abs(v);
                }

                double strength = Math.Pow(length, constP) / (constA + dist);
                double weight   = (constB == 2.0) ? strength * strength : Math.Pow(strength, constB);
                dSum       = AddPoints(dSum, ScalePoint(SubPoints(Xp, p), weight));
                weightSum += weight;
            }

            return(AddPoints(p, ScalePoint(dSum, 1.0 / weightSum)));
        }
        private Bitmap RenderFrame(LinePairCollection lines, FastBitmap startImage, FastBitmap endImage, double percent)
        {
            var forwardsAndBackwards = InterpolateLines(lines, percent);

            using (Bitmap forward = ComputePreimage(startImage, forwardsAndBackwards.Item1))
                using (Bitmap backward = ComputePreimage(endImage, forwardsAndBackwards.Item2))
                    return(BlendImages(forward, backward, 1 - percent));
        }
Пример #6
0
        private void Form1_Load(object sender, EventArgs e)
        {
            // Create a Task factory to use for targetting the UI thread
            _uiThread = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());

            // Initialize the picture boxes
            _lines = new LinePairCollection();
            ConfigurePictureBoxes(_lines, null, null);

            // Set up the parallel menu item to reflect the number of cores
            parallelProcessingModeToolStripMenuItem.Text += " (" + Environment.ProcessorCount + "x)";
        }
 private void openToolStripMenuItem_Click(object sender, EventArgs e)
 {
     _lines.Selected = null;
     using (OpenFileDialog ofd = new OpenFileDialog()) {
         ofd.Filter = "Morph Files (*.morph)|*.morph|All Files (*.*)|*.*";
         if (ofd.ShowDialog(this) == DialogResult.OK)
         {
             var formatter = new BinaryFormatter();
             using (Stream fileStream = ofd.OpenFile()) {
                 SavedSettings ss = (SavedSettings)formatter.Deserialize(fileStream);
                 _lines         = ss.Lines;
                 _morphSettings = ss.Settings;
                 ConfigurePictureBoxes(_lines, ss.FirstImage, ss.SecondImage);
             }
         }
     }
 }
Пример #8
0
        /// <summary>Generates the output image for a source image and a collection of morph lines.</summary>
        /// <param name="bmp">The input image.</param>
        /// <param name="pairs">The lines used to skew the image.</param>
        /// <returns>The computed image.</returns>
        private unsafe Bitmap ComputePreimage(FastBitmap bmp, LinePairCollection pairs)
        {
            int    width = bmp.Size.Width, height = bmp.Size.Height;
            Bitmap output = new Bitmap(width, height);

            using (FastBitmap fastOut = new FastBitmap(output))
            {
                if (!_useParallelism)
                {
                    for (int j = 0; j < height; j++)
                    {
                        _cancellationToken.ThrowIfCancellationRequested();
                        for (int i = 0; i < width; i++)
                        {
                            PointF     pf       = GetPreimageLocation(new PointF(i, j), pairs);
                            Point      p        = ClampPoint(pf, new Size(width, height));
                            PixelData *inPixel  = bmp[p.X, p.Y];
                            PixelData *outPixel = fastOut[i, j];
                            outPixel->R = inPixel->R;
                            outPixel->G = inPixel->G;
                            outPixel->B = inPixel->B;
                        }
                    }
                }
                else
                {
                    Parallel.For(0, height, new ParallelOptions {
                        CancellationToken = _cancellationToken
                    }, (j, loop) =>
                    {
                        for (int i = 0; i < width; i++)
                        {
                            PointF pf           = GetPreimageLocation(new PointF(i, j), pairs);
                            Point p             = ClampPoint(pf, new Size(width, height));
                            PixelData *inPixel  = bmp[p.X, p.Y];
                            PixelData *outPixel = fastOut[i, j];
                            outPixel->R         = inPixel->R;
                            outPixel->G         = inPixel->G;
                            outPixel->B         = inPixel->B;
                        }
                    });
                }
            }

            return(output);
        }
        /// <summary>Interpolates between the starting and ending morph lines.</summary>
        /// <param name="pairs">The morph lines to interpolate.</param>
        /// <param name="percent">The percent of the way through the morph.</param>
        /// <param name="interpolatedForwards">Resulting interpolated lines for the starting image.</param>
        /// <param name="interpolatedBackwards">Resulting interpolated lines for the ending image.</param>
        private Tuple <LinePairCollection, LinePairCollection> InterpolateLines(
            LinePairCollection pairs, double percent)
        {
            LinePairCollection interpolatedForwards = new LinePairCollection(), interpolatedBackwards = new LinePairCollection();

            foreach (Tuple <Line, Line> pair in pairs)
            {
                // Source line is the same as the original; dest line is the interpolated line
                // Add the new pair to the forwards list and the inverse to the backwards list.
                var newPair = Tuple.Create(
                    new Line(pair.Item1.Item1, pair.Item1.Item2),
                    new Line(
                        AddPoints(pair.Item1.Item1, ScalePoint(SubPoints(pair.Item2.Item1, pair.Item1.Item1), percent)),
                        AddPoints(pair.Item1.Item2, ScalePoint(SubPoints(pair.Item2.Item2, pair.Item1.Item2), percent))
                        ));
                interpolatedForwards.Add(newPair);
                interpolatedBackwards.Add(Tuple.Create(
                                              new Line(pair.Item2.Item1, pair.Item2.Item2),
                                              new Line(newPair.Item2.Item1, newPair.Item2.Item2)));
            }
            return(Tuple.Create(interpolatedForwards, interpolatedBackwards));
        }
Пример #10
0
        private void PrepareUIDataForMorph(
            out UiSettings settings, out LinePairCollection lines,
            out Bitmap newStartImage, out Bitmap newEndImage)
        {
            // Grab UI data
            settings = Utilities.DeepClone(_morphSettings);
            lines    = Utilities.DeepClone(_lines);

            // Get the original iamges
            var origStartImage = (Bitmap)pbStartImage.Image;
            var origEndImage   = (Bitmap)pbEndImage.Image;

            // Get a scale factor from the UI
            float startImageScaleFactor = int.Parse(outputSizeToolStripTextBox.Text) / 100f;

            // Create the starting and ending images.  The starting image is scaled by the UI setting,
            // and the ending image is created to match the starting image's size.
            newStartImage = Utilities.CreateNewBitmapFrom(origStartImage, startImageScaleFactor);
            newEndImage   = Utilities.CreateNewBitmapFrom(origEndImage, newStartImage.Width, newStartImage.Height);

            // Get a scale factor by comparing the new and old ending images
            var endImageScaleFactor = new PointF(
                newEndImage.Width / (float)origEndImage.Width,
                newEndImage.Height / (float)origEndImage.Height);

            // Create new line pairings to cope with the scaling
            var newlineList =
                (from pair in _lines
                 select Tuple.Create(
                     new Line(
                         new PointF(pair.Item1.Item1.X * startImageScaleFactor, pair.Item1.Item1.Y * startImageScaleFactor),
                         new PointF(pair.Item1.Item2.X * startImageScaleFactor, pair.Item1.Item2.Y * startImageScaleFactor)),
                     new Line(
                         new PointF(pair.Item2.Item1.X * endImageScaleFactor.X, pair.Item2.Item1.Y * endImageScaleFactor.Y),
                         new PointF(pair.Item2.Item2.X * endImageScaleFactor.X, pair.Item2.Item2.Y * endImageScaleFactor.Y)))).ToList();

            lines = new LinePairCollection(newlineList);
        }
Пример #11
0
 private void newToolStripMenuItem_Click(object sender, EventArgs e)
 {
     this.Text = "Parallel Morph";
     _lines    = new LinePairCollection();
     ConfigurePictureBoxes(_lines, null, null);
 }