OpenCV прерывает последовательную связь с Arduino? - PullRequest
1 голос
/ 20 апреля 2019

Я пытаюсь создать программу, которая использует сервоприводы, подключенные к Arduino, который следует за вашим лицом. Я использую Visual C ++ в Visual Studio 2017 с opencv 4.1 для распознавания лиц, а затем отправляю местоположение идентифицированного лица в Arduino через последовательное соединение.

Я новичок в opencv, поэтому я прошёл много уроков, чтобы попытаться создать работающий код.

План состоит в том, чтобы выполнить распознавание лиц, а затем рассчитать местоположение лица в визуальной студии. Затем объедините местоположения x и y в одну строку и отправьте ее в arduino с помощью serial. Затем arduino разделяет координаты, разделенные двоеточием, используя strtok (). Затем он будет соответствующим образом перемещать сервоприводы, чтобы сохранить отслеживаемое лицо в центре экрана.

Я проверил последовательную связь в отдельном проекте c ++, и он, кажется, отлично работает с текущим кодом Arduino (не где-то близко, когда закончил, потому что я столкнулся с ошибкой последовательной связи), за исключением случаев, когда я отправляю строку местоположения, серво перемещается в нужное место и возвращается в исходное положение.

Когда я пытаюсь реализовать последовательную связь в проекте с opencv, он отправляет местоположение один раз, затем появляется, чтобы остановить отправку последовательных команд. Я попытался отладить вручную, вызвав функцию sendSerial в других местах, чтобы посмотреть, смогу ли я получить ее для отправки. Я пытался искать решения, но не нашел каких-либо определенных решений, кроме как это может быть функция waitKey (10). Если это так, есть ли способ обойти это?

Спасибо.

###############SerialPort.h##############
#ifndef SERIALPORT_H
#define SERIALPORT_H

#define ARDUINO_WAIT_TIME 2000
#define MAX_DATA_LENGTH 255

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

class SerialPort
{
private:
    HANDLE handler;
    bool connected;
    COMSTAT status;
    DWORD errors;
public:
    SerialPort(char *portName);
    ~SerialPort();

    int readSerialPort(char *buffer, unsigned int buf_size);
    bool writeSerialPort(char *buffer, unsigned int buf_size);
    bool isConnected();
};

#endif // SERIALPORT_H
#################SerialSource.cpp##################
#include "SerialPort.h"

SerialPort::SerialPort(char *portName)
{
    this->connected = false;

    this->handler = CreateFileA(static_cast<LPCSTR>(portName),
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (this->handler == INVALID_HANDLE_VALUE) {
        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
            printf("ERROR: Handle was not attached. Reason: %s not available\n", portName);
        }
        else
        {
            printf("ERROR!!!");
        }
    }
    else {
        DCB dcbSerialParameters = { 0 };

        if (!GetCommState(this->handler, &dcbSerialParameters)) {
            printf("failed to get current serial parameters");
        }
        else {
            dcbSerialParameters.BaudRate = CBR_9600;
            dcbSerialParameters.ByteSize = 8;
            dcbSerialParameters.StopBits = ONESTOPBIT;
            dcbSerialParameters.Parity = NOPARITY;
            dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;

            if (!SetCommState(handler, &dcbSerialParameters))
            {
                printf("ALERT: could not set Serial port parameters\n");
            }
            else {
                this->connected = true;
                PurgeComm(this->handler, PURGE_RXCLEAR | PURGE_TXCLEAR);
                Sleep(ARDUINO_WAIT_TIME);
            }
        }
    }
}

SerialPort::~SerialPort()
{
    if (this->connected) {
        this->connected = false;
        CloseHandle(this->handler);
    }
}

int SerialPort::readSerialPort(char *buffer, unsigned int buf_size)
{
    DWORD bytesRead;
    unsigned int toRead = 0;

    ClearCommError(this->handler, &this->errors, &this->status);

    if (this->status.cbInQue > 0) {
        if (this->status.cbInQue > buf_size) {
            toRead = buf_size;
        }
        else toRead = this->status.cbInQue;
    }

    if (ReadFile(this->handler, buffer, toRead, &bytesRead, NULL)) return bytesRead;

    return 0;
}

bool SerialPort::writeSerialPort(char *buffer, unsigned int buf_size)
{
    DWORD bytesSend;

    if (!WriteFile(this->handler, (void*)buffer, buf_size, &bytesSend, 0)) {
        ClearCommError(this->handler, &this->errors, &this->status);
        return false;
    }
    else return true;
}

bool SerialPort::isConnected()
{
    return this->connected;
}
###################faceDetect.cpp################
// CPP program to detects face in a video 

// Include required header files from OpenCV directory 
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream> 
#include <opencv2/opencv.hpp>

#include <string>
#include <stdlib.h>
#include "SerialPort.h"

#include <sstream>
#include <iomanip>

using namespace std;
using namespace cv;


//Set up serial comm
char output[MAX_DATA_LENGTH];
char port[] = "\\\\.\\COM3";
char incoming[MAX_DATA_LENGTH];


// Function for Face Detection 
void detectAndDraw(Mat& img, CascadeClassifier& cascade, double scale, SerialPort arduino);
string cascadeName;

// Function for sending locations to arduino
void sendSerial(string locations, SerialPort arduino);






int main(int argc, const char** argv)
{
    //Establish connection to serial
    SerialPort arduino(port);

    if (arduino.isConnected()) {
        cout << "COnnection Established" << endl;
    }
    else {
        cout << "Error in port name" << endl;
    }

    // VideoCapture class for playing video for which faces to be detected 
    VideoCapture capture;
    Mat frame, image;

    // PreDefined trained XML classifiers with facial features 
    CascadeClassifier cascade;
    double scale = 1;


    // Change path before execution  
    cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml");

    // Start Video..1) 0 for WebCam 2) "Path to Video" for a Local Video 
    capture.open(CAP_MSMF);
    //sendSerial("400:100", arduino);
    if (capture.isOpened())
    {
        // Capture frames from video and detect faces 
        cout << "Face Detection Started...." << endl;
        while (1)
        {
            capture >> frame;
            if (frame.empty())
                break;
            Mat frame1 = frame.clone();
            detectAndDraw(frame1, cascade, scale, arduino);
            char c = (char)waitKey(10);



            // Press q to exit from window 
            if (c == 27 || c == 'q' || c == 'Q')
                break;
        }
    }
    else
        cout << "Could not Open Camera";
    return 0;
}



void sendSerial(string locations, SerialPort arduino) {
    //string command;
    //command = to_string(xloc);




    cout << locations << endl;

    char *charArray = new char[locations.size() + 1];
    copy(locations.begin(), locations.end(), charArray);
    charArray[locations.size()] = '\n';

    arduino.writeSerialPort(charArray, MAX_DATA_LENGTH);



    //arduino.readSerialPort(output, MAX_DATA_LENGTH);

    //cout << output;

    delete[] charArray;


    //
    //command = to_string(yloc);
    //copy(command.begin(), command.end(), charArray);
    //charArray[command.size()] = '\n';

    //arduino.writeSerialPort(charArray, MAX_DATA_LENGTH);
    ////arduino.readSerialPort(output, MAX_DATA_LENGTH);

    ////cout << output;

    //delete[] charArray;
}


void detectAndDraw(Mat& img, CascadeClassifier& cascade,
    double scale, SerialPort arduino)
{
    vector<Rect> faces;
    Mat gray, smallImg;

    cvtColor(img, gray, COLOR_BGR2GRAY); // Convert to Gray Scale 
    double fx = 1 / scale;

    // Resize the Grayscale Image  
    resize(gray, smallImg, Size(), fx, fx, INTER_LINEAR);
    equalizeHist(smallImg, smallImg);

    // Detect faces of different sizes using cascade classifier  
    cascade.detectMultiScale(smallImg, faces, 1.1,
        2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

    // Draw circles around the faces 
    for (size_t i = 0; i < faces.size(); i++)
    {
        Rect r = faces[i];
        Mat smallImgROI;


        int x = faces[i].x;
        int y = faces[i].y;
        int h = y + faces[i].height;
        int w = x + faces[i].width;
        int centerX = x + (.5* faces[i].width);
        int centerY = y + (.5* faces[i].height);

        if (abs(320 - centerX) <= 50) {
            if (abs(240 - centerY) <= 50) {
                rectangle(img,
                    Point(x, y),
                    Point(w, h),
                    Scalar(0, 0, 275),
                    2,
                    8,
                    0);
            }
        }

        else {
            rectangle(img,
                Point(x, y),
                Point(w, h),
                Scalar(275, 275, 275),
                2,
                8,
                0);

        }


        stringstream stringX;
        stringstream stringY;
        stringX << std::setw(3) << std::setfill('0') << centerX;
        stringY << std::setw(3) << std::setfill('0') << centerY;

        std::stringstream ss;
        //ss << std::setw(3) << std::setfill('0') << centerX << ":"<< centerY;
        //std::string s = ss.str();
        std::string s = stringX.str() + ":" + stringY.str();
        //cout << s << endl;
        sendSerial(s, arduino);

        smallImgROI = smallImg(r);


        if (arduino.isConnected()) {
            cout << "COnnection Established" << endl;
            //sendSerial("400:100", arduino);
        }

    }

    // Show Processed Image with detected faces 
    imshow("Face Detection", img);
}

#####################arduino code################
#include <Servo.h>

String input;
char array[6];
char *strings[3];
char *ptr = NULL;
int xloc;
int yloc;

int hServoPin = 9;
Servo hServo;
int ledPin = 13;

void setup() {
  //set up servos
  hServo.attach(hServoPin);

  //start serial connection
  Serial.begin(9600);


  //***** delete later *****
  pinMode(ledPin, OUTPUT);

}

void loop() {



  if(Serial.available()){

    //grab "xloc:yloc" and convert to char array
    input = Serial.readStringUntil('\n');


    //delete later
    //Serial.print("input; ");
    //Serial.println(input);

    for(int i = 0; i<6; i++){
        array[i] = input.charAt(i);
        //Serial.print(array[i]);
    }


    //split char array into two entities
    byte index = 0;
    ptr = strtok(array, ":;");  // takes a list of delimiters

    while(ptr != NULL)
    {
        strings[index] = ptr;
        index++;
        ptr = strtok(NULL, ":;");  // takes a list of delimiters
        //Serial.println("loop");
    }

    //set xloc and yloc respectively
    xloc = atoi(strings[0]);
    yloc = atoi(strings[1]);



  }

  if((xloc < 214)){
    hServo.write(0);
    delay(100);
  }
  else if((xloc > 214) && (xloc < 328)){
    hServo.write(90);
    delay(100);
  }
  else if((xloc > 328)){
    hServo.write(180);
    delay(100);
  }


}
...