context: /*Automated Rodent Tracker - A program to automatically track rodents
  Copyright(C) 2015 Brett Michael Hewitt
  
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program.If not, see<http://www.gnu.org/licenses/>.*/
  
  using System;
  using System.Collections.Generic;
  using System.Drawing;
  using System.Linq;
  using System.Windows.Media.Imaging;
  using AutomatedRodentTracker.Commands;
  using AutomatedRodentTracker.Extensions;
  using AutomatedRodentTracker.Services.FileBrowser;
  using Emgu.CV;
  using Emgu.CV.Structure;
  using AutomatedRodentTracker.Services.ImageToBitmapSource;
  using AutomatedRodentTracker.ViewModel;
  
  namespace AutomatedRodentTracker.ViewModel.HoughLinesTest
  {
      public class HoughLinesViewModel : WindowViewModelBase
      {
          private ActionCommand m_OpenCommand;
  
          public ActionCommand OpenCommand
          {
              get
              {
                  return m_OpenCommand ?? (m_OpenCommand = new ActionCommand()
                  {
                      ExecuteAction = OpenImage,
                  });
              }
          }
  
          private ActionCommand m_SaveCommand;
  
          public ActionCommand SaveCommand
          {
              get
              {
                  return m_SaveCommand ?? (m_SaveCommand = new ActionCommand()
                  {
                      ExecuteAction = Save
                  });
              }
          }
  
          private double m_DistanceResolution;
          private double m_AngleResolution;
          private int m_Threshold;
          private double m_MinLineWidth;
          private double m_GapBetweenLines;
          private Image<Gray, Byte> m_MainImage;
          private BitmapSource m_DisplayImage;
          private BitmapSource m_DisplayImage2;
          private BitmapSource m_DisplayImage3;
  
          public double DistanceResolution
          {
              get
              {
                  return m_DistanceResolution;
              }
              set
              {
                  if (Equals(m_DistanceResolution, value))
                  {
                      return;
                  }
  
                  m_DistanceResolution = value;
  
                  NotifyPropertyChanged();
                  UpdateImage();
              }
          }
  
          public double AngleResolution
          {
              get
              {
                  return m_AngleResolution;
              }
              set
              {
                  if (Equals(m_AngleResolution, value))
                  {
                      return;
                  }
  
                  m_AngleResolution = value;
  
                  NotifyPropertyChanged();
                  UpdateImage();
              }
          }
  
          public int Threshold
          {
              get
              {
                  return m_Threshold;
              }
              set
              {
                  if (Equals(m_Threshold, value))
                  {
                      return;
                  }
  
                  m_Threshold = value;
  
                  NotifyPropertyChanged();
                  UpdateImage();
              }
          }
  
          public double MinLineWidth
          {
              get
              {
                  return m_MinLineWidth;
              }
              set
              {
                  if (Equals(m_MinLineWidth, value))
                  {
                      return;
                  }
  
                  m_MinLineWidth = value;
  
                  NotifyPropertyChanged();
                  UpdateImage();
              }
          }
  
          public double GapBetweenLines
          {
              get
              {
                  return m_GapBetweenLines;
              }
              set
              {
                  if (Equals(m_GapBetweenLines, value))
                  {
                      return;
                  }
  
                  m_GapBetweenLines = value;
  
                  NotifyPropertyChanged();
                  UpdateImage();
              }
          }
  
          public Image<Gray, Byte> MainImage
          {
              get
              {
                  return m_MainImage;
              }
              set
              {
                  if (ReferenceEquals(m_MainImage, value))
                  {
                      return;
                  }
  
                  if (m_MainImage != null)
                  {
                      m_MainImage.Dispose();
                  }
  
                  m_MainImage = value;
  
                  NotifyPropertyChanged();
                  UpdateImage();
              }
          }
  
          public BitmapSource DisplayImage
          {
              get
              {
                  return m_DisplayImage;
              }
              set
              {
                  if (ReferenceEquals(m_DisplayImage, value))
                  {
                      return;
                  }
  
                  m_DisplayImage = value;
  
                  NotifyPropertyChanged();
              }
          }
  
          public BitmapSource DisplayImage2
          {
              get
              {
                  return m_DisplayImage2;
              }
              set
              {
                  if (ReferenceEquals(m_DisplayImage2, value))
                  {
                      return;
                  }
  
                  m_DisplayImage2 = value;
  
                  NotifyPropertyChanged();
              }
          }
  
          public BitmapSource DisplayImage3
          {
              get
              {
                  return m_DisplayImage3;
              }
              set
              {
                  if (ReferenceEquals(m_DisplayImage3, value))
                  {
                      return;
                  }
  
                  m_DisplayImage3 = value;
  
                  NotifyPropertyChanged();
              }
          }
  
          public HoughLinesViewModel()
          {
              DistanceResolution = 1;
              AngleResolution = 45;
              Threshold = 20;
              MinLineWidth = 5;
              GapBetweenLines = 40;
              Random = new Random();
          }
  
          private void OpenImage()
          {
              string image = FileBrowser.BrowseForImageFiles();
  
              if (string.IsNullOrWhiteSpace(image))
              {
                  return;
              }
  
              MainImage = new Image<Gray, byte>(image);
          }
  
          Image<Gray, Byte> SaveImage
          {
              get;
              set;
          }
  
          private void UpdateImage()
          {
              const int iterations = 1;
  
              if (MainImage == null)
              {
                  return;
              }
  
              Image<Gray, Byte> testImage;
  
              using (Image<Gray, Byte> dilate1 = MainImage.Dilate(iterations))
              using (Image<Gray, Byte> erode1 = dilate1.Erode(iterations))
              using (Image<Gray, Byte> dilate2 = erode1.Dilate(iterations))
              using (Image<Gray, Byte> erode2 = dilate2.Erode(iterations))
              using (Image<Gray, Byte> dilate3 = erode2.Dilate(iterations))
              using (Image<Gray, Byte> erode3 = dilate3.Erode(iterations))
              {
                  testImage = erode3.Clone();
                  DisplayImage = ImageService.ToBitmapSource(testImage);
                  //DisplayImage2 = ImageService.ToBitmapSource(MainImage);
              }
  
              LineSegment2D[] lines = CvInvoke.HoughLinesP(testImage,
                     DistanceResolution, //Distance resolution in pixel-related units
                     Math.PI / AngleResolution, //Angle resolution measured in radians.
                     Threshold, //threshold
                     MinLineWidth, //min Line width
                     GapBetweenLines); //gap between lines
  
              FindSpine(lines, RotatedRect.Empty, testImage);
              using (Image<Bgr, Byte> moddedImage = testImage.Convert<Bgr, Byte>())
              {
                  SaveImage = new Image<Gray, byte>(moddedImage.Width, moddedImage.Height, new Gray(0));
                  foreach (var line in lines)
                  {
                      moddedImage.Draw(line, new Bgr(Color.Aqua), 2);
                      SaveImage.Draw(line, new Gray(255), 1);
                  }
  
                  DisplayImage2 = ImageService.ToBitmapSource(moddedImage);
              }
          }
  
          private void FindSpine(LineSegment2D[] lines, RotatedRect rotatedRectangle, Image<Gray, Byte> img)
          {
              LineSegment2DF[] initialLines = new LineSegment2DF[2];
  
              if (!rotatedRectangle.Size.IsEmpty)
              {
                  //Use one of the smaller boundries from rotatedRect for initial detection
                  PointF[] vertices = rotatedRectangle.GetVertices();
                  PointF p1 = vertices[0];
                  PointF p2 = vertices[1];
                  PointF p3 = vertices[2];
                  PointF p4 = vertices[3];
  
  
gt:                 if (p2.DistanceSquared(p1) < p2.DistanceSquared(p3))