I am building an application that uses Computer Vision to detect objects with a webcam.
- To implement the idea, I use the OpenCV library and C++.
- To build the windows form I am using C++/CLR (.NET Framework) with Visual Studio 2019.
I have already got the program to work but I want to improve my code.
Introduction to my question:
I want to make less and more efficient code in the "button events" which you can see in "CODE 1". The reason for it, is because I am almost using the same code for all of the three buttons (it takes a lot of space and is ugly).
My idea is to build a class around the code which you can see in the button events and make instances of the class in each button event. The problem is, I also need to be able to press the exit button and control the member variables I have in CODE 1.
The three private member variables in CODE 1 are as follows:
//// private member variables
private:
bool CamWhileLoop1;
bool CamWhileLoop2;
bool CamWhileLoop3;
I use them to turn the while loops on and off in each button event so the webcam window will be turned off when a new event is pressed.
(the webcam window is provided by the OpenCV library when you press one of the three buttons).
My questions:
- What is the best and most efficient way to implement this.
- Is it good as it is?
- I am using already trained Haar Cascade files from the OpenCV library to detect the objects. My program is very slow and the webcam lags a lot. How can get rid of this lag? (I think I need to use YOLO or some other implementation of the Artificial Intelligence (AI) part but i'm not sure)
- Is it good as it is? Do I need to turn one event off by my self when another button event is pressed or does that happen automatically inside of the C++/CLR library?
CODE 1 and CODE 2 are found below.
CODE 1: Here is my "windows Form code" called MyForm.h
#pragma once
// Include OpenCV
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
// Include C++ libraries
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
//#include <opencv2/opencv.hpp>
namespace ObjectCounter {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
/// <summary>
/// Summary for MyForm
/// </summary>
public ref class MyForm : public System::Windows::Forms::Form
{
public:
MyForm(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~MyForm()
{
if (components)
{
delete components;
}
}
protected:
//// private member variables
private:
bool CamWhileLoop1;
bool CamWhileLoop2;
bool CamWhileLoop3;
private: System::Windows::Forms::Label^ label1;
private: System::Windows::Forms::Label^ label2;
private: System::Windows::Forms::Button^ button1;
private: System::Windows::Forms::Button^ button2;
private: System::Windows::Forms::Button^ button3;
private: System::Windows::Forms::Button^ button4;
private:
/// <summary>
/// Required designer variable.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->button1 = (gcnew System::Windows::Forms::Button());
this->label1 = (gcnew System::Windows::Forms::Label());
this->label2 = (gcnew System::Windows::Forms::Label());
this->button2 = (gcnew System::Windows::Forms::Button());
this->button3 = (gcnew System::Windows::Forms::Button());
this->button4 = (gcnew System::Windows::Forms::Button());
this->SuspendLayout();
//
// button1
//
this->button1->Location = System::Drawing::Point(113, 64);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(459, 65);
this->button1->TabIndex = 0;
this->button1->Text = L"Count Faces";
this->button1->UseVisualStyleBackColor = true;
this->button1->Click += gcnew System::EventHandler(this, &MyForm::button1_Click);
//
// label1
//
this->label1->AutoSize = true;
this->label1->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 20, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(0)));
this->label1->Location = System::Drawing::Point(83, 422);
this->label1->Name = L"label1";
this->label1->Size = System::Drawing::Size(297, 39);
this->label1->TabIndex = 1;
this->label1->Text = L"Amount of objects:";
//
// label2
//
this->label2->AutoSize = true;
this->label2->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 30, System::Drawing::FontStyle::Regular, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(0)));
this->label2->Location = System::Drawing::Point(477, 403);
this->label2->Name = L"label2";
this->label2->Size = System::Drawing::Size(53, 58);
this->label2->TabIndex = 2;
this->label2->Text = L"0";
this->label2->Click += gcnew System::EventHandler(this, &MyForm::label2_Click);
//
// button2
//
this->button2->Location = System::Drawing::Point(113, 135);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(459, 65);
this->button2->TabIndex = 3;
this->button2->Text = L"Count Eyes";
this->button2->UseVisualStyleBackColor = true;
this->button2->Click += gcnew System::EventHandler(this, &MyForm::button2_Click);
//
// button3
//
this->button3->Location = System::Drawing::Point(113, 206);
this->button3->Name = L"button3";
this->button3->Size = System::Drawing::Size(459, 65);
this->button3->TabIndex = 4;
this->button3->Text = L"Count Russian License Plates";
this->button3->UseVisualStyleBackColor = true;
this->button3->Click += gcnew System::EventHandler(this, &MyForm::button3_Click);
//
// button4
//
this->button4->Location = System::Drawing::Point(240, 301);
this->button4->Name = L"button4";
this->button4->Size = System::Drawing::Size(214, 39);
this->button4->TabIndex = 5;
this->button4->Text = L"Exit";
this->button4->UseVisualStyleBackColor = true;
this->button4->Click += gcnew System::EventHandler(this, &MyForm::button4_Click);
//
// MyForm
//
this->AutoScaleDimensions = System::Drawing::SizeF(8, 16);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(680, 560);
this->Controls->Add(this->button4);
this->Controls->Add(this->button3);
this->Controls->Add(this->button2);
this->Controls->Add(this->label2);
this->Controls->Add(this->label1);
this->Controls->Add(this->button1);
this->Name = L"MyForm";
this->Text = L"Artificial Intelligence Counter";
this->ResumeLayout(false);
this->PerformLayout();
}
#pragma endregion
private: System::Void label2_Click(System::Object^ sender, System::EventArgs^ e) {
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { // Count Faces
//Initialize variables
unsigned int ObjectCounter1 = 0;
this->CamWhileLoop1 = true;
this->CamWhileLoop2 = false;
this->CamWhileLoop3 = false;
cv::VideoCapture Video_Capture1(0); // Create an instance of the cv::VideoCapture class
cv::Mat image1; // Create an instance of the cv:Mat class (creating an empty image)
cv::CascadeClassifier faceCascade1; // Create an instance of the cv::CascadeClassifier class
faceCascade1.load("Resources/haarcascade_frontalface_alt.xml"); // Load haar cascade file
if (!Video_Capture1.isOpened()) { // Check if camera opened successfully
std::cout << "Error opening video stream or file" << std::endl;
//return -1;
}
if (faceCascade1.empty()) { // Check if the XML file has been loaded properly or not
std::cout << "XML file not loaded." << std::endl;
}
std::vector<cv::Rect> Rectangles_for_objects1; // Storing rectangles in a vector
std::this_thread::sleep_for(std::chrono::milliseconds(200)); //Giving the webcam time to start
while (this->CamWhileLoop1) {
Video_Capture1.read(image1); //Create matrix from the webcam
faceCascade1.detectMultiScale(image1, Rectangles_for_objects1, 1.1, 10);
for (int i = 0; i < Rectangles_for_objects1.size(); i++) { // Iterate over all objects and print them
//Code for rectangle around faces
cv::rectangle(image1, Rectangles_for_objects1[i].tl(), Rectangles_for_objects1[i].br(), cv::Scalar(255, 0, 255), 3);
//tl = top left and br = bottom right
}
// For the counter part
if (Rectangles_for_objects1.size() != ObjectCounter1) {
if (Rectangles_for_objects1.size() == 0) {
std::cout << "There is no person in the image" << std::endl;
}
else if (Rectangles_for_objects1.size() == 1) {
std::cout <