mirror of
https://github.com/azaion/autopilot.git
synced 2026-04-22 11:36:34 +00:00
Initial version of combining rtsp_ai_player and camera modules.
Functionality has been written to rtsp_ai_player. TODO!! - move functionality of camera module misc/rtsp_ai_player/aienginegimbalserver.cpp - implement all signals in AiEngineGimbalClient - get drone position from autopilot and send it to AiEngineGimbalServer
This commit is contained in:
@@ -31,7 +31,7 @@ AiEngine::AiEngine(QString modelPath, QObject *parent)
|
|||||||
connect(this, &AiEngine::inferenceFrame, mInference, &AiEngineInference::performInferenceSlot, Qt::QueuedConnection);
|
connect(this, &AiEngine::inferenceFrame, mInference, &AiEngineInference::performInferenceSlot, Qt::QueuedConnection);
|
||||||
inferenceThread->start();
|
inferenceThread->start();
|
||||||
|
|
||||||
mGimbalControl = new AiEngineGimbalControl(this);
|
mGimbalClient = new AiEngineGimbalClient(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -50,11 +50,7 @@ void AiEngine::stop(void)
|
|||||||
void AiEngine::inferenceResultsReceivedSlot(AiEngineInferenceResult result)
|
void AiEngine::inferenceResultsReceivedSlot(AiEngineInferenceResult result)
|
||||||
{
|
{
|
||||||
//qDebug() << "AiEngine got inference results in thread: " << QThread::currentThreadId();
|
//qDebug() << "AiEngine got inference results in thread: " << QThread::currentThreadId();
|
||||||
|
mGimbalClient->inferenceResultSlot(result);
|
||||||
#ifdef OPI5_BUILD
|
|
||||||
mGimbalControl->inferenceResultSlot(result);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cv::imshow("Received Frame", result.frame);
|
cv::imshow("Received Frame", result.frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <opencv2/videoio.hpp>
|
#include <opencv2/videoio.hpp>
|
||||||
#include "aienginertsplistener.h"
|
#include "aienginertsplistener.h"
|
||||||
#include "aiengineinference.h"
|
#include "aiengineinference.h"
|
||||||
#include "aienginegimbalcontrol.h"
|
#include "aienginegimbalclient.h"
|
||||||
|
|
||||||
class AiEngine : public QObject
|
class AiEngine : public QObject
|
||||||
{
|
{
|
||||||
@@ -25,5 +25,5 @@ signals:
|
|||||||
private:
|
private:
|
||||||
AiEngineRtspListener *mRtspListener;
|
AiEngineRtspListener *mRtspListener;
|
||||||
AiEngineInference *mInference;
|
AiEngineInference *mInference;
|
||||||
AiEngineGimbalControl *mGimbalControl;
|
AiEngineGimbalClient *mGimbalClient;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Common geoposition
|
||||||
|
typedef struct {
|
||||||
|
float lat;
|
||||||
|
float lon;
|
||||||
|
float alt;
|
||||||
|
} AiEngineGeoPosition;
|
||||||
|
|
||||||
|
|
||||||
|
// AiEngineGimbalClient -> AiEngineGimbalServer is sent when location or position of the drone changes.
|
||||||
|
typedef struct {
|
||||||
|
AiEngineGeoPosition position;
|
||||||
|
float pitch;
|
||||||
|
float yaw;
|
||||||
|
} AiEngineDronePosition;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int left;
|
||||||
|
int top;
|
||||||
|
int right;
|
||||||
|
int bottom;
|
||||||
|
} AiEngineRectangle;
|
||||||
|
|
||||||
|
|
||||||
|
// AiEngineGimbalClient -> AiEngineGimbalServer when AI finds the target. Index is a new variable to
|
||||||
|
// keep track of the targets.
|
||||||
|
typedef struct {
|
||||||
|
int index;
|
||||||
|
AiEngineRectangle rectangle;
|
||||||
|
} AiEngineCameraTarget;
|
||||||
|
|
||||||
|
|
||||||
|
// AiEngineGimbalServer -> AiEngineGimbalClient when AiEngineGimbalServer has zoomed to the target
|
||||||
|
// defined in AiEngineCameraTarget. Position variable contains calculated geoposition of the target.
|
||||||
|
typedef struct {
|
||||||
|
int targetIndex;
|
||||||
|
AiEngineGeoPosition position;
|
||||||
|
} AiEngineTargetPosition;
|
||||||
|
|
||||||
|
|
||||||
|
// AiEngineGimbalClient -> AiEngineGimbalServer when AI asks to change camera direction. For example
|
||||||
|
// nothing interesting was not found. AiEngineGimbalServer -> AiEngineGimbalClient every few second so
|
||||||
|
// that AI knows the position of the camera.
|
||||||
|
typedef struct {
|
||||||
|
float yaw;
|
||||||
|
float pitch;
|
||||||
|
float zoom;
|
||||||
|
} AiEngineCameraPosition;
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QVector>
|
||||||
|
#include "aienginegimbalclient.h"
|
||||||
|
#include "aiengineinference.h"
|
||||||
|
|
||||||
|
AiEngineGimbalClient::AiEngineGimbalClient(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
{
|
||||||
|
// Create server and run it in the new thread.
|
||||||
|
// Connect all signal and slots here. No need to do the same in AiEngineGimbalServer class.
|
||||||
|
|
||||||
|
mGimbalServer = new AiEngineGimbalServer(this);
|
||||||
|
QThread *gimbalServerThread = new QThread(this);
|
||||||
|
mGimbalServer->moveToThread(gimbalServerThread);
|
||||||
|
|
||||||
|
// Client -> Server communication. Only zoomToAiTarget() signal is emitted ATM.
|
||||||
|
connect(this, &AiEngineGimbalClient::setDronePosition, mGimbalServer, &AiEngineGimbalServer::dronePositionSlot, Qt::QueuedConnection);
|
||||||
|
connect(this, &AiEngineGimbalClient::zoomToAiTarget, mGimbalServer, &AiEngineGimbalServer::zoomToAiTargetSlot, Qt::QueuedConnection);
|
||||||
|
connect(this, &AiEngineGimbalClient::setCameraPosition, mGimbalServer, &AiEngineGimbalServer::cameraPositionSlot, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// Server -> Client communication
|
||||||
|
connect(mGimbalServer, &AiEngineGimbalServer::aiTargetZoomed, this, &AiEngineGimbalClient::aiTargetZoomedSlot, Qt::QueuedConnection);
|
||||||
|
connect(mGimbalServer, &AiEngineGimbalServer::newCameraPosition, this, &AiEngineGimbalClient::cameraPositionSlot, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
gimbalServerThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AiEngineGimbalClient::aiTargetZoomedSlot(AiEngineTargetPosition targetPosition)
|
||||||
|
{
|
||||||
|
qDebug() << "AiEngineGimbalClient::aiTargetZoomedSlot() Server zoomed to index:"
|
||||||
|
<< targetPosition.targetIndex
|
||||||
|
<< "Geopos:"
|
||||||
|
<< targetPosition.position.lat
|
||||||
|
<< targetPosition.position.lon
|
||||||
|
<< targetPosition.position.alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AiEngineGimbalClient::cameraPositionSlot(AiEngineCameraPosition cameraPosition)
|
||||||
|
{
|
||||||
|
qDebug() << "AiEngineGimbalClient::cameraPositionSlot() Camera moved to:"
|
||||||
|
<< cameraPosition.pitch
|
||||||
|
<< cameraPosition.yaw
|
||||||
|
<< cameraPosition.zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AiEngineRectangle AiEngineGimbalClient::getGroupCoordinates(QVector<AiEngineObject> &objects)
|
||||||
|
{
|
||||||
|
AiEngineRectangle groupRectangle;
|
||||||
|
groupRectangle.top = 1000000;
|
||||||
|
groupRectangle.left = 1000000;
|
||||||
|
groupRectangle.bottom = 0;
|
||||||
|
groupRectangle.right = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < objects.size(); i++) {
|
||||||
|
const AiEngineRectangle &objectRectangle = objects[i].rectangle;
|
||||||
|
|
||||||
|
if (objectRectangle.top < groupRectangle.top) {
|
||||||
|
groupRectangle.top = objectRectangle.top;
|
||||||
|
}
|
||||||
|
if (objectRectangle.left < groupRectangle.left) {
|
||||||
|
groupRectangle.left = objectRectangle.left;
|
||||||
|
}
|
||||||
|
if (objectRectangle.bottom > groupRectangle.bottom) {
|
||||||
|
groupRectangle.bottom = objectRectangle.bottom;
|
||||||
|
}
|
||||||
|
if (objectRectangle.right > groupRectangle.right) {
|
||||||
|
groupRectangle.right = objectRectangle.right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupRectangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AiEngineGimbalClient::inferenceResultSlot(AiEngineInferenceResult result)
|
||||||
|
{
|
||||||
|
if (result.objects.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO!! Just increasing number for testing purposes ATM.
|
||||||
|
static int index = 0;
|
||||||
|
|
||||||
|
// We got list of all recognized objects, but at least for now we will zoom to all objects at
|
||||||
|
// once and not for each invidually. Got minimal coordinates which contains the all objects.
|
||||||
|
AiEngineRectangle groupRect = getGroupCoordinates(result.objects);
|
||||||
|
|
||||||
|
if (groupRect.top > 600 || groupRect.bottom > 600) {
|
||||||
|
qDebug() << "ERROR! inferenceResultSlot() groupRect.top > 600 || groupRect.bottom > 600";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupRect.left > 600 || groupRect.right > 600) {
|
||||||
|
qDebug() << "ERROR! inferenceResultSlot() groupRect.left > 600 || groupRect.right > 600";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((groupRect.bottom <= groupRect.top) || (groupRect.right <= groupRect.left)) {
|
||||||
|
qDebug() << "ERROR! (groupRect.bottom <= groupRect.top) || (groupRect.right <= groupRect.left)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "inferenceResultSlot() Zooming to square top=" << groupRect.top << "x" << groupRect.left << "and bottom:" << groupRect.bottom << "x" << groupRect.right;
|
||||||
|
|
||||||
|
AiEngineCameraTarget target;
|
||||||
|
target.rectangle = groupRect;
|
||||||
|
target.index = index++;
|
||||||
|
emit zoomToAiTarget(target);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include "aiengineinference.h"
|
||||||
|
#include "aienginegimbalserver.h"
|
||||||
|
#include "aienginedefinitions.h"
|
||||||
|
|
||||||
|
class AiEngineGimbalClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit AiEngineGimbalClient(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void aiTargetZoomedSlot(AiEngineTargetPosition targetPosition);
|
||||||
|
void cameraPositionSlot(AiEngineCameraPosition cameraPosition);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void inferenceResultSlot(AiEngineInferenceResult results);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void setDronePosition(AiEngineDronePosition);
|
||||||
|
void zoomToAiTarget(AiEngineCameraTarget);
|
||||||
|
void setCameraPosition(AiEngineCameraPosition);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AiEngineRectangle getGroupCoordinates(QVector<AiEngineObject> &objects);
|
||||||
|
AiEngineGimbalServer *mGimbalServer;
|
||||||
|
};
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#include <QDebug>
|
|
||||||
#include <QVector>
|
|
||||||
#include "aienginegimbalcontrol.h"
|
|
||||||
|
|
||||||
AiEngineGimbalControl::AiEngineGimbalControl(QObject *parent)
|
|
||||||
: QObject{parent}
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
AiEngineRectangle AiEngineGimbalControl::getGroupCoordinates(QVector<AiEngineObject> &objects)
|
|
||||||
{
|
|
||||||
AiEngineRectangle groupRectangle;
|
|
||||||
groupRectangle.top = 1000000;
|
|
||||||
groupRectangle.left = 1000000;
|
|
||||||
groupRectangle.bottom = 0;
|
|
||||||
groupRectangle.right = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < objects.size(); i++) {
|
|
||||||
const AiEngineRectangle &objectRectangle = objects[i].rectangle;
|
|
||||||
|
|
||||||
if (objectRectangle.top < groupRectangle.top) {
|
|
||||||
groupRectangle.top = objectRectangle.top;
|
|
||||||
}
|
|
||||||
if (objectRectangle.left < groupRectangle.left) {
|
|
||||||
groupRectangle.left = objectRectangle.left;
|
|
||||||
}
|
|
||||||
if (objectRectangle.bottom > groupRectangle.bottom) {
|
|
||||||
groupRectangle.bottom = objectRectangle.bottom;
|
|
||||||
}
|
|
||||||
if (objectRectangle.right > groupRectangle.right) {
|
|
||||||
groupRectangle.right = objectRectangle.right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupRectangle;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AiEngineGimbalControl::inferenceResultSlot(AiEngineInferenceResult result)
|
|
||||||
{
|
|
||||||
if (result.objects.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We got list of all recognized objects, but at least for now we will zoom to all objects at
|
|
||||||
// once and not for each invidually. Got minimal coordinates which contains the all objects.
|
|
||||||
AiEngineRectangle groupRect = getGroupCoordinates(result.objects);
|
|
||||||
|
|
||||||
// AI did inference with 640x360 resolution. Scale back to A8's 1280x720 resolution.
|
|
||||||
groupRect.top *= 2;
|
|
||||||
groupRect.left *= 2;
|
|
||||||
groupRect.bottom *= 2;
|
|
||||||
groupRect.right *= 2;
|
|
||||||
|
|
||||||
if (groupRect.top > 720 || groupRect.bottom > 720) {
|
|
||||||
qDebug() << "ERROR! inferenceResultSlot() groupRect.top > 720 || groupRect.bottom > 720";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (groupRect.left > 1280 || groupRect.right > 1280) {
|
|
||||||
qDebug() << "ERROR! inferenceResultSlot() groupRect.left > 1280 || groupRect.right > 1280";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((groupRect.bottom <= groupRect.top) || (groupRect.right <= groupRect.left)) {
|
|
||||||
qDebug() << "ERROR! (groupRect.bottom <= groupRect.top) || (groupRect.right <= groupRect.left)";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "TUOMAS!! Zooming to square top=" << groupRect.top << "x" << groupRect.left << "and bottom:" << groupRect.bottom << "x" << groupRect.right;
|
|
||||||
|
|
||||||
mRemoteControl.sendData(groupRect.top, groupRect.left, groupRect.bottom, groupRect.right);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QElapsedTimer>
|
|
||||||
#include "aiengineinference.h"
|
|
||||||
#include "remoteControl.hpp"
|
|
||||||
|
|
||||||
class AiEngineGimbalControl : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit AiEngineGimbalControl(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
AiEngineRectangle getGroupCoordinates(QVector<AiEngineObject> &objects);
|
|
||||||
RemoteControl mRemoteControl;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void inferenceResultSlot(AiEngineInferenceResult results);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
#include "aienginegimbalserver.h"
|
||||||
|
|
||||||
|
AiEngineGimbalServer::AiEngineGimbalServer(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
{
|
||||||
|
mSerialPort = new QSerialPort(this);
|
||||||
|
// TODO!! Setup and use serial port....
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO!! Client doesn't really send any signal yet to this slot.
|
||||||
|
void AiEngineGimbalServer::dronePositionSlot(AiEngineDronePosition position)
|
||||||
|
{
|
||||||
|
qDebug() << "AiEngineGimbalServer::dronePositionSlot() Server got new drone position:"
|
||||||
|
<< position.position.lat
|
||||||
|
<< position.position.lon
|
||||||
|
<< position.position.alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This is actually called from the client.
|
||||||
|
void AiEngineGimbalServer::zoomToAiTargetSlot(AiEngineCameraTarget target)
|
||||||
|
{
|
||||||
|
qDebug() << "AiEngineGimbalServer::zoomToAiTargetSlot() Move camera to the new target:"
|
||||||
|
<< "index:" << target.index
|
||||||
|
<< "pos:" << target.rectangle.top << target.rectangle.left << target.rectangle.bottom << target.rectangle.right;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO!! Not sent from the client yet.
|
||||||
|
void AiEngineGimbalServer::cameraPositionSlot(AiEngineCameraPosition position)
|
||||||
|
{
|
||||||
|
qDebug() << "SAiEngineGimbalServer::cameraPositionSlot() Move camera to:" << position.pitch << position.yaw << "zoom:" << position.zoom;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSerialPort>
|
||||||
|
#include "aienginedefinitions.h"
|
||||||
|
|
||||||
|
class AiEngineGimbalServer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit AiEngineGimbalServer(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void dronePositionSlot(AiEngineDronePosition);
|
||||||
|
void zoomToAiTargetSlot(AiEngineCameraTarget);
|
||||||
|
void cameraPositionSlot(AiEngineCameraPosition);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void aiTargetZoomed(AiEngineTargetPosition);
|
||||||
|
void newCameraPosition(AiEngineCameraPosition);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSerialPort *mSerialPort;
|
||||||
|
};
|
||||||
@@ -5,21 +5,13 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <opencv2/core.hpp>
|
#include <opencv2/core.hpp>
|
||||||
#include <opencv2/imgproc.hpp>
|
#include <opencv2/imgproc.hpp>
|
||||||
|
#include "aienginedefinitions.h"
|
||||||
|
|
||||||
|
|
||||||
const int INFERENCE_SQUARE_WIDTH = 640;
|
const int INFERENCE_SQUARE_WIDTH = 640;
|
||||||
const int INFERENCE_SQUARE_HEIGHT = 640;
|
const int INFERENCE_SQUARE_HEIGHT = 640;
|
||||||
|
|
||||||
|
|
||||||
class AiEngineRectangle {
|
|
||||||
public:
|
|
||||||
int left;
|
|
||||||
int top;
|
|
||||||
int right;
|
|
||||||
int bottom;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class AiEngineObject {
|
class AiEngineObject {
|
||||||
public:
|
public:
|
||||||
AiEngineRectangle rectangle;
|
AiEngineRectangle rectangle;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
QT += core network
|
QT += core network serialport
|
||||||
QT -= gui
|
QT -= gui
|
||||||
CONFIG += c++11 link_pkgconfig concurrent console
|
CONFIG += c++11 link_pkgconfig concurrent console
|
||||||
PKGCONFIG += opencv4
|
PKGCONFIG += opencv4
|
||||||
@@ -6,7 +6,8 @@ MOC_DIR = moc
|
|||||||
OBJECTS_DIR = obj
|
OBJECTS_DIR = obj
|
||||||
|
|
||||||
SOURCES = $$PWD/*.cpp $$PWD/../../misc/camera/a8_remote/remoteControl.cpp
|
SOURCES = $$PWD/*.cpp $$PWD/../../misc/camera/a8_remote/remoteControl.cpp
|
||||||
HEADERS = $$PWD/*.h
|
HEADERS = $$PWD/*.h \
|
||||||
|
aienginedefinitions.h
|
||||||
INCLUDEPATH += $$PWD/../../misc/camera/a8_remote
|
INCLUDEPATH += $$PWD/../../misc/camera/a8_remote
|
||||||
|
|
||||||
opi5 {
|
opi5 {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ AiEngineInferenceOpencvOnnx::AiEngineInferenceOpencvOnnx(QString modelPath, QObj
|
|||||||
void AiEngineInferenceOpencvOnnx::performInferenceSlot(cv::Mat frame)
|
void AiEngineInferenceOpencvOnnx::performInferenceSlot(cv::Mat frame)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
//qDebug() << "performInferenceSlot() in thread: " << QThread::currentThreadId();
|
qDebug() << "performInferenceSlot() in thread: " << QThread::currentThreadId();
|
||||||
|
|
||||||
mActive = true;
|
mActive = true;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user