├── Sound ├── saddness │ ├── sorry.wav │ ├── whyyy.wav │ ├── sorry2.wav │ ├── No_hard_feeling.wav │ ├── I_dont_blame_you.wav │ └── I_did_everything_you_asked.wav ├── startup │ ├── Hello.wav │ ├── Hello2.wav │ ├── Activated.wav │ └── Sentry_Mode_Activated.wav ├── shutdown │ ├── Goodbye.wav │ ├── Naptime.wav │ ├── Goodnight.wav │ ├── Hibernating.wav │ ├── Shutting_Down.wav │ └── Sleep_Mode_Activated.wav ├── detection │ ├── I_See_You.wav │ ├── Target_Aquired.wav │ ├── There_You_Are.wav │ ├── There_You_Are2.wav │ └── Targert_Aquired2.wav └── noDetection │ ├── Canvassing.wav │ ├── Searching.wav │ ├── Searching2.wav │ ├── Target_Lost.wav │ ├── Is_Anyone_There.wav │ └── Are_You_Still_There.wav ├── detectionSettings.json ├── src ├── Program.cs ├── OptionForm.cs ├── OptionForm.Designer.cs ├── VoiceRecog.cs ├── Person_Detector.cs ├── Calibration.cs ├── Calibration.Designer.cs ├── Form1.Designer.cs └── Form1.cs ├── arduino interpreter └── laserInterpreter │ └── laserInterpreter.ino └── README.md /Sound/saddness/sorry.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/saddness/sorry.wav -------------------------------------------------------------------------------- /Sound/saddness/whyyy.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/saddness/whyyy.wav -------------------------------------------------------------------------------- /Sound/startup/Hello.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/startup/Hello.wav -------------------------------------------------------------------------------- /Sound/startup/Hello2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/startup/Hello2.wav -------------------------------------------------------------------------------- /Sound/saddness/sorry2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/saddness/sorry2.wav -------------------------------------------------------------------------------- /Sound/shutdown/Goodbye.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/shutdown/Goodbye.wav -------------------------------------------------------------------------------- /Sound/shutdown/Naptime.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/shutdown/Naptime.wav -------------------------------------------------------------------------------- /Sound/startup/Activated.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/startup/Activated.wav -------------------------------------------------------------------------------- /Sound/detection/I_See_You.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/detection/I_See_You.wav -------------------------------------------------------------------------------- /Sound/shutdown/Goodnight.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/shutdown/Goodnight.wav -------------------------------------------------------------------------------- /Sound/noDetection/Canvassing.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/noDetection/Canvassing.wav -------------------------------------------------------------------------------- /Sound/noDetection/Searching.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/noDetection/Searching.wav -------------------------------------------------------------------------------- /Sound/noDetection/Searching2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/noDetection/Searching2.wav -------------------------------------------------------------------------------- /Sound/shutdown/Hibernating.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/shutdown/Hibernating.wav -------------------------------------------------------------------------------- /Sound/shutdown/Shutting_Down.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/shutdown/Shutting_Down.wav -------------------------------------------------------------------------------- /Sound/detection/Target_Aquired.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/detection/Target_Aquired.wav -------------------------------------------------------------------------------- /Sound/detection/There_You_Are.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/detection/There_You_Are.wav -------------------------------------------------------------------------------- /Sound/detection/There_You_Are2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/detection/There_You_Are2.wav -------------------------------------------------------------------------------- /Sound/noDetection/Target_Lost.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/noDetection/Target_Lost.wav -------------------------------------------------------------------------------- /Sound/saddness/No_hard_feeling.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/saddness/No_hard_feeling.wav -------------------------------------------------------------------------------- /Sound/detection/Targert_Aquired2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/detection/Targert_Aquired2.wav -------------------------------------------------------------------------------- /Sound/noDetection/Is_Anyone_There.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/noDetection/Is_Anyone_There.wav -------------------------------------------------------------------------------- /Sound/saddness/I_dont_blame_you.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/saddness/I_dont_blame_you.wav -------------------------------------------------------------------------------- /Sound/shutdown/Sleep_Mode_Activated.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/shutdown/Sleep_Mode_Activated.wav -------------------------------------------------------------------------------- /Sound/startup/Sentry_Mode_Activated.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/startup/Sentry_Mode_Activated.wav -------------------------------------------------------------------------------- /Sound/noDetection/Are_You_Still_There.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/noDetection/Are_You_Still_There.wav -------------------------------------------------------------------------------- /Sound/saddness/I_did_everything_you_asked.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaelreeves08/face-detection-laser-system/HEAD/Sound/saddness/I_did_everything_you_asked.wav -------------------------------------------------------------------------------- /detectionSettings.json: -------------------------------------------------------------------------------- 1 | {"xShift":0,"yShift":1,"xLeftCalibration":59,"xRightCalibration":120,"yTopCalibration":116,"yBotCalibration":70,"sendSerial":true,"faceRecogOn":true,"figureRecogOn":false,"soundsOn":true} -------------------------------------------------------------------------------- /src/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace Emgu_4._0 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new OptionForm()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /arduino interpreter/laserInterpreter/laserInterpreter.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Servo serX; 4 | Servo serY; 5 | 6 | String tempModify; 7 | 8 | void setup() { 9 | 10 | serX.attach(11); 11 | serY.attach(10); 12 | Serial.begin(9600); 13 | Serial.setTimeout(10); 14 | } 15 | 16 | void loop() { 17 | //lol 18 | } 19 | 20 | void serialEvent() { 21 | tempModify = Serial.readString(); 22 | 23 | serX.write(parseDataX(tempModify)); 24 | serY.write(parseDataY(tempModify)); 25 | 26 | } 27 | 28 | int parseDataX(String data){ 29 | data.remove(data.indexOf(":")); 30 | data.remove(data.indexOf("X"), 1); 31 | 32 | return data.toInt(); 33 | } 34 | 35 | int parseDataY(String data){ 36 | data.remove(0,data.indexOf(":") + 1); 37 | data.remove(data.indexOf("Y"), 1); 38 | 39 | return data.toInt(); 40 | 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/OptionForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace Emgu_4._0 12 | { 13 | public partial class OptionForm : Form 14 | { 15 | Form1 cam; 16 | Calibration cal; 17 | 18 | public OptionForm() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | private void button1_Click(object sender, EventArgs e) 24 | { 25 | if(cal != null) 26 | { 27 | cal.Close(); 28 | } 29 | cam = new Form1(); 30 | cam.Show(); 31 | } 32 | 33 | private void button2_Click(object sender, EventArgs e) 34 | { 35 | if(cam != null) 36 | { 37 | cam.Close(); 38 | } 39 | cal = new Calibration(); 40 | cal.Show(); 41 | 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/OptionForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Emgu_4._0 2 | { 3 | partial class OptionForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.button1 = new System.Windows.Forms.Button(); 32 | this.button2 = new System.Windows.Forms.Button(); 33 | this.SuspendLayout(); 34 | // 35 | // button1 36 | // 37 | this.button1.Location = new System.Drawing.Point(119, 73); 38 | this.button1.Name = "button1"; 39 | this.button1.Size = new System.Drawing.Size(91, 74); 40 | this.button1.TabIndex = 0; 41 | this.button1.Text = "Aut"; 42 | this.button1.UseVisualStyleBackColor = true; 43 | this.button1.Click += new System.EventHandler(this.button1_Click); 44 | // 45 | // button2 46 | // 47 | this.button2.Location = new System.Drawing.Point(236, 73); 48 | this.button2.Name = "button2"; 49 | this.button2.Size = new System.Drawing.Size(91, 74); 50 | this.button2.TabIndex = 1; 51 | this.button2.Text = "Calibrate System"; 52 | this.button2.UseVisualStyleBackColor = true; 53 | this.button2.Click += new System.EventHandler(this.button2_Click); 54 | // 55 | // OptionForm 56 | // 57 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 58 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 59 | this.ClientSize = new System.Drawing.Size(448, 303); 60 | this.Controls.Add(this.button2); 61 | this.Controls.Add(this.button1); 62 | this.Name = "OptionForm"; 63 | this.Text = "OptionForm"; 64 | this.ResumeLayout(false); 65 | 66 | } 67 | 68 | #endregion 69 | 70 | private System.Windows.Forms.Button button1; 71 | private System.Windows.Forms.Button button2; 72 | } 73 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --IMPORTANT-- 2 | This is the repository of the laser project showcased on YouTube. I think it goes without saying, and was evident by my multiple winces on camera, that no one should shoot a laser into their eye. No one should use this technology to inflict bodily harm on themselves or anyone else. That being said, enjoy the repository. 3 | 4 | --Personal Note-- 5 | To be honest, this project started as a joke, but quickly evolved into a personal challenge of ability. I had to tackle a lot of different problems and am 6 | very pleased with the overall outcome. 7 | 8 | 9 | --Summary-- 10 | This software processes incoming video from a live camera and searches for faces or human figures. If a detection is made, the system outputs coordinate data via serial port(1), 11 | which is interpreted by additional software compiled on a microcontroller. The data is parsed and signals are sent to 2 servos arranged in such a way that one carries out the X 12 | value and the other carries out the Y value of the coordinates. A laser is attached to the Y servo so that it points to the position of the detected object, ultimately shining a 13 | laser in your face. 14 | 15 | 16 | There is additional functionality of the system accessing and playing back sound files dependent on the situation. The software also constantly listens for voice commands and 17 | carries out actions based on them. 18 | 19 | 20 | 1 - The coordinate data must be calculated based on the camera's current field of view. To avoid any hard-coding specific to my hardware, I created a calibration mode. In this 21 | mode, the user uses arrow buttons to position the laser to the bounds of the screen on all 4 sides, these values are serialized to a json file (using json .net)(it's also used 22 | to store settings) located in the same directory as the .exe. When the main detection mode is started and detects an object, outputs to the robot are scaled based on these values. 23 | 24 | 25 | --Materials-- 26 | -OS Capable of compiling and running executable files, recommend Windows, but the same results may be achievable with a system running a .Net equivalent such as Mono (not tested) 27 | -Webcam, I used the Logitech 9000 Pro, but it normally retails for around $110 and I got mine used for $20 on Amazon. I would not spend the full $110 on a webcam, any will do. 28 | -ATmega 328 microcontroller mounted on an arduino board, but really any ATMEL microcontroller capable of PWM should do the trick 29 | -2X Proster MG996R Digital Metal Copper Gear High Torque Servo Motors 30 | -WYHP Mini Laser Dot Diode Module Head WL Red 650nm 6mm 5V 5mW. You can do with one, but I bought 10, only $2.66. May also consider something to mount it in, I used a hollow pen 31 | -3X 5v 2a power supplies, 2 for the servos, 1 for the laser 32 | 33 | 34 | --Dependencies-- 35 | -Emgu CV image recognition library v 2.4 36 | -.Net Framework 4.5 37 | -Telerik aesthetic framework (I use this on 1 or 2 elements, you may just want to change it to the winforms counterpart(s)) 38 | 39 | 40 | --Contact-- 41 | Email: michaelreeves808@gmail.com 42 | 43 | 44 | --Visit Me-- 45 | My Portfolio: michaelreeves.us 46 | My Company Website: www.infibit.net -------------------------------------------------------------------------------- /src/VoiceRecog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Threading; 7 | using System.Speech.Recognition; 8 | using System.Windows.Forms; 9 | 10 | namespace Emgu_4._0 11 | { 12 | public partial class Form1 : Form 13 | { 14 | private SpeechRecognitionEngine recog = new SpeechRecognitionEngine(); 15 | private Choices choices = new Choices(); 16 | private GrammarBuilder builder = new GrammarBuilder(); 17 | private Grammar grammar; 18 | private string[] commands = new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "command x axis add", "command y axis add", "command x axis subtract", "command y axis subtract", "command clear shift string", "command execute shutdown", "command shut the fuck up", "command flip tracking", "command pause", "command detect face", "command detect body", "command fuck off"}; 19 | 20 | private string shiftString = ""; 21 | private bool restFlag = false; 22 | 23 | private void initializeVoiceRecognition() 24 | { 25 | 26 | 27 | choices.Add(commands); 28 | builder.Append(choices); 29 | grammar = new Grammar(builder); 30 | 31 | 32 | recog.LoadGrammar(grammar); 33 | recog.SetInputToDefaultAudioDevice(); 34 | recog.RecognizeAsync(RecognizeMode.Multiple); 35 | recog.SpeechRecognized += recogCommand; 36 | 37 | } 38 | 39 | private void recogCommand(object sender, SpeechRecognizedEventArgs e) 40 | { 41 | if( !e.Result.Text.StartsWith("command")) 42 | { 43 | shiftString += e.Result.Text; 44 | 45 | } 46 | else 47 | { 48 | try 49 | { 50 | switch (e.Result.Text) 51 | { 52 | //case "command x axis add": 53 | // settings.xShift += Int32.Parse(shiftString); 54 | // break; 55 | 56 | //case "command y axis add": 57 | // settings.yShift += Int32.Parse(shiftString); 58 | 59 | // break; 60 | 61 | //case "command x axis subtract": 62 | // settings.xShift -= Int32.Parse(shiftString); 63 | 64 | // break; 65 | 66 | //case "command y axis subtract": 67 | // settings.yShift -= Int32.Parse(shiftString); 68 | 69 | // break; 70 | 71 | //case "command clear shift string": 72 | // shiftString = ""; 73 | // break; 74 | 75 | case "command shut the fuck up": 76 | settings.soundsOn = !settings.soundsOn; 77 | break; 78 | 79 | case "command flip tracking": 80 | settings.sendSerial = !settings.sendSerial; 81 | break; 82 | 83 | case "command pause": 84 | flipPause(); 85 | break; 86 | 87 | case "command detect face": 88 | settings.figureRecogOn = false; 89 | settings.faceRecogOn = true; 90 | break; 91 | 92 | case "command detect body": 93 | settings.faceRecogOn = false; 94 | settings.figureRecogOn = true; 95 | break; 96 | 97 | case "command fuck off": 98 | 99 | laserDown(); 100 | 101 | break; 102 | 103 | case "command execute shutdown": 104 | resetPos(); 105 | this.Close(); 106 | break; 107 | 108 | } 109 | 110 | 111 | saveSettingsToFile(); 112 | applySettings(); 113 | shiftString = ""; 114 | } 115 | catch(FormatException ex) 116 | { 117 | MessageBox.Show("Voice recognition error " + e.Result.Text + " " + shiftString.ToString()); 118 | shiftString = ""; 119 | 120 | } 121 | 122 | 123 | 124 | } 125 | } 126 | 127 | } 128 | 129 | 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/Person_Detector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Drawing; 7 | using Emgu.CV; 8 | using Emgu.CV.GPU; 9 | using Emgu.CV.CvEnum; 10 | using Emgu.CV.Structure; 11 | using Emgu.CV.UI; 12 | using System.Diagnostics; 13 | 14 | 15 | namespace Emgu_4._0 16 | { 17 | 18 | public static class Person_Detector 19 | { 20 | private static Rectangle[] regeions; 21 | private static Rectangle[] faces; 22 | private static Image imageToProcess; 23 | private static List positions = new List(); 24 | private static List facePositions = new List(); 25 | private static GpuCascadeClassifier face = new GpuCascadeClassifier(@"haarcascade_frontalface_default.xml"); 26 | 27 | 28 | 29 | 30 | public static Image findPerson(Image image, out int detections, out List positions) 31 | { 32 | //If the gpu has nvidia CUDA 33 | if (GpuInvoke.HasCuda) 34 | { 35 | imageToProcess = new Image(image.Bitmap); //Value is coppied so the refference of the input image is not changed outside of this class 36 | Person_Detector.positions.Clear(); 37 | using(GpuHOGDescriptor descriptor = new GpuHOGDescriptor()) 38 | { 39 | descriptor.SetSVMDetector(GpuHOGDescriptor.GetDefaultPeopleDetector()); 40 | 41 | using(GpuImage gpuImage = new GpuImage(imageToProcess)) //Create gpuImage from image 42 | { 43 | using (GpuImage bgraImage = gpuImage.Convert()) 44 | { 45 | regeions = descriptor.DetectMultiScale(bgraImage); //Returns all detected regions in a rectangle array 46 | 47 | } 48 | 49 | } 50 | 51 | } 52 | } 53 | else 54 | { 55 | using (HOGDescriptor des = new HOGDescriptor()) 56 | { 57 | regeions = des.DetectMultiScale(imageToProcess); 58 | } 59 | } 60 | 61 | 62 | detections = regeions.Length; 63 | 64 | //Draws detected rectangles onto the image being returned 65 | foreach(Rectangle ped in regeions) 66 | { 67 | imageToProcess.Draw(ped, new Bgr(Color.Red), 5); 68 | imageToProcess.Draw(new Cross2DF(new PointF(ped.Location.X + (ped.Width / 2), ped.Location.Y + (ped.Height / 2)), 30, 30), new Bgr(Color.Green), 3); 69 | Person_Detector.positions.Add(new PointF(ped.Location.X + (ped.Width / 2), ped.Location.Y + (ped.Height / 2))); //Sets the putput variable 70 | } 71 | 72 | 73 | positions = Person_Detector.positions; 74 | return imageToProcess; 75 | } 76 | 77 | 78 | public static Image detectFace(Image image, out int detections, out List positions) 79 | { 80 | Image copyImage = new Image(image.Bitmap); //Copy the image into a new one 81 | 82 | Person_Detector.facePositions.Clear(); 83 | 84 | 85 | using (GpuImage gpuImage = new GpuImage(image)) 86 | using (GpuImage gpuGray = gpuImage.Convert()) //The cascade classifier only takes gray for some reason 87 | { 88 | faces = face.DetectMultiScale(gpuGray, 1.1, 10, Size.Empty); 89 | 90 | //Draws rectanges to the face detection positions 91 | foreach (Rectangle f in faces) 92 | { 93 | 94 | copyImage.Draw(f, new Bgr(Color.Red), 4); 95 | Person_Detector.facePositions.Add(new PointF(f.Location.X + (f.Width / 2), f.Location.Y + (f.Height / 2))); 96 | 97 | } 98 | detections = faces.Length; 99 | positions = facePositions; 100 | } 101 | 102 | 103 | 104 | 105 | 106 | 107 | return copyImage; 108 | } 109 | 110 | 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Calibration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using Emgu.CV; 11 | using Emgu.CV.GPU; 12 | using Emgu.CV.CvEnum; 13 | using Emgu.CV.Structure; 14 | using Emgu.CV.UI; 15 | using Newtonsoft.Json; 16 | using System.IO; 17 | using System.Timers; 18 | 19 | namespace Emgu_4._0 20 | { 21 | 22 | /// 23 | /// Used to callibrate the outermoust positions of the screen to be used when calculating servo positions 24 | /// 25 | public partial class Calibration : Form 26 | { 27 | private buttonState buttonState = new buttonState(); 28 | private System.Timers.Timer buttonHoldtimer; 29 | private Capture capture; 30 | private Settings settings; 31 | private Point virtualPoint = new Point(90, 90); 32 | 33 | public Calibration() 34 | { 35 | InitializeComponent(); 36 | initializePerepherals(); 37 | initializeSettings(); 38 | initializeTimer(); 39 | resetPos(); 40 | 41 | Application.Idle += displayImage; 42 | MessageBox.Show("Use the arrows to adjust the laser to the outermost part of the screen"); 43 | 44 | } 45 | 46 | private void initializeTimer() 47 | { 48 | buttonHoldtimer = new System.Timers.Timer(); 49 | buttonHoldtimer.Interval = 1; 50 | buttonHoldtimer.Enabled = false; 51 | buttonHoldtimer.Elapsed += timerEllapsed; 52 | buttonHoldtimer.AutoReset = true; 53 | 54 | } 55 | 56 | /// 57 | /// Winforms has no event for buttonhold, this is a makeshift one 58 | /// 59 | /// 60 | /// 61 | private void timerEllapsed(object sender, ElapsedEventArgs e) 62 | { 63 | switch (buttonState) 64 | { 65 | case buttonState.Right: 66 | virtualPoint.X--; 67 | break; 68 | 69 | case buttonState.Up: 70 | virtualPoint.Y++; 71 | break; 72 | 73 | case buttonState.Left: 74 | virtualPoint.X++; 75 | break; 76 | 77 | case buttonState.Down: 78 | virtualPoint.Y--; 79 | break; 80 | } 81 | 82 | sendSerial(); 83 | 84 | buttonHoldtimer.Interval = 100; 85 | } 86 | 87 | private void displayImage(object sender, EventArgs arg) 88 | { 89 | imageBox1.Image = capture.QueryFrame(); 90 | 91 | 92 | } 93 | 94 | private void initializeSettings() 95 | { 96 | 97 | try 98 | { 99 | settings = JsonConvert.DeserializeObject(File.ReadAllText(Properties.Resources.settingsFileName)); 100 | } 101 | catch (FileNotFoundException e) 102 | { 103 | MessageBox.Show("No memory file detected, generating one"); 104 | settings = new Settings(); 105 | saveSettings(); 106 | 107 | } 108 | catch (JsonReaderException e) 109 | { 110 | MessageBox.Show("Corrupt Memory File"); 111 | File.Delete(Properties.Resources.settingsFileName); 112 | this.Close(); 113 | } 114 | } 115 | 116 | private void saveSettings() 117 | { 118 | File.WriteAllText(Properties.Resources.settingsFileName, JsonConvert.SerializeObject(settings)); 119 | 120 | } 121 | private void resetPos() 122 | { 123 | serialPort1.Write("X90:Y90"); 124 | } 125 | 126 | private void initializePerepherals() 127 | { 128 | try 129 | { 130 | capture = new Capture(); 131 | } 132 | catch (Exception e) 133 | { 134 | MessageBox.Show("Cannot initialize camera"); 135 | this.Close(); 136 | } 137 | 138 | try 139 | { 140 | serialPort1.Open(); 141 | } 142 | catch (Exception e) 143 | { 144 | MessageBox.Show("Cannot initialize on COM port"); 145 | this.Close(); 146 | } 147 | } 148 | 149 | private void sendSerial() 150 | { 151 | if (virtualPoint.X < 180 && virtualPoint.X > 0 && virtualPoint.Y < 180 && virtualPoint.Y > 0) 152 | { 153 | serialPort1.Write("X" + (virtualPoint.X).ToString() + ":Y" + (virtualPoint.Y).ToString()); //Data stream format 154 | } 155 | 156 | } 157 | 158 | 159 | 160 | 161 | private void Calibration_FormClosing(object sender, FormClosingEventArgs e) 162 | { 163 | capture.Dispose(); 164 | resetPos(); 165 | } 166 | 167 | private void button1_Click(object sender, EventArgs e) 168 | { 169 | DialogResult result = MessageBox.Show("Calibrate " + radDropDownList1.Text + "?", "", MessageBoxButtons.YesNo); 170 | 171 | if (result == DialogResult.Yes) 172 | { 173 | if (radDropDownList1.SelectedIndex != -1) 174 | { 175 | if (radDropDownList1.SelectedIndex == 0) 176 | { 177 | settings.xLeftCalibration = virtualPoint.X; 178 | } 179 | else if (radDropDownList1.SelectedIndex == 1) 180 | { 181 | settings.xRightCalibration = virtualPoint.X; 182 | } 183 | else if (radDropDownList1.SelectedIndex == 2) 184 | { 185 | settings.yTopCalibration = virtualPoint.Y; 186 | } 187 | else if (radDropDownList1.SelectedIndex == 3) 188 | { 189 | settings.yBotCalibration = virtualPoint.Y; 190 | } 191 | 192 | saveToFile(); 193 | } 194 | } 195 | 196 | } 197 | 198 | private void saveToFile() 199 | { 200 | File.WriteAllText(Properties.Resources.settingsFileName, JsonConvert.SerializeObject(settings)); 201 | 202 | } 203 | 204 | private void mouseDown(object sender, MouseEventArgs e) 205 | { 206 | Button button = (Button)sender; 207 | 208 | if (button.Equals(upButton)) 209 | { 210 | buttonState = buttonState.Up; 211 | } 212 | else if (button.Equals(rightButton)) 213 | { 214 | buttonState = buttonState.Right; 215 | } 216 | else if (button.Equals(downButton)) 217 | { 218 | buttonState = buttonState.Down; 219 | } 220 | else if (button.Equals(leftButton)) 221 | { 222 | buttonState = buttonState.Left; 223 | } 224 | 225 | 226 | buttonHoldtimer.Enabled = true; 227 | } 228 | 229 | private void mouseUp(object sender, MouseEventArgs e) 230 | { 231 | buttonHoldtimer.Enabled = false; 232 | } 233 | } 234 | 235 | public enum buttonState 236 | { 237 | Up, Down, Right, Left 238 | } 239 | 240 | public enum soundType 241 | { 242 | Detection, Missing, Startup, Shutdown, Saddness 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/Calibration.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Emgu_4._0 2 | { 3 | partial class Calibration 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Calibration)); 33 | Telerik.WinControls.UI.RadListDataItem radListDataItem1 = new Telerik.WinControls.UI.RadListDataItem(); 34 | Telerik.WinControls.UI.RadListDataItem radListDataItem2 = new Telerik.WinControls.UI.RadListDataItem(); 35 | Telerik.WinControls.UI.RadListDataItem radListDataItem3 = new Telerik.WinControls.UI.RadListDataItem(); 36 | Telerik.WinControls.UI.RadListDataItem radListDataItem4 = new Telerik.WinControls.UI.RadListDataItem(); 37 | this.imageBox1 = new Emgu.CV.UI.ImageBox(); 38 | this.upButton = new System.Windows.Forms.Button(); 39 | this.downButton = new System.Windows.Forms.Button(); 40 | this.rightButton = new System.Windows.Forms.Button(); 41 | this.leftButton = new System.Windows.Forms.Button(); 42 | this.serialPort1 = new System.IO.Ports.SerialPort(this.components); 43 | this.button1 = new System.Windows.Forms.Button(); 44 | this.radDropDownList1 = new Telerik.WinControls.UI.RadDropDownList(); 45 | ((System.ComponentModel.ISupportInitialize)(this.imageBox1)).BeginInit(); 46 | ((System.ComponentModel.ISupportInitialize)(this.radDropDownList1)).BeginInit(); 47 | this.SuspendLayout(); 48 | // 49 | // imageBox1 50 | // 51 | this.imageBox1.Location = new System.Drawing.Point(115, 67); 52 | this.imageBox1.Name = "imageBox1"; 53 | this.imageBox1.Size = new System.Drawing.Size(640, 480); 54 | this.imageBox1.TabIndex = 2; 55 | this.imageBox1.TabStop = false; 56 | // 57 | // upButton 58 | // 59 | this.upButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; 60 | this.upButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 61 | this.upButton.Image = ((System.Drawing.Image)(resources.GetObject("upButton.Image"))); 62 | this.upButton.Location = new System.Drawing.Point(403, 2); 63 | this.upButton.Name = "upButton"; 64 | this.upButton.Size = new System.Drawing.Size(65, 59); 65 | this.upButton.TabIndex = 3; 66 | this.upButton.UseVisualStyleBackColor = true; 67 | this.upButton.MouseDown += new System.Windows.Forms.MouseEventHandler(this.mouseDown); 68 | this.upButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.mouseUp); 69 | // 70 | // downButton 71 | // 72 | this.downButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; 73 | this.downButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 74 | this.downButton.Image = ((System.Drawing.Image)(resources.GetObject("downButton.Image"))); 75 | this.downButton.Location = new System.Drawing.Point(403, 553); 76 | this.downButton.Name = "downButton"; 77 | this.downButton.Size = new System.Drawing.Size(65, 59); 78 | this.downButton.TabIndex = 4; 79 | this.downButton.UseVisualStyleBackColor = true; 80 | this.downButton.MouseDown += new System.Windows.Forms.MouseEventHandler(this.mouseDown); 81 | this.downButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.mouseUp); 82 | // 83 | // rightButton 84 | // 85 | this.rightButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; 86 | this.rightButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 87 | this.rightButton.Image = ((System.Drawing.Image)(resources.GetObject("rightButton.Image"))); 88 | this.rightButton.Location = new System.Drawing.Point(761, 278); 89 | this.rightButton.Name = "rightButton"; 90 | this.rightButton.Size = new System.Drawing.Size(65, 59); 91 | this.rightButton.TabIndex = 5; 92 | this.rightButton.UseVisualStyleBackColor = true; 93 | this.rightButton.MouseDown += new System.Windows.Forms.MouseEventHandler(this.mouseDown); 94 | this.rightButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.mouseUp); 95 | // 96 | // leftButton 97 | // 98 | this.leftButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; 99 | this.leftButton.Font = new System.Drawing.Font("Microsoft Sans Serif", 48F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 100 | this.leftButton.Image = ((System.Drawing.Image)(resources.GetObject("leftButton.Image"))); 101 | this.leftButton.Location = new System.Drawing.Point(44, 278); 102 | this.leftButton.Name = "leftButton"; 103 | this.leftButton.Size = new System.Drawing.Size(65, 59); 104 | this.leftButton.TabIndex = 6; 105 | this.leftButton.UseVisualStyleBackColor = true; 106 | this.leftButton.MouseDown += new System.Windows.Forms.MouseEventHandler(this.mouseDown); 107 | this.leftButton.MouseUp += new System.Windows.Forms.MouseEventHandler(this.mouseUp); 108 | // 109 | // serialPort1 110 | // 111 | this.serialPort1.PortName = "COM3"; 112 | // 113 | // button1 114 | // 115 | this.button1.Location = new System.Drawing.Point(744, 25); 116 | this.button1.Name = "button1"; 117 | this.button1.Size = new System.Drawing.Size(125, 36); 118 | this.button1.TabIndex = 7; 119 | this.button1.Text = "Save Calibration"; 120 | this.button1.UseVisualStyleBackColor = true; 121 | this.button1.Click += new System.EventHandler(this.button1_Click); 122 | // 123 | // radDropDownList1 124 | // 125 | radListDataItem1.Text = "Right"; 126 | radListDataItem2.Text = "Left"; 127 | radListDataItem3.Text = "Top"; 128 | radListDataItem4.Text = "Bottom"; 129 | this.radDropDownList1.Items.Add(radListDataItem1); 130 | this.radDropDownList1.Items.Add(radListDataItem2); 131 | this.radDropDownList1.Items.Add(radListDataItem3); 132 | this.radDropDownList1.Items.Add(radListDataItem4); 133 | this.radDropDownList1.Location = new System.Drawing.Point(744, 2); 134 | this.radDropDownList1.Name = "radDropDownList1"; 135 | this.radDropDownList1.Size = new System.Drawing.Size(125, 20); 136 | this.radDropDownList1.TabIndex = 8; 137 | // 138 | // Calibration 139 | // 140 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 141 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 142 | this.ClientSize = new System.Drawing.Size(870, 615); 143 | this.Controls.Add(this.radDropDownList1); 144 | this.Controls.Add(this.button1); 145 | this.Controls.Add(this.leftButton); 146 | this.Controls.Add(this.rightButton); 147 | this.Controls.Add(this.downButton); 148 | this.Controls.Add(this.upButton); 149 | this.Controls.Add(this.imageBox1); 150 | this.Name = "Calibration"; 151 | this.Text = "Calibration"; 152 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Calibration_FormClosing); 153 | ((System.ComponentModel.ISupportInitialize)(this.imageBox1)).EndInit(); 154 | ((System.ComponentModel.ISupportInitialize)(this.radDropDownList1)).EndInit(); 155 | this.ResumeLayout(false); 156 | this.PerformLayout(); 157 | 158 | } 159 | 160 | #endregion 161 | 162 | private Emgu.CV.UI.ImageBox imageBox1; 163 | private System.Windows.Forms.Button upButton; 164 | private System.Windows.Forms.Button downButton; 165 | private System.Windows.Forms.Button rightButton; 166 | private System.Windows.Forms.Button leftButton; 167 | private System.IO.Ports.SerialPort serialPort1; 168 | private System.Windows.Forms.Button button1; 169 | private Telerik.WinControls.UI.RadDropDownList radDropDownList1; 170 | } 171 | } -------------------------------------------------------------------------------- /src/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Emgu_4._0 2 | { 3 | partial class Form1 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.imageBox1 = new Emgu.CV.UI.ImageBox(); 33 | this.textBox1 = new System.Windows.Forms.TextBox(); 34 | this.pauseButton = new System.Windows.Forms.Button(); 35 | this.serialPort1 = new System.IO.Ports.SerialPort(this.components); 36 | this.resetButton = new System.Windows.Forms.Button(); 37 | this.checkBox1 = new System.Windows.Forms.CheckBox(); 38 | this.imageBox2 = new Emgu.CV.UI.ImageBox(); 39 | this.label1 = new System.Windows.Forms.Label(); 40 | this.label2 = new System.Windows.Forms.Label(); 41 | this.label3 = new System.Windows.Forms.Label(); 42 | this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); 43 | this.numericUpDown2 = new System.Windows.Forms.NumericUpDown(); 44 | this.saveSettingsButton = new System.Windows.Forms.Button(); 45 | this.radioButton1 = new System.Windows.Forms.RadioButton(); 46 | this.radioButton2 = new System.Windows.Forms.RadioButton(); 47 | this.checkBox2 = new System.Windows.Forms.CheckBox(); 48 | ((System.ComponentModel.ISupportInitialize)(this.imageBox1)).BeginInit(); 49 | ((System.ComponentModel.ISupportInitialize)(this.imageBox2)).BeginInit(); 50 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); 51 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).BeginInit(); 52 | this.SuspendLayout(); 53 | // 54 | // imageBox1 55 | // 56 | this.imageBox1.Location = new System.Drawing.Point(12, 12); 57 | this.imageBox1.Name = "imageBox1"; 58 | this.imageBox1.Size = new System.Drawing.Size(640, 480); 59 | this.imageBox1.TabIndex = 2; 60 | this.imageBox1.TabStop = false; 61 | // 62 | // textBox1 63 | // 64 | this.textBox1.Location = new System.Drawing.Point(292, 498); 65 | this.textBox1.Multiline = true; 66 | this.textBox1.Name = "textBox1"; 67 | this.textBox1.ReadOnly = true; 68 | this.textBox1.Size = new System.Drawing.Size(1004, 128); 69 | this.textBox1.TabIndex = 4; 70 | // 71 | // pauseButton 72 | // 73 | this.pauseButton.Location = new System.Drawing.Point(12, 498); 74 | this.pauseButton.Name = "pauseButton"; 75 | this.pauseButton.Size = new System.Drawing.Size(143, 40); 76 | this.pauseButton.TabIndex = 5; 77 | this.pauseButton.Text = "Pause"; 78 | this.pauseButton.UseVisualStyleBackColor = true; 79 | this.pauseButton.Click += new System.EventHandler(this.button1_Click); 80 | // 81 | // serialPort1 82 | // 83 | this.serialPort1.PortName = "COM3"; 84 | // 85 | // resetButton 86 | // 87 | this.resetButton.Location = new System.Drawing.Point(161, 498); 88 | this.resetButton.Name = "resetButton"; 89 | this.resetButton.Size = new System.Drawing.Size(125, 40); 90 | this.resetButton.TabIndex = 6; 91 | this.resetButton.Text = "Reset Position"; 92 | this.resetButton.UseVisualStyleBackColor = true; 93 | this.resetButton.Click += new System.EventHandler(this.button2_Click); 94 | // 95 | // checkBox1 96 | // 97 | this.checkBox1.AutoSize = true; 98 | this.checkBox1.Checked = true; 99 | this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; 100 | this.checkBox1.Location = new System.Drawing.Point(12, 537); 101 | this.checkBox1.Name = "checkBox1"; 102 | this.checkBox1.Size = new System.Drawing.Size(80, 17); 103 | this.checkBox1.TabIndex = 7; 104 | this.checkBox1.Text = "Send Serial"; 105 | this.checkBox1.UseVisualStyleBackColor = true; 106 | // 107 | // imageBox2 108 | // 109 | this.imageBox2.Location = new System.Drawing.Point(658, 12); 110 | this.imageBox2.Name = "imageBox2"; 111 | this.imageBox2.Size = new System.Drawing.Size(640, 480); 112 | this.imageBox2.TabIndex = 8; 113 | this.imageBox2.TabStop = false; 114 | // 115 | // label1 116 | // 117 | this.label1.AutoSize = true; 118 | this.label1.Location = new System.Drawing.Point(9, 583); 119 | this.label1.Name = "label1"; 120 | this.label1.Size = new System.Drawing.Size(36, 13); 121 | this.label1.TabIndex = 11; 122 | this.label1.Text = "X Axis"; 123 | // 124 | // label2 125 | // 126 | this.label2.AutoSize = true; 127 | this.label2.Location = new System.Drawing.Point(9, 613); 128 | this.label2.Name = "label2"; 129 | this.label2.Size = new System.Drawing.Size(36, 13); 130 | this.label2.TabIndex = 12; 131 | this.label2.Text = "Y Axis"; 132 | // 133 | // label3 134 | // 135 | this.label3.AutoSize = true; 136 | this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 137 | this.label3.Location = new System.Drawing.Point(8, 557); 138 | this.label3.Name = "label3"; 139 | this.label3.Size = new System.Drawing.Size(133, 20); 140 | this.label3.TabIndex = 13; 141 | this.label3.Text = "Calibration Adjust"; 142 | // 143 | // numericUpDown1 144 | // 145 | this.numericUpDown1.Location = new System.Drawing.Point(51, 581); 146 | this.numericUpDown1.Minimum = new decimal(new int[] { 147 | 100, 148 | 0, 149 | 0, 150 | -2147483648}); 151 | this.numericUpDown1.Name = "numericUpDown1"; 152 | this.numericUpDown1.Size = new System.Drawing.Size(90, 20); 153 | this.numericUpDown1.TabIndex = 14; 154 | // 155 | // numericUpDown2 156 | // 157 | this.numericUpDown2.Location = new System.Drawing.Point(51, 611); 158 | this.numericUpDown2.Minimum = new decimal(new int[] { 159 | 100, 160 | 0, 161 | 0, 162 | -2147483648}); 163 | this.numericUpDown2.Name = "numericUpDown2"; 164 | this.numericUpDown2.Size = new System.Drawing.Size(90, 20); 165 | this.numericUpDown2.TabIndex = 15; 166 | // 167 | // saveSettingsButton 168 | // 169 | this.saveSettingsButton.Location = new System.Drawing.Point(161, 544); 170 | this.saveSettingsButton.Name = "saveSettingsButton"; 171 | this.saveSettingsButton.Size = new System.Drawing.Size(125, 39); 172 | this.saveSettingsButton.TabIndex = 16; 173 | this.saveSettingsButton.Text = "Save Settings"; 174 | this.saveSettingsButton.UseVisualStyleBackColor = true; 175 | this.saveSettingsButton.Click += new System.EventHandler(this.button3_Click); 176 | // 177 | // radioButton1 178 | // 179 | this.radioButton1.AutoSize = true; 180 | this.radioButton1.Checked = true; 181 | this.radioButton1.Location = new System.Drawing.Point(161, 589); 182 | this.radioButton1.Name = "radioButton1"; 183 | this.radioButton1.Size = new System.Drawing.Size(98, 17); 184 | this.radioButton1.TabIndex = 17; 185 | this.radioButton1.TabStop = true; 186 | this.radioButton1.Text = "Face Detection"; 187 | this.radioButton1.UseVisualStyleBackColor = true; 188 | // 189 | // radioButton2 190 | // 191 | this.radioButton2.AutoSize = true; 192 | this.radioButton2.Location = new System.Drawing.Point(161, 612); 193 | this.radioButton2.Name = "radioButton2"; 194 | this.radioButton2.Size = new System.Drawing.Size(103, 17); 195 | this.radioButton2.TabIndex = 18; 196 | this.radioButton2.Text = "Figure Detection"; 197 | this.radioButton2.UseVisualStyleBackColor = true; 198 | // 199 | // checkBox2 200 | // 201 | this.checkBox2.AutoSize = true; 202 | this.checkBox2.Location = new System.Drawing.Point(93, 537); 203 | this.checkBox2.Name = "checkBox2"; 204 | this.checkBox2.Size = new System.Drawing.Size(62, 17); 205 | this.checkBox2.TabIndex = 19; 206 | this.checkBox2.Text = "Sounds"; 207 | this.checkBox2.UseVisualStyleBackColor = true; 208 | // 209 | // Form1 210 | // 211 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 212 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 213 | this.ClientSize = new System.Drawing.Size(1308, 634); 214 | this.Controls.Add(this.checkBox2); 215 | this.Controls.Add(this.radioButton2); 216 | this.Controls.Add(this.radioButton1); 217 | this.Controls.Add(this.saveSettingsButton); 218 | this.Controls.Add(this.numericUpDown2); 219 | this.Controls.Add(this.numericUpDown1); 220 | this.Controls.Add(this.label3); 221 | this.Controls.Add(this.label2); 222 | this.Controls.Add(this.label1); 223 | this.Controls.Add(this.imageBox2); 224 | this.Controls.Add(this.checkBox1); 225 | this.Controls.Add(this.resetButton); 226 | this.Controls.Add(this.pauseButton); 227 | this.Controls.Add(this.textBox1); 228 | this.Controls.Add(this.imageBox1); 229 | this.Name = "Form1"; 230 | this.Text = "Form1"; 231 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); 232 | this.Load += new System.EventHandler(this.Form1_Load); 233 | ((System.ComponentModel.ISupportInitialize)(this.imageBox1)).EndInit(); 234 | ((System.ComponentModel.ISupportInitialize)(this.imageBox2)).EndInit(); 235 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); 236 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).EndInit(); 237 | this.ResumeLayout(false); 238 | this.PerformLayout(); 239 | 240 | } 241 | 242 | #endregion 243 | 244 | private Emgu.CV.UI.ImageBox imageBox1; 245 | private System.Windows.Forms.TextBox textBox1; 246 | private System.Windows.Forms.Button pauseButton; 247 | private System.IO.Ports.SerialPort serialPort1; 248 | private System.Windows.Forms.Button resetButton; 249 | private System.Windows.Forms.CheckBox checkBox1; 250 | private Emgu.CV.UI.ImageBox imageBox2; 251 | private System.Windows.Forms.Label label1; 252 | private System.Windows.Forms.Label label2; 253 | private System.Windows.Forms.Label label3; 254 | private System.Windows.Forms.NumericUpDown numericUpDown1; 255 | private System.Windows.Forms.NumericUpDown numericUpDown2; 256 | private System.Windows.Forms.Button saveSettingsButton; 257 | private System.Windows.Forms.RadioButton radioButton1; 258 | private System.Windows.Forms.RadioButton radioButton2; 259 | private System.Windows.Forms.CheckBox checkBox2; 260 | } 261 | } 262 | 263 | -------------------------------------------------------------------------------- /src/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using System.Diagnostics; 11 | using Emgu.CV; 12 | using Emgu.CV.GPU; 13 | using Emgu.CV.CvEnum; 14 | using Emgu.CV.Structure; 15 | using Emgu.CV.UI; 16 | using Newtonsoft.Json; 17 | using System.IO; 18 | using System.Media; 19 | 20 | namespace Emgu_4._0 21 | { 22 | /// 23 | /// Displays original and processed images, preforms position calculations, sends data to microcontroller 24 | /// 25 | public partial class Form1 : Form 26 | { 27 | Capture capture; 28 | 29 | 30 | List positions = new List(); 31 | PointF averagedPoint; 32 | 33 | private Stopwatch serialTimoutwatch = new Stopwatch(); 34 | private Stopwatch soundWatch = new Stopwatch(); 35 | Image originalImage; 36 | 37 | private int detections; 38 | bool isCapturing = false; 39 | 40 | private float xDivConst; //Scaling factors for range of vision applied to servo ranges 41 | private float yDivConst; 42 | 43 | private SoundPlayer player = new SoundPlayer(); //For portal turret noises 44 | private Random random = new Random(); //For picking random noise 45 | 46 | private Settings settings; //Generic settings class to be instantiated by deserializing a Json 47 | 48 | 49 | public Form1() 50 | { 51 | InitializeComponent(); 52 | } 53 | 54 | private void Form1_Load(object sender, EventArgs e) 55 | { 56 | initializeJson(); 57 | applySettings(); 58 | serialPort1.Open(); 59 | 60 | resetPos(); 61 | 62 | serialTimoutwatch = Stopwatch.StartNew(); 63 | soundWatch = Stopwatch.StartNew(); 64 | 65 | 66 | try 67 | { 68 | capture = new Emgu.CV.Capture(); //Start Capture object that takes input from default camera 69 | calculateDivisionConstants(); 70 | 71 | Application.Idle += processFrameAndUpdateImg; //Alternative to threading or running a continuous loop, adds this method to list of functions that the application calls constantly 72 | 73 | isCapturing = true; 74 | } 75 | catch (Exception ex) 76 | { 77 | MessageBox.Show(ex.Message); 78 | this.Close(); 79 | } 80 | 81 | initializeVoiceRecognition(); 82 | playSituationalSound(soundType.Startup); //Portal startup sound 83 | 84 | 85 | } 86 | 87 | 88 | /// 89 | /// Get stored settings and callibrations from a Json, deserialize into Settings object 90 | /// 91 | private void initializeJson() 92 | { 93 | try 94 | { 95 | settings = JsonConvert.DeserializeObject(File.ReadAllText(Properties.Resources.settingsFileName)); 96 | } 97 | //If no file is found, make a new one with default settings 98 | catch(FileNotFoundException e) 99 | { 100 | MessageBox.Show("No memory file detected, generating one"); 101 | settings = new Settings(); 102 | saveSettings(); 103 | 104 | } 105 | //If for whatever reason the Json is corrupt 106 | catch (JsonReaderException e) 107 | { 108 | MessageBox.Show("Corrupt Memory File"); 109 | File.Delete(Properties.Resources.settingsFileName); 110 | this.Close(); 111 | } 112 | } 113 | 114 | /// 115 | /// Apply settings using information from Settings object 116 | /// 117 | private void applySettings() 118 | { 119 | this.numericUpDown1.Value = settings.xShift; 120 | this.numericUpDown2.Value = settings.yShift; 121 | this.checkBox1.Checked = settings.sendSerial; 122 | this.checkBox2.Checked = settings.soundsOn; 123 | this.radioButton1.Checked = settings.faceRecogOn; 124 | this.radioButton2.Checked = settings.figureRecogOn; 125 | } 126 | 127 | /// 128 | /// Center servos 129 | /// 130 | private void resetPos() 131 | { 132 | serialPort1.Write("X" + (90 + settings.xShift).ToString() + ":Y" + (90 + settings.yShift).ToString()); 133 | } 134 | 135 | /// 136 | /// Used to scale servo movements to camera's field of view 137 | /// 138 | private void calculateDivisionConstants() 139 | { 140 | xDivConst = (capture.QueryFrame().Width) / (settings.xRightCalibration - settings.xLeftCalibration); 141 | yDivConst = (capture.QueryFrame().Height) / (settings.yTopCalibration - settings.yBotCalibration); 142 | } 143 | 144 | /// 145 | /// Constantly called by application, displays original and processed frames 146 | /// 147 | /// 148 | /// 149 | private void processFrameAndUpdateImg(object sender, EventArgs arg) 150 | { 151 | 152 | originalImage = capture.QueryFrame(); 153 | 154 | 155 | imageBox1.Image = originalImage; 156 | 157 | //These 2 conditions never conflict because both bools are controlled by radio buttons 158 | if (settings.faceRecogOn) 159 | { 160 | imageBox2.Image = Person_Detector.detectFace(originalImage, out detections, out positions); 161 | } 162 | else if (settings.figureRecogOn) 163 | { 164 | imageBox2.Image = Person_Detector.findPerson(originalImage, out detections, out positions); 165 | } 166 | 167 | 168 | averagedPoint = averagePoints(positions); 169 | 170 | 171 | if (positions.Count > 0) 172 | { 173 | //Only proceed to further processing if setting permit and we havn't sent a message in the last 15ms (arduino gets confuzzled) 174 | if (checkBox1.Checked && serialTimoutwatch.ElapsedMilliseconds > 15) 175 | { 176 | serialTimoutwatch = Stopwatch.StartNew(); 177 | calculatePoint(averagedPoint); 178 | playSituationalSound(soundType.Detection); //Play portal detection sound 179 | } 180 | } 181 | //If there are no detections returned, play turret loose sight portal sound 182 | else 183 | { 184 | playSituationalSound(soundType.Missing); 185 | } 186 | 187 | } 188 | 189 | /// 190 | /// Average all detection positions returned by the image recognition class 191 | /// 192 | /// 193 | /// 194 | private PointF averagePoints(List pointList) 195 | { 196 | PointF targetPoint = new PointF(0, 0); 197 | 198 | foreach (PointF point in pointList) 199 | { 200 | targetPoint.X += point.X; 201 | targetPoint.Y += point.Y; 202 | } 203 | 204 | targetPoint.X /= pointList.Count; 205 | targetPoint.Y /= pointList.Count; 206 | return targetPoint; 207 | } 208 | 209 | /// 210 | /// Sends signal to the arduino in proper data format (the sitty one I made) and print position to screen 211 | /// 212 | /// 213 | private void sendSignal(Point currentPoint) 214 | { 215 | 216 | if(settings.sendSerial && !restFlag)serialPort1.Write("X" + (currentPoint.X + settings.xShift).ToString() + ":Y" + (currentPoint.Y + settings.yShift).ToString()); //Data stream format 217 | 218 | textBox1.AppendText("Auto: X" + (currentPoint.X + settings.xShift).ToString() + " Y" + (currentPoint.Y + settings.yShift).ToString() + Environment.NewLine); //Display detection position 219 | 220 | } 221 | 222 | /// 223 | /// Calculates the point that will be sent to arduino, factors in scaling constants and settings adjustments 224 | /// 225 | /// 226 | private void calculatePoint(PointF point) 227 | { 228 | if (withinSafeRange(point)) 229 | { 230 | sendSignal(new Point(((int)(settings.xRightCalibration - (point.X / xDivConst))), ((int)(settings.yTopCalibration - (point.Y / yDivConst))))); 231 | } 232 | 233 | } 234 | 235 | /// 236 | /// Assures that point is not in a position where maving to it could damage hardware, only ever happens if calibration is done wrong 237 | /// 238 | /// 239 | /// 240 | private bool withinSafeRange(PointF point) 241 | { 242 | if ((settings.yTopCalibration - (point.Y / yDivConst)) + ((float)numericUpDown2.Value) > 65 && (settings.yTopCalibration - (point.Y / yDivConst)) + ((float)numericUpDown2.Value) < 138) 243 | { 244 | return true; 245 | } 246 | else 247 | { 248 | return false; 249 | } 250 | } 251 | 252 | 253 | 254 | /// 255 | /// Takes enum dependant on situation, randomly selects a sound from a set of organized directories 256 | /// 257 | /// 258 | private void playSituationalSound(soundType soundType) 259 | { 260 | if (settings.soundsOn) 261 | if (soundWatch.ElapsedMilliseconds > random.Next(5000,8000) || soundType == soundType.Startup || soundType == soundType.Shutdown || soundType == soundType.Saddness) //Exceptions for startup and shutdown so they dont have to wait the 5 seconds 262 | { 263 | switch (soundType) 264 | { 265 | case soundType.Detection: 266 | player.SoundLocation = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\detection")[random.Next(Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\detection").Length)]; // I'm sorry 267 | break; 268 | 269 | case soundType.Startup: 270 | player.SoundLocation = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\startup")[random.Next(Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\startup").Length)]; 271 | break; 272 | 273 | case soundType.Shutdown: 274 | player.SoundLocation = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\shutdown")[random.Next(Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\shutdown").Length)]; 275 | break; 276 | 277 | case soundType.Missing: 278 | 279 | player.SoundLocation = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\noDetection")[random.Next(Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\noDetection").Length)]; 280 | break; 281 | 282 | case soundType.Saddness: 283 | player.SoundLocation = Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\saddness")[random.Next(Directory.GetFiles(Directory.GetCurrentDirectory() + @"\Sound\saddness").Length)]; 284 | break; 285 | 286 | 287 | } 288 | 289 | //Need to start the sound in a new thread to that it doesn't stall the main thread and so that souns don't overlap 290 | Thread thread = new Thread(new ThreadStart(playSound)); 291 | thread.Start(); 292 | 293 | soundWatch = Stopwatch.StartNew(); 294 | 295 | } 296 | 297 | 298 | 299 | } 300 | 301 | private void playSound() 302 | { 303 | player.PlaySync(); 304 | } 305 | 306 | 307 | private void laserDown() 308 | { 309 | restFlag = true; 310 | 311 | for (int i = 0; i < 10; i++) 312 | { 313 | serialPort1.Write("X90:Y50"); 314 | textBox1.AppendText("From Rest\n"); 315 | Thread.Sleep(15); 316 | } 317 | playSituationalSound(soundType.Saddness); 318 | Thread.Sleep(4000); 319 | restFlag = false; 320 | 321 | } 322 | 323 | /// 324 | /// Pauses image processing by removing processing method from Application's idle list 325 | /// 326 | /// 327 | /// 328 | private void button1_Click(object sender, EventArgs e) 329 | { 330 | flipPause(); 331 | } 332 | 333 | private void flipPause() 334 | { 335 | if (isCapturing) 336 | { 337 | Application.Idle -= processFrameAndUpdateImg; 338 | isCapturing = false; 339 | pauseButton.Text = "Resume"; 340 | resetPos(); 341 | } 342 | else if (!isCapturing) 343 | { 344 | Application.Idle += processFrameAndUpdateImg; 345 | isCapturing = true; 346 | pauseButton.Text = "Pause"; 347 | } 348 | } 349 | 350 | 351 | 352 | /// 353 | /// Plays shutdown sound, and resets the servos upon shutdown 354 | /// 355 | /// 356 | /// 357 | private void Form1_FormClosing(object sender, FormClosingEventArgs e) 358 | { 359 | playSituationalSound(soundType.Shutdown); 360 | 361 | Application.Idle -= processFrameAndUpdateImg; 362 | resetPos(); 363 | serialPort1.Close(); 364 | capture.Dispose(); 365 | //this.ParentForm.Close(); //Some of the emgu dlls dont like being instantiated twice at runtime, so the entire program needs to shutdown after running this form 366 | 367 | } 368 | 369 | private void button2_Click(object sender, EventArgs e) 370 | { 371 | resetPos(); 372 | } 373 | 374 | //Calls saveSettings and plays alert 375 | private void button3_Click(object sender, EventArgs e) 376 | { 377 | saveSettings(); 378 | System.Media.SystemSounds.Asterisk.Play(); 379 | 380 | } 381 | 382 | /// 383 | /// Updates settings object with the state of current controls 384 | /// 385 | private void saveSettings() 386 | { 387 | settings.xShift = (int)numericUpDown1.Value; 388 | settings.yShift = (int)numericUpDown2.Value; 389 | settings.sendSerial = checkBox1.Checked; 390 | settings.faceRecogOn = radioButton1.Checked; 391 | settings.figureRecogOn = radioButton2.Checked; 392 | settings.soundsOn = checkBox2.Checked; 393 | 394 | saveSettingsToFile(); 395 | } 396 | 397 | private void saveSettingsToFile() 398 | { 399 | File.WriteAllText(Properties.Resources.settingsFileName, JsonConvert.SerializeObject(settings)); 400 | } 401 | } 402 | 403 | /// 404 | /// Settings class, constructor initializes value with defaults 405 | /// 406 | public class Settings 407 | { 408 | public int xShift { get; set; } 409 | public int yShift { get; set; } 410 | public int xLeftCalibration { get; set; } 411 | public int xRightCalibration { get; set; } 412 | public int yTopCalibration { get; set; } 413 | public int yBotCalibration { get; set; } 414 | public bool sendSerial { get; set; } 415 | public bool faceRecogOn { get; set; } 416 | public bool figureRecogOn { get; set; } 417 | public bool soundsOn { get; set; } 418 | 419 | public Settings() 420 | { 421 | xShift = 0; 422 | yShift = 0; 423 | xLeftCalibration = 59; 424 | xRightCalibration = 118; 425 | yTopCalibration = 110; 426 | yBotCalibration = 70; 427 | faceRecogOn = true; 428 | figureRecogOn = false; 429 | soundsOn = true; 430 | sendSerial = true; 431 | } 432 | 433 | } 434 | } 435 | --------------------------------------------------------------------------------