Simply3DScan
ScanControl.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Drawing;
5 using System.IO;
6 using System.Linq;
7 using System.Windows.Forms;
8 using AForge.Video.DirectShow;
10 using Configuration;
11 using PointWriter;
12 using SharedObjects;
13 using Syncfusion.Windows.Forms.Tools;
14 
15 namespace Simple3DScan.UI
16 {
20  public partial class ScanControl : UserControl
21  {
22  #region fields
23 
27  protected readonly BackgroundWorker ScanWorker = new BackgroundWorker();
28 
32  protected readonly Information ConfigurationInformation = Singleton<Config>.Instance.Information;
33 
37  public ArduinoCommands Arduino { get; set; }
38 
42  protected readonly Dictionary<string, string> VideoSources = new Dictionary<string, string>();
43 
44  #endregion
45 
46  #region events
47  public delegate void StartScan();
54  public event StartScan StartScanning;
58  public delegate void StopScan();
62  public event StopScan StopScanning;
63  #endregion
64 
65  #region Constructor
66 
70  [Log]
71  [LogException]
72  public ScanControl()
73  {
74  this.InitializeComponent();
75  }
76 
77  #endregion
78 
79  #region load
80 
81  [Log]
82  [LogException]
83  private void ScanControl_Load(object sender, EventArgs e)
84  {
85  if(!this.DesignMode)
86  this.InitiateCameraDropdown();
87  }
88 
93  [Log]
94  [LogException]
95  public void Init(ArduinoCommands arduino)
96  {
97  this.Arduino = arduino;
98  this.Arduino.ActivateLaser(false);
99 
100  ButtonRenderer styleRenderer = new ButtonRenderer();
101  this.ToggleButtonCapture.Renderer = styleRenderer;
102 
103  this.RadialSliderPrecision.ValueChanged += this.RadialSliderPrecision_ValueChanged;
104 
105  }
106 
110  [Log]
111  [LogException]
112  protected void InitiateCameraDropdown()
113  {
114  int i = 0;
115  foreach (FilterInfo filterInfo in new FilterInfoCollection(FilterCategory.VideoInputDevice))
116  {
117  this.ComboBoxCameras.Items.Add(filterInfo.Name);
118  this.VideoSources.Add(filterInfo.Name, filterInfo.MonikerString);
119  if (!String.IsNullOrEmpty(this.ConfigurationInformation.Camera.Name) &&
120  filterInfo.Name == this.ConfigurationInformation.Camera.Name)
121  this.ComboBoxCameras.SelectedIndex = i;
122  i++;
123  }
124  }
125 
131  [Log]
132  [LogException]
133  private void buttonRefreshCams_Click(object sender, EventArgs e)
134  {
135  this.ComboBoxCameras.Items.Clear();
136  this.VideoSources.Clear();
137  this.InitiateCameraDropdown();
138  this.ConfigurationInformation.Camera.Name = this.ComboBoxCameras.SelectedItem.ToString();
139  this.ImagingControl.StartImaging(this.ConfigurationInformation.Camera.Name);
140  }
141 
142  #endregion
143 
144  #region dispose
145  [Log]
150  [LogException]
151  protected override void Dispose(bool disposing)
152  {
153  if (disposing)
154  {
155  this.components?.Dispose();
156  }
157  this.ImagingControl.StopImaging();
158 
159  base.Dispose(disposing);
160  }
161  #endregion
162 
163  #region background job
164  [Log]
170  [LogException]
171  protected void ScanWorker_DoWork(object sender, DoWorkEventArgs e)
172  {
173  this.StartScanning?.Invoke();
174  Precision precision = (Precision)e.Argument;
175 
176  string imageFolder = ResetImageFolder(this.ConfigurationInformation);
177 
178  int numberOfTotalSteps;
179  Resolution resolution;
180  GetResolutionAndSteps(precision, this.ConfigurationInformation, out numberOfTotalSteps, out resolution);
181 
182  MoveLaserToLeftStartPosition(this.Arduino, this.ImagingControl, this.ConfigurationInformation);
183 
184  IPointWriter writer;
185  if (!this.InitiateWriter(this.Arduino, this.ConfigurationInformation, out writer))
186  return;
187 
188  if (this.PerformScan(this.Arduino, this.ImagingControl, this.ConfigurationInformation, numberOfTotalSteps, resolution, imageFolder, writer)) return;
189 
190  if (this.ConfigurationInformation.Places.FileFormat == FileFormat.Ascii)
191  this.Arduino.ActivateLaser(false);
192 
193  SavePoints(this, writer, this.ConfigurationInformation);
194  }
195 
201  [LogException]
202  protected void ScanWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
203  {
204  this.RadialGaugeProgress.Value = e.ProgressPercentage;
205  }
206 
212  [Log]
213  [LogException]
214  protected virtual void ScanWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
215  {
216  this.StopScanning?.Invoke();
217 
218  this.ToggleButtonCapture.ToggleState = ToggleButtonState.Inactive;
219  this.ScanWorker.DoWork -= this.ScanWorker_DoWork;
220  this.ScanWorker.ProgressChanged -= this.ScanWorker_ProgressChanged;
221  this.ScanWorker.RunWorkerCompleted -= this.ScanWorker_RunWorkerCompleted;
222  this.Arduino.ActivateLaser(false);
223  }
224 
225  #endregion
226 
227  #region controls
228  [Log]
234  [LogException]
235  protected void ToggleButtonCapture_Click(object sender, EventArgs e)
236  {
237  this.RadialGaugeProgress.Value = 0;
238 
239  if (this.ScanWorker.IsBusy != true)
240  {
241  this.ScanWorker.DoWork += this.ScanWorker_DoWork;
242  this.ScanWorker.ProgressChanged += this.ScanWorker_ProgressChanged;
243  this.ScanWorker.RunWorkerCompleted += this.ScanWorker_RunWorkerCompleted;
244  this.ScanWorker.WorkerReportsProgress = true;
245  this.ScanWorker.WorkerSupportsCancellation = true;
246  this.ScanWorker.RunWorkerAsync((Precision)this.RadialSliderPrecision.Value);
247  }
248  else
249  this.ScanWorker.CancelAsync();
250  }
251 
257  [Log]
258  [LogException]
259  protected void ComboBoxCameras_SelectedIndexChanged(object sender, EventArgs e)
260  {
261  if (!this.VideoSources.ContainsKey(this.ComboBoxCameras.SelectedItem.ToString()))
262  return;
263 
264  this.ConfigurationInformation.Camera.Name = this.ComboBoxCameras.SelectedItem.ToString();
265  this.ConfigurationInformation.Camera.Moniker = this.VideoSources[this.ComboBoxCameras.SelectedItem.ToString()];
266 
267  this.SetMaxFrameSizes(this.ConfigurationInformation.Camera.Moniker);
268 
269  this.ImagingControl.LaserMotorEnabled = this.ConfigurationInformation.Laser.MotorEnabled;
270  this.ImagingControl.LaserLeftPosition = this.ConfigurationInformation.Laser.SwipeMin * this.ConfigurationInformation.Camera.Width / 100;
271  this.ImagingControl.LaserRightPosition = this.ConfigurationInformation.Laser.SwipeMax * this.ConfigurationInformation.Camera.Width / 100;
272 
273  this.ImagingControl.StartImaging(this.ConfigurationInformation.Camera.Name);
274  }
275 
276  [Log]
277  [LogException]
278  private void SetMaxFrameSizes(string monikerString)
279  {
280  VideoCaptureDevice source = new VideoCaptureDevice(monikerString);
281 
282  if (source.VideoCapabilities.Length > 0)
283  {
284  VideoCapabilities max = source.VideoCapabilities.OrderBy(p => p.FrameSize.Width).Last();
285  source.VideoResolution = max;
286  }
287  if (null != source.VideoResolution)
288  {
289  this.ConfigurationInformation.Camera.Height = source.VideoResolution.FrameSize.Height;
290  this.ConfigurationInformation.Camera.Width = source.VideoResolution.FrameSize.Width;
291  }
292  }
293 
294  #endregion
295 
296  #region scan
297 
309  [Log]
310  [LogException]
311  protected IEnumerable<ColorPoint3D> ScanImage(int actualSteps, string imageFolder, int steps, int sweep, ArduinoCommands arduino, CameraControl imaging, Information configuration)
312  {
313  Image image;
314  Image imageOff = null;
315  List<ColorPoint3D> points = new List<ColorPoint3D>();
316 
317  if (!configuration.Laser.MotorEnabled)
318  {
319  if (configuration.Places.FileFormat == FileFormat.Pcd)
320  {
321  arduino.ActivateLaser(false);
322 
323  image = imaging.GetNextPicture();
324 
325  imageOff = (Image) image.Clone();
326  imageOff.SaveImage(imageFolder, "OffLaserLight", actualSteps, configuration); // for autodesk 123d
327 
328  arduino.ActivateLaser();
329  }
330 
331  image = imaging.GetNextPicture();
332 
333  if (configuration.Places.FileFormat == FileFormat.Pcd)
334  arduino.ActivateLaser(false);
335 
336  image.SaveImage(imageFolder, "OnLaserLight", actualSteps, configuration);
337 
338  image = TransformImage.CreateGrayImageOfLaser((Bitmap) image, configuration.Filter);
339  image.SaveImage(imageFolder, "LaserLight", actualSteps, configuration);
340 
341  Image skeletonImage = TransformImage.SimpleSkeletonizationImage((Bitmap) image);
342  skeletonImage.SaveImage(imageFolder, "Skeleton", actualSteps, configuration);
343 
344  points = TransformImage.TransformStepImage(skeletonImage, imageOff, actualSteps,
345  configuration.Motor.MicroStepsEnabled, configuration);
346  }
347 
348  if (configuration.Laser.MotorEnabled)
349  {
350  if (configuration.Places.FileFormat == FileFormat.Pcd)
351  arduino.ActivateLaser();
352 
353  image = imaging.GetNextPicture();
354 
355  float actualX = TransformImage.GetLaserLinePosition(image, configuration.Filter);
356  bool swipeRight = actualX <= configuration.Laser.SwipeMin*configuration.Camera.Width/100;
357 
358  if (swipeRight)
359  {
360  while (TransformImage.GetLaserLinePosition(image, configuration.Filter) <
361  configuration.Laser.SwipeMax*configuration.Camera.Width/100)
362  {
363  if (this.ScanWorker.CancellationPending)
364  return null;
365 
366  arduino.RotateLaserCw(sweep);
367 
368  image = CaptureSweepImage(actualSteps, imaging, configuration, ref points);
369  }
370  }
371  else
372  {
373  while (TransformImage.GetLaserLinePosition(image, configuration.Filter) >
374  configuration.Laser.SwipeMin*configuration.Camera.Width/100)
375  {
376  if (this.ScanWorker.CancellationPending)
377  return null;
378 
379  arduino.RotateLaserCcw(sweep);
380 
381  image = CaptureSweepImage(actualSteps, imaging, configuration, ref points);
382  }
383  }
384  }
385  arduino.RotateTurnTableCw(steps);
386 
387  return points;
388  }
389 
390  [LogException]
391  private static Image CaptureSweepImage(int actualSteps, CameraControl imaging, Information configuration, ref List<ColorPoint3D> points)
392  {
393  Image image = imaging.GetNextPicture();
394  image = TransformImage.CreateGrayImageOfLaser((Bitmap)image, configuration.Filter);
395  Image skeletonImage = TransformImage.SimpleSkeletonizationImage((Bitmap)image);
396 
397  points.AddRange(TransformImage.TransformStepImage(skeletonImage, null, actualSteps,
398  configuration.Motor.MicroStepsEnabled, configuration));
399 
400  image = imaging.GetNextPicture();
401  return image;
402  }
403 
415  [Log]
416  [LogException]
417  protected bool PerformScan(ArduinoCommands arduino, CameraControl cameraControl, Information configuration, int numberOfTotalSteps, Resolution resolution, string imageFolder, IPointWriter writer)
418  {
419  for (int actualSteps = 0; actualSteps <= numberOfTotalSteps; actualSteps += resolution.Steps)
420  {
421  if (this.ScanWorker.CancellationPending)
422  return true;
423 
424  int percentage = actualSteps*100/numberOfTotalSteps;
425 
426  IEnumerable<ColorPoint3D> points = this.ScanImage(actualSteps, imageFolder, resolution.Steps, resolution.SweepSteps, arduino, cameraControl, configuration);
427 
428  if(null != points)
429  foreach (ColorPoint3D point in points)
430  writer.AddPoint(point);
431 
432  this.ScanWorker.ReportProgress(percentage);
433  }
434  return false;
435  }
436 
437  #endregion
438 
439  #region laser
440 
447  [Log]
448  [LogException]
449  protected static void MoveLaserToLeftStartPosition(ArduinoCommands arduino, CameraControl cameraControl, Information configuration)
450  {
451  if (!configuration.Laser.MotorEnabled)
452  return;
453  arduino.ActivateLaser();
454 
455  float actualX = TransformImage.GetLaserLinePosition(cameraControl.GetNextPicture(), configuration.Filter);
456 
457  while (actualX > configuration.Laser.SwipeMin*configuration.Camera.Width/100)
458  {
459  arduino.RotateLaserCcw(4);
460  actualX = TransformImage.GetLaserLinePosition(cameraControl.GetNextPicture(), configuration.Filter);
461  }
462  arduino.RotateLaserCcw(4);
463  arduino.ActivateLaser(false);
464  }
465 
466  #endregion
467 
468  #region resolution
469 
477  [Log]
478  [LogException]
479  protected static void GetResolutionAndSteps(Precision precision, Information configuration, out int numberOfTotalSteps, out Resolution resolution)
480  {
481  numberOfTotalSteps = configuration.Motor.MicroStepsEnabled
482  ? configuration.Motor.MicroSteps*configuration.Motor.Steps
483  : configuration.Motor.Steps;
484 
485  resolution = configuration.Resolutions.First(x => x.Precision == precision);
486  }
487 
488  #endregion
489 
490  #region writer
491 
497  [Log]
498  [LogException]
499  protected static string ResetImageFolder(Information configuration)
500  {
501  string imageFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
502  configuration.Places.ImageSubPath);
503 
504  FileHelper.CreatePathIfNotExisting(imageFolder);
505 
506  FileHelper.DeleteAllFilesInFolder(imageFolder);
507  return imageFolder;
508  }
509 
517  [Log]
518  [LogException]
519  protected bool InitiateWriter(ArduinoCommands arduino, Information configuration, out IPointWriter writer)
520  {
521  switch (configuration.Places.FileFormat)
522  {
523  case FileFormat.Ascii:
524  arduino.ActivateLaser();
525  writer = new WriterAsc();
526  break;
527  case FileFormat.Pcd:
528  writer = new WriterPcd();
529  break;
530  default:
531  writer = null;
532  return false;
533  }
534  return true;
535  }
536 
543  [Log]
544  [LogException]
545  protected static void SavePoints(Control control, IPointWriter writer, Information configuration)
546  {
547  control.Invoke((MethodInvoker) delegate
548  {
549  SaveFileDialog saveDialog = new SaveFileDialog();
550  if (!String.IsNullOrEmpty(configuration.Places.ImageSubPath))
551  saveDialog.InitialDirectory = configuration.Places.ImageSubPath;
552 
553  switch (configuration.Places.FileFormat)
554  {
555 
556  case FileFormat.Pcd:
557  saveDialog.DefaultExt = ".PLY";
558  saveDialog.Filter = "PLY (.ply)|*.ply";
559  saveDialog.FileName = "ColoredPoints" + DateTime.Now.ToFileTime();
560  break;
561  default:
562  saveDialog.DefaultExt = ".asc";
563  saveDialog.Filter = "Ascii (.asc)|*.asc";
564  saveDialog.FileName = "Points" + DateTime.Now.ToFileTime();
565  break;
566  }
567 
568  DialogResult result = saveDialog.ShowDialog();
569 
570  if (result != DialogResult.OK)
571  return;
572 
573  string filename = saveDialog.FileName;
574  configuration.Places.LastFilePath = Path.GetDirectoryName(filename);
575  writer.Write(filename);
576  });
577  }
578 
579  #endregion
580 
581  #region start stop
582  [Log]
586  [LogException]
587  internal void Stop()
588  {
589  this.ImagingControl.StopImaging();
590  if (this.ScanWorker.IsBusy)
591  this.ScanWorker.CancelAsync();
592  }
593 
597  [Log]
598  [LogException]
599  internal void Start()
600  {
601  this.ImagingControl.StartImaging(this.ConfigurationInformation.Camera.Name);
602  }
603 
604  private void RadialSliderPrecision_ValueChanged(object sender, RadialSlider.ValueChangedEventArgs args)
605  {
606  this.RadialSliderPrecision.ValueChanged -= this.RadialSliderPrecision_ValueChanged;
607 
608  int testValue = (int)Math.Round(this.RadialSliderPrecision.Value);
609  this.RadialSliderPrecision.Value = testValue;
610 
611  this.RadialSliderPrecision.ValueChanged += this.RadialSliderPrecision_ValueChanged;
612  }
613  #endregion
614  }
615 }
static void CreatePathIfNotExisting(string folder)
Creates the path if not existing.
Definition: FileHelper.cs:14
Filter Filter
Gets or sets the filter.
Definition: Information.cs:89
FileFormat FileFormat
Gets or sets the file format.
Definition: Places.cs:46
ScanControl()
Initializes a new instance of the ScanControl class.
Definition: ScanControl.cs:72
Configuration of a scan resulution
Definition: Resolution.cs:10
void ToggleButtonCapture_Click(object sender, EventArgs e)
Handles the Click event of the toggleButtonCapture control.
Definition: ScanControl.cs:235
Class for detecting an arduino and sending commands to it
Camera Camera
Gets or sets the camera.
Definition: Information.cs:24
string LastFilePath
Gets or sets the last file path.
Definition: Places.cs:22
void RotateLaserCw(int steps)
Rotates the laser clockwise.
static float GetLaserLinePosition(Image laserImage, Filter filter)
Gets the laser line position.
void Start()
Starts this instance.
Definition: ScanControl.cs:599
void ScanWorker_DoWork(object sender, DoWorkEventArgs e)
Handles the DoWork event of the scanWorker control.
Definition: ScanControl.cs:171
void Init(ArduinoCommands arduino)
Initializes the control.
Definition: ScanControl.cs:95
Class holding configuration to access an arduino
Definition: Arduino.cs:7
static string ResetImageFolder(Information configuration)
Resets the image folder.
Definition: ScanControl.cs:499
override void Dispose(bool disposing)
Verwendete Ressourcen bereinigen.
Definition: ScanControl.cs:151
Class holding the configuration information
Definition: Information.cs:8
void Write(string fileName)
Writes to specified file name.
int Steps
Gets or sets the steps.
Definition: Resolution.cs:33
Laser Laser
Gets or sets the laser.
Definition: Information.cs:17
static void MoveLaserToLeftStartPosition(ArduinoCommands arduino, CameraControl cameraControl, Information configuration)
Moves the laser to left start position.
Definition: ScanControl.cs:449
static Bitmap CreateGrayImageOfLaser(Bitmap image, Filter filter)
Creates the gray image of laser.
float SwipeMax
Gets or sets the swipe maximum.
Definition: Laser.cs:52
static Bitmap SimpleSkeletonizationImage(Bitmap bitmap)
Skeletonization for image.
string ImageSubPath
Gets or sets the image sub path.
Definition: Places.cs:38
Control for accessing a camera
void AddPoint(ColorPoint3D point)
Adds the point.
bool MicroStepsEnabled
Gets or sets a value indicating whether [micro steps enabled].
Definition: Motor.cs:31
Class for creating a singleton for a generic class
Definition: Singleton.cs:9
static List< ColorPoint3D > TransformStepImage(Image skeletonImage, Image colorImage, int step, bool microSteps, Information configuration)
Transforms the step image.
static File Helpers
Definition: FileHelper.cs:8
Write Points to PCD file
Definition: WriterPcd.cs:26
void InitiateCameraDropdown()
Initiates the camera dropdown.
Definition: ScanControl.cs:112
IEnumerable< ColorPoint3D > ScanImage(int actualSteps, string imageFolder, int steps, int sweep, ArduinoCommands arduino, CameraControl imaging, Information configuration)
Scans the image.
Definition: ScanControl.cs:311
void ComboBoxCameras_SelectedIndexChanged(object sender, EventArgs e)
Handles the SelectedIndexChanged event of the comboBoxCameras control.
Definition: ScanControl.cs:259
void RotateTurnTableCw(int steps)
Rotates the turn table clockwise.
Places Places
Gets or sets the places.
Definition: Information.cs:59
Just a class for a special style of the toogle buttons
FileFormat
File output format
Definition: FileFormat.cs:6
Control for 3d Scanning
Definition: ScanControl.cs:20
static T Instance
Gets the instance.
Definition: Singleton.cs:27
void ActivateLaser(bool on=true)
Activates the laser.
Does transformations of an image
int MicroSteps
Gets or sets the number of micro steps.
Definition: Motor.cs:24
Image GetNextPicture()
Gets the next picture.
void RotateLaserCcw(int steps)
Rotates the laser counter clockwise.
bool PerformScan(ArduinoCommands arduino, CameraControl cameraControl, Information configuration, int numberOfTotalSteps, Resolution resolution, string imageFolder, IPointWriter writer)
Performs the scan.
Definition: ScanControl.cs:417
List< Resolution > Resolutions
Gets or sets the resolutions.
Definition: Information.cs:67
Interface for writing points to file
Definition: IPointWriter.cs:8
int Width
Gets or sets the width.
Definition: Camera.cs:38
void ScanWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
Handles the ProgressChanged event of the ScanWorker control.
Definition: ScanControl.cs:202
static void DeleteAllFilesInFolder(string imageFolder)
Deletes all files in folder.
Definition: FileHelper.cs:26
Write Points to Asc file
Definition: WriterAsc.cs:13
System.Drawing.Image Image
int SweepSteps
Gets or sets the sweep steps.
Definition: Resolution.cs:41
static void GetResolutionAndSteps(Precision precision, Information configuration, out int numberOfTotalSteps, out Resolution resolution)
Gets the resolution and steps.
Definition: ScanControl.cs:479
Motor Motor
Gets or sets the motor.
Definition: Information.cs:52
StartScan StartScanning
Occurs when [start scanning].
Definition: ScanControl.cs:54
Precision
Information about the precision of a scan
Definition: Precision.cs:6
int Steps
Gets or sets the number of steps.
Definition: Motor.cs:16
float SwipeMin
Gets or sets the swipe minimum.
Definition: Laser.cs:45
static void SavePoints(Control control, IPointWriter writer, Information configuration)
Saves the points.
Definition: ScanControl.cs:545
StopScan StopScanning
Occurs when [stop scanning].
Definition: ScanControl.cs:62
virtual void ScanWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
Handles the RunWorkerCompleted event of the ScanWorker control.
Definition: ScanControl.cs:214
void Stop()
Stops this instance.
Definition: ScanControl.cs:587
bool MotorEnabled
Gets or sets a value indicating whether [motor enabled].
Definition: Laser.cs:59
bool InitiateWriter(ArduinoCommands arduino, Information configuration, out IPointWriter writer)
Initiates the writer.
Definition: ScanControl.cs:519