using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Text.RegularExpressions; using System.IO; using System.Collections; using System.Windows.Forms; namespace VisualIntelligentScissors { public partial class frmMain : Form { private GrayBitmap image = new GrayBitmap(); private StopWatch timer = new StopWatch(); public static readonly string SegmentPointRegex = @"\((\d+), *(\d+)\)"; public frmMain() { InitializeComponent(); } private void Form1_Shown(object sender, EventArgs e) { btnOpenFile_Click(this, null); } private void btnSaveFile_Click(object sender, EventArgs e) { if (image.Bitmap == null) { MessageBox.Show("No image loaded to save."); return; } if (saveFileDialog1.ShowDialog() != DialogResult.OK) return; using (Stream s = saveFileDialog1.OpenFile()) image.Bitmap.Save(s, System.Drawing.Imaging.ImageFormat.Png); } /// /// Gets/sets the status text to appear in the toolstrip at the /// bottom (status bar). /// public string Status { get { return lblStatus.Text == "Idle" ? null : lblStatus.Text; } set { lblStatus.Text = value == null ? "Idle" : value; } } public void RefreshImage() { boxImage.Refresh(); boxGradient.Refresh(); } private void BackgroundProcess_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar.Value = e.ProgressPercentage; } #region File opening operation private void btnOpenFile_Click(object sender, EventArgs e) { DialogResult result = openFileDialog1.ShowDialog(); // see if user selected a file. if (result != DialogResult.OK) return; UseWaitCursor = true; Status = "Loading image"; Application.DoEvents(); // Allow time for wait cursor to turn on try { // clear the segmentation points box. tbSegmentPoints.Text = "Click image to add segmentation points"; // Disable opening another file until this one is done. btnOpenFile.Enabled = false; // Load the data file. FileLoader.RunWorkerAsync(new FileLoadingParams(openFileDialog1.FileName)); } finally { UseWaitCursor = false; } } struct FileLoadingParams { public FileLoadingParams(string fileName) { FileName = fileName; } public readonly string FileName; } struct FileLoadingResult { public FileLoadingResult(Exception ex) { this.Exception = ex; this.SegmentationPoints = null; this.GrayImage = null; } public FileLoadingResult(GrayBitmap grayImage, string segmentationPoints) { this.GrayImage = grayImage; this.SegmentationPoints = segmentationPoints; this.Exception = null; } public readonly GrayBitmap GrayImage; public readonly string SegmentationPoints; public readonly Exception Exception; } private void FileLoader_DoWork(object sender, DoWorkEventArgs e) { FileLoadingParams fileLoadingParams = (FileLoadingParams)e.Argument; timer.Start(); GrayBitmap img = new GrayBitmap(); string segmentationPoints; using (Stream file = File.OpenRead(fileLoadingParams.FileName)) img.Load(file, out segmentationPoints, new ProgressCallback(FileLoader.ReportProgress)); timer.Stop(); e.Result = new FileLoadingResult(img, segmentationPoints); } private void FileLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { FileLoadingResult result = (FileLoadingResult)e.Result; Status = null; lblLastOperationTime.Text = timer.Elapsed.ToString(); if (result.GrayImage != null) { image = result.GrayImage; tbSegmentPoints.Text = result.SegmentationPoints; // Display the image. boxImage.BackgroundImage = image.Bitmap; boxImage.Image = PrepareOverlay(); boxGradient.BackgroundImage = image.Gradient.Bitmap; boxGradient.Image = boxImage.Image; // Enable toolbar buttons //btnShowGradient.Enabled = true; btnSaveFile.Enabled = true; // Size the application window appropriately. Width += boxImage.BackgroundImage.Width - boxImage.Width; Height += boxImage.BackgroundImage.Height - boxImage.Height; // Start generating the gradient right away GenerateGradient(); tabControl1.SelectTab(tabImage); } else if (result.Exception != null) { if (MessageBox.Show(this, result.Exception.ToString(), "Error during image load.", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Retry) GenerateGradient(); } } #endregion #region Gradient generating mechanism private void GenerateGradient() { if (GradientGenerator.IsBusy) return; Status = "Generating gradient image"; GradientGenerator.RunWorkerAsync(image.Clone()); } private void GradientGenerator_DoWork(object sender, DoWorkEventArgs e) { GrayBitmap asyncImage = (GrayBitmap)e.Argument; try { if (asyncImage.Gradient.Bitmap == null) { // Don't step through this code with an Locals or Auto // window opened at all. VS will crash the background thread. timer.Start(); asyncImage.Gradient.GenerateGradientBitmap(new ProgressCallback(GradientGenerator.ReportProgress)); timer.Stop(); e.Result = asyncImage.Gradient; } } catch (Exception ex) { e.Result = ex; } finally { asyncImage.Bitmap.Dispose(); } } private void GradientGenerator_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { btnOpenFile.Enabled = true; // re-enable loading files Status = null; lblLastOperationTime.Text = timer.Elapsed.ToString(); if (e.Result is GradientBitmap) { boxGradient.BackgroundImage = ((GradientBitmap)e.Result).Bitmap; image.Gradient = ((GradientBitmap)e.Result); boxGradient.Refresh(); btnScissors.Enabled = true; } else if (e.Result is Exception) { if (MessageBox.Show(this, e.Result.ToString(), "Error during gradient generation", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Retry) GenerateGradient(); } } #endregion #region Segmentation point handling private Bitmap overlay; private Image PrepareOverlay() { return overlay = new Bitmap(boxImage.BackgroundImage.Width, boxImage.BackgroundImage.Height); } private void imgBox_MouseClick(object sender, MouseEventArgs e) { if (image.Bitmap == null) return; // no image loaded to operate against. // write the current mouse location into the image // segmation point list text box. This can be cut and // pasted into a comment in a pgm file. if (!tbSegmentPoints.Text.Contains("(")) tbSegmentPoints.Text = ("(" + e.X + ", " + e.Y + ")"); else tbSegmentPoints.AppendText("; (" + e.X + ", " + e.Y + ")"); overlay.SetPixel(e.X, e.Y, Color.White); RefreshImage(); } private IList GetPoints() { MatchCollection mc = Regex.Matches(tbSegmentPoints.Text, SegmentPointRegex); List list = new List(mc.Count); foreach (Match m in mc) list.Add(new Point(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value))); return list; } private void btnCopyPointsToClipboard_Click(object sender, EventArgs e) { tbSegmentPoints.Copy(); } private void btnClearPoints_Click(object sender, EventArgs e) { tbSegmentPoints.Clear(); } #endregion #region Scissor operations private void UseScissors(Scissors scissors, Pen pen) { if (scissors == null) throw new ArgumentNullException("scissors"); if (image.Gradient.Bitmap == null) throw new InvalidOperationException("Cannot use scissors until gradient is calculated."); UseWaitCursor = true; Application.DoEvents(); // Allow time for wait cursor to turn on tryagain: try { scissors.Image = image; scissors.Overlay = overlay; Status = "Tracing"; timer.Start(); scissors.Trace(GetPoints(), pen); timer.Stop(); Status = null; lblLastOperationTime.Text = timer.Elapsed.ToString(); Refresh(); } catch (Exception ex) { Status = "Tracing error"; if (MessageBox.Show(this, ex.ToString(), "Error during scissor operation", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Retry) goto tryagain; } finally { UseWaitCursor = false; } } private void btnStraightScissors_Click(object sender, EventArgs e) { UseScissors(new StraightScissors(), Pens.Red); } private void btnSimpleScissors_Click(object sender, EventArgs e) { UseScissors(new SimpleScissors(), Pens.Orange); } private void btnIntelligentScissors_Click(object sender, EventArgs e) { UseScissors(new DijkstraScissors(), Pens.Green); } private void btnScissors_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) { btnScissors.Text = e.ClickedItem.Text; btnScissors.Tag = e.ClickedItem; } private void btnScissors_ButtonClick(object sender, EventArgs e) { if (btnScissors.Tag == btnStraightScissors) btnStraightScissors_Click(sender, e); else if (btnScissors.Tag == btnSimpleScissors) btnSimpleScissors_Click(sender, e); else if (btnScissors.Tag == btnIntelligentScissors) btnIntelligentScissors_Click(sender, e); else btnScissors.ShowDropDown(); } #endregion } }