建立 MAG160C 逆向工程交接仓库
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
V1.2.2
|
||||
1. Add feature: GetDefaultCalibration(), wrapper for simply using.
|
||||
2. Add feature: SetThreshold(), opening interface for threshold adjustment.
|
||||
3. Add feature: SetCameraLightParameter(), using for low-lux environment.
|
||||
|
||||
V1.2.1
|
||||
1. Add feature: notify sensor failure: onFail() in INewDistance (available on TCM version:V1.21 210120 or above)
|
||||
2. Add feature: soft reset TCM SoftResetTCM(), which can be used if sensor is malfunctional. (available on TCM version:V1.21 210120 or above)
|
||||
|
||||
V1.1.0
|
||||
1. Add feature: store/load calibration data on hardware (available on TCM version:V1.1 201117 or above)
|
||||
2. Add notification: limit switch on/off
|
||||
3. Fix some bugs.
|
||||
|
||||
|
||||
V1.0.1
|
||||
1. Add smart mode
|
||||
|
||||
V1.0.0
|
||||
1. First release.
|
||||
@@ -0,0 +1,167 @@
|
||||
Coding Tips V1.2.2:
|
||||
1. We add GetDefaultCalibration() method, which used for get default calibration X,Y.
|
||||
Code logic:
|
||||
a) Getting from hardware. Return if yes, otherwise,
|
||||
b) Getting from pre-calibration data. Return if yes, otherwise,
|
||||
c) Return default X,Y
|
||||
|
||||
Sample codes:
|
||||
int defaults[2] = {0,0};
|
||||
GetDefaultCalibration(defaults);
|
||||
EloUVCCameraConverter::setOffset(defaults[0], defaults[1]);
|
||||
|
||||
For early version of IRKit, we strongly recommand ISV do manual calibration rather than using default X,Y
|
||||
|
||||
|
||||
2. We add SetThreshold(), interface for threshold adjustment.
|
||||
* Default thershold is 0.8f, 0.8f, 0.6f (values are different from Android Version!!!)
|
||||
You can set threshold of face tracking algorithm now. Decrease threshold can increase possibility of finding facing. But it will increase false negative (FN) as well.
|
||||
Sample codes in SmartWidget:
|
||||
SetThreshold(0.5f,0.5f,0.5f);
|
||||
|
||||
|
||||
|
||||
|
||||
3. We add SetCameraLightParameter(), using for low-lux environment. (values are different from Android Version!!!)
|
||||
The higher value leads to the brighter(more white) image.
|
||||
|
||||
For example:
|
||||
|
||||
SetCameraLightParameter(0, 1, 100); //Reset to default in normal environment
|
||||
|
||||
Or,
|
||||
|
||||
SetCameraLightParameter(64, 3, 300); //setting brightness, backlightComp and gamma, in dark environment.
|
||||
|
||||
|
||||
Coding Tips V1.2.1:
|
||||
1. In order to use new feature, firmware update in required.
|
||||
The path of TCM's firmware is under firmware/IR V1.21 210120.bin.
|
||||
|
||||
2. SoftResetTCM() can be used if sensor is malfunctional.
|
||||
|
||||
3. A whole machine power off/on is required after firmware update, please do not use SoftResetTCM() instead.
|
||||
|
||||
|
||||
Coding Tips V1.1.0:
|
||||
1. What's new in firmware of TCM V1.1? Do I need to update firmware?
|
||||
|
||||
The firmware of TCM V1.1 includes calibartion data saving (offsetX and offsetY).
|
||||
|
||||
If you are working well and do the calibration by your own, you don't have to update the firmware.
|
||||
If you want to save/load the calibration data between AIOs, you can consider upgrading the firmware.
|
||||
|
||||
* Please notice: In SDK 1.0.1 and before, the cabibration data is saved on values of application.
|
||||
Therefore, if you re-install application or move IR Kit to another AIO will lead to an extra calibration.
|
||||
|
||||
|
||||
2. How to update firmware if I have an older Kit?
|
||||
The IR Kit in DVT stage or later supports firmware upgrade.
|
||||
The path of TCM's firmware is under firmware/IR V1.1b.bin.
|
||||
|
||||
Reference code (see in testwidget.cpp):
|
||||
|
||||
QFileDialog *fileDialog = new QFileDialog(this);
|
||||
fileDialog->setWindowTitle(tr("Open File"));
|
||||
fileDialog->setDirectory(".");
|
||||
fileDialog->setNameFilter(tr("Firmware Files(*.bin)"));
|
||||
if(fileDialog->exec() == QDialog::Accepted) {
|
||||
QString path = fileDialog->selectedFiles()[0];
|
||||
if (path.isEmpty() == false) {
|
||||
QFile file (path);
|
||||
bool isOk = file.open(QIODevice::ReadOnly);
|
||||
if (isOk)
|
||||
{
|
||||
QByteArray array = file.readAll();
|
||||
int length = array.size();
|
||||
char* firm = array.data();
|
||||
SetFirmwareData((const unsigned char*)firm, length);
|
||||
file.close();
|
||||
|
||||
StartUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Callback:
|
||||
SetUpdateCallback(onUpdate);
|
||||
|
||||
void TestWidget::onUpdateCallback(bool isSuc, int prog) {
|
||||
if (isSuc) {
|
||||
emit updateLabel(_txTCMVersion, QString::asprintf("Update:%d Suc", prog));
|
||||
}
|
||||
else {
|
||||
emit updateLabel(_txTCMVersion, QString::asprintf("Update:%d Fail", prog));
|
||||
}
|
||||
}
|
||||
|
||||
* "isSuc == true and prog == 100" means update successfully.
|
||||
|
||||
Important!!
|
||||
a) Please DO NOT disconnect or power off IR Kit when you are updating firmware (prog != 100).
|
||||
b) No matter the update is successful or not, you are required to switch off/on the whole machine to make changes valid. (Power off entire AIO and IR Kit, then power on).
|
||||
|
||||
|
||||
3. How to use feature: store/load calibration data on hardware (available on TCM version:V1.1 201117 or above)
|
||||
If IR kit on your side is V1.1 already, you can use this feature already. The calibration data is preseted. (640*480 resolution).
|
||||
If you are updating to V1.1, you are required to save data at the first time,
|
||||
|
||||
|
||||
void TestWidget::on_btnSavePreset_clicked()
|
||||
{
|
||||
QString serial = _txSerial->text();
|
||||
if (serial.length() == 0) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Serial empty!"));
|
||||
return;
|
||||
}
|
||||
else if (serial.length() > 12) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Serial too long!"));
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray arr;
|
||||
arr.append(serial);
|
||||
const char *str = arr.data();
|
||||
bool isOK = UpdatePreset(EloUVCCameraConverter::getOffsetX(),
|
||||
EloUVCCameraConverter::getOffsetY(),
|
||||
str);
|
||||
|
||||
if (isOK) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Save success!"));
|
||||
}
|
||||
else {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Save failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Then, you can get data via method
|
||||
|
||||
int x, y;
|
||||
bool hasPreset = HasPreset();
|
||||
if (hasPreset) {
|
||||
x = GetPresetOffsetX();
|
||||
y = GetPresetOffsetY();
|
||||
char serial[50] = {0};
|
||||
GetPresetSerial(serial);
|
||||
emit updateEdit(_txSerial, QString::asprintf("%s", serial));
|
||||
|
||||
}
|
||||
else {
|
||||
x = EloUVCCameraConverter::getOffsetX();
|
||||
y = EloUVCCameraConverter::getOffsetY();
|
||||
}
|
||||
EloUVCCameraConverter::setOffset(x, y);
|
||||
updateOffset();
|
||||
|
||||
|
||||
4. What's limit notification?
|
||||
Limit notification is a notification which indicate the motor is reached to the bottom of the IR Kit, or gives a zero-point of the angle of rotation.
|
||||
|
||||
You can add code like this:
|
||||
|
||||
SetLimitEventListener(onLimit);
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifdef _WINDOWS
|
||||
#ifdef CAMERASDK_EXPORTS
|
||||
#define CAMERASDK_API __declspec(dllexport)
|
||||
#else
|
||||
#define CAMERASDK_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define CAMERASDK_API
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define CALL_CONVENTION __stdcall
|
||||
#else
|
||||
#define CALL_CONVENTION
|
||||
#endif
|
||||
typedef void(CALL_CONVENTION * INewUVCFrame)(const unsigned char*, int, int, int);
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
CAMERASDK_API bool CALL_CONVENTION OpenCamera(int num, int width, int height);
|
||||
CAMERASDK_API void CALL_CONVENTION CloseCamera();
|
||||
|
||||
CAMERASDK_API void CALL_CONVENTION SetNewUVCFrame(INewUVCFrame call);
|
||||
CAMERASDK_API void CALL_CONVENTION SetCameraLightParameter(double brightness, double backlightComp, double gamma);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef THERMAL_DEF
|
||||
#define THERMAL_DEF
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define CALL_CONVENTION __stdcall
|
||||
#else
|
||||
#define CALL_CONVENTION
|
||||
#endif
|
||||
|
||||
const static int IR_HEIGHT = 120;
|
||||
const static int IR_WIDTH = 160;
|
||||
|
||||
const static int Thermal_Unit_Metric = 0;
|
||||
const static int Thermal_Unit_US = 1;
|
||||
|
||||
const static double Thermal_Invalid_Temp = -1e8;
|
||||
const static double Thermal_Default_Fever_Threshold = 37.0;
|
||||
const static double Thermal_Default_Boundary_Low = 32.0;
|
||||
const static double Thermal_Default_Boundary_High = 40.0;
|
||||
|
||||
|
||||
const static int Thermal_Judgement_Illegal_Temp = -2;
|
||||
const static int Thermal_Judgement_Beyond_Boundary = -1;
|
||||
const static int Thermal_Judgement_Normal = 0;
|
||||
const static int Thermal_Judgement_Fever = 1;
|
||||
|
||||
|
||||
typedef void(CALL_CONVENTION* INewIRFrame)(const unsigned char*, int, int, int);
|
||||
typedef void(CALL_CONVENTION* INewDistance)(float distance);
|
||||
typedef void(CALL_CONVENTION* IDistanceError)();
|
||||
|
||||
typedef void(CALL_CONVENTION* INewLimitEvent)(bool inplace);
|
||||
|
||||
typedef void(CALL_CONVENTION* UpdateCallback)(bool, int);
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
}PointF;
|
||||
typedef struct {
|
||||
PointF point;
|
||||
double tempRaw;
|
||||
double tempArm;
|
||||
int unit;
|
||||
int judgement;
|
||||
}TemperatureResult;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
}Rect;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double width;
|
||||
double height;
|
||||
}RectF;
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifdef _WINDOWS
|
||||
#ifdef FACETRACKINGSDK_EXPORTS
|
||||
#define FACETRACKINGSDK_API __declspec(dllexport)
|
||||
#else
|
||||
#define FACETRACKINGSDK_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define FACETRACKINGSDK_API
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define CALL_CONVENTION __stdcall
|
||||
#else
|
||||
#define CALL_CONVENTION
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
FACETRACKINGSDK_API bool CALL_CONVENTION LoadNetwork();
|
||||
|
||||
FACETRACKINGSDK_API int CALL_CONVENTION DetectFaces(const unsigned char* pBuf, int width, int height, int channel,
|
||||
unsigned char* outRects, int maxOut,
|
||||
int minFace);
|
||||
|
||||
FACETRACKINGSDK_API void CALL_CONVENTION SetThreshold(float p, float r, float o);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "INIParser.h"
|
||||
|
||||
//remove before and after blank space
|
||||
string& INIParser::TrimString(string &str)
|
||||
{
|
||||
string::size_type pos = 0;
|
||||
while(str[pos] == ' ' && str.npos != (pos = str.find(" ")))
|
||||
str = str.replace(pos, pos+1, "");
|
||||
|
||||
pos = str.size()-1;
|
||||
while(str[pos] == ' ')
|
||||
{
|
||||
str = str.replace(pos, pos+1, "");
|
||||
pos--;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
//read in INI file and parse it
|
||||
int INIParser::ReadINI(string path)
|
||||
{
|
||||
ifstream in_conf_file(path.c_str());
|
||||
if(!in_conf_file) return 0;
|
||||
string str_line = "";
|
||||
string str_root = "";
|
||||
vector<ININode> vec_ini;
|
||||
while(getline(in_conf_file, str_line))
|
||||
{
|
||||
string::size_type left_pos = 0;
|
||||
string::size_type right_pos = 0;
|
||||
string::size_type equal_div_pos = 0;
|
||||
string str_key = "";
|
||||
string str_value = "";
|
||||
if((str_line.npos != (left_pos = str_line.find("["))) && (str_line.npos != (right_pos = str_line.find("]"))))
|
||||
str_root = str_line.substr(left_pos+1, right_pos-1);
|
||||
|
||||
if(str_line.npos != (equal_div_pos = str_line.find("=")))
|
||||
{
|
||||
str_key = str_line.substr(0, equal_div_pos);
|
||||
str_value = str_line.substr(equal_div_pos+1, str_line.size()-1);
|
||||
str_key = TrimString(str_key);
|
||||
str_value = TrimString(str_value);
|
||||
}
|
||||
|
||||
if((!str_root.empty()) && (!str_key.empty()) && (!str_value.empty()))
|
||||
{
|
||||
ININode ini_node(str_root, str_key, str_value);
|
||||
vec_ini.push_back(ini_node);
|
||||
}
|
||||
}
|
||||
in_conf_file.close();
|
||||
in_conf_file.clear();
|
||||
|
||||
//vector convert to set
|
||||
set<string> set_tmp;
|
||||
for(vector<ININode>::iterator itr = vec_ini.begin(); itr != vec_ini.end(); ++itr)
|
||||
{
|
||||
set_tmp.insert(itr->root);
|
||||
}
|
||||
|
||||
SubNode sn;
|
||||
for(set<string>::iterator itr = set_tmp.begin(); itr != set_tmp.end(); ++itr)
|
||||
{
|
||||
for(vector<ININode>::iterator sub_itr = vec_ini.begin(); sub_itr != vec_ini.end(); ++sub_itr)
|
||||
{
|
||||
if(sub_itr->root == (*itr))
|
||||
sn.InsertElement(sub_itr->key, sub_itr->value);
|
||||
}
|
||||
map_ini.insert(make_pair((*itr), sn));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//get value by root and key
|
||||
string INIParser::GetValue(string root, string key)
|
||||
{
|
||||
map<string, SubNode>::iterator itr = map_ini.find(root);
|
||||
if (itr == map_ini.end()) {
|
||||
return "";
|
||||
}
|
||||
map<string, string>::iterator sub_itr = itr->second.sub_node.find(key);
|
||||
if (sub_itr != itr->second.sub_node.end()) {
|
||||
return sub_itr->second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//write ini file
|
||||
int INIParser::WriteINI(string path)
|
||||
{
|
||||
ofstream out_conf_file(path.c_str());
|
||||
if(!out_conf_file)
|
||||
return -1;
|
||||
|
||||
for(map<string, SubNode>::iterator itr = map_ini.begin(); itr != map_ini.end(); ++itr)
|
||||
{
|
||||
out_conf_file << "[" << itr->first << "]" << endl;
|
||||
for(map<string, string>::iterator sub_itr = itr->second.sub_node.begin(); sub_itr != itr->second.sub_node.end(); ++sub_itr)
|
||||
out_conf_file << sub_itr->first << "=" << sub_itr->second << endl;
|
||||
}
|
||||
|
||||
out_conf_file.close();
|
||||
out_conf_file.clear();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//set value
|
||||
vector<INIParser::ININode>::size_type INIParser::SetValue(string root, string key, string value)
|
||||
{
|
||||
map<string, SubNode>::iterator itr = map_ini.find(root);
|
||||
if(map_ini.end() != itr)
|
||||
{
|
||||
itr->second.sub_node[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
SubNode sn;
|
||||
sn.InsertElement(key, value);
|
||||
map_ini.insert(make_pair(root, sn));
|
||||
}
|
||||
return map_ini.size();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef INI_PARSER_H
|
||||
#define INI_PARSER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <set>
|
||||
using namespace std;
|
||||
|
||||
class INIParser
|
||||
{
|
||||
public:
|
||||
// inner class ININode
|
||||
class ININode
|
||||
{
|
||||
public:
|
||||
ININode(string r, string k, string v): root(r), key(k), value(v){}
|
||||
string root;
|
||||
string key;
|
||||
string value;
|
||||
};
|
||||
// inner class SubNode
|
||||
class SubNode
|
||||
{
|
||||
public:
|
||||
void InsertElement(string key, string value)
|
||||
{
|
||||
sub_node.insert(make_pair(key, value));
|
||||
}
|
||||
map<string, string> sub_node;
|
||||
};
|
||||
|
||||
/** member of class INIParser */
|
||||
string& TrimString(string &str);
|
||||
int ReadINI(string path);
|
||||
string GetValue(string root, string key);
|
||||
vector<ININode>::size_type GetSize(){return map_ini.size();}
|
||||
vector<ININode>::size_type SetValue(string root, string key, string value);
|
||||
int WriteINI(string path);
|
||||
void Clear(){map_ini.clear();}
|
||||
private:
|
||||
map<string, SubNode> map_ini;
|
||||
};
|
||||
|
||||
#endif // INI_PARSER_H
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifdef _WINDOWS
|
||||
#ifdef THERMALSDK_EXPORTS
|
||||
#define THERMALSDK_API __declspec(dllexport)
|
||||
#else
|
||||
#define THERMALSDK_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define THERMALSDK_API
|
||||
#endif
|
||||
|
||||
#include "Def.h"
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
THERMALSDK_API int CALL_CONVENTION GetSDKVersion();
|
||||
|
||||
THERMALSDK_API bool CALL_CONVENTION Start();
|
||||
THERMALSDK_API void CALL_CONVENTION Stop();
|
||||
THERMALSDK_API bool CALL_CONVENTION IsWorking();
|
||||
THERMALSDK_API bool CALL_CONVENTION IsTCMOpen();
|
||||
THERMALSDK_API bool CALL_CONVENTION IsIROpen();
|
||||
|
||||
THERMALSDK_API void CALL_CONVENTION SetNewIRFrameDelegate(INewIRFrame call);
|
||||
THERMALSDK_API void CALL_CONVENTION SetNewDistanceDelegate(INewDistance call);
|
||||
THERMALSDK_API void CALL_CONVENTION SetDistanceError(IDistanceError call);
|
||||
|
||||
THERMALSDK_API void CALL_CONVENTION ReadTemperatureAtPoint(int x, int y, unsigned char* buffer);
|
||||
THERMALSDK_API void CALL_CONVENTION ReadTemperatureInRect(int x, int y, int width, int height, unsigned char* buffer);
|
||||
|
||||
THERMALSDK_API void CALL_CONVENTION SetTempBoundary(double low, double high, double fever);
|
||||
THERMALSDK_API void CALL_CONVENTION SetTempOffset(double offset);
|
||||
THERMALSDK_API void CALL_CONVENTION SetUnitMode(int unitMode);
|
||||
THERMALSDK_API bool CALL_CONVENTION Rotate(int val);
|
||||
|
||||
|
||||
THERMALSDK_API double CALL_CONVENTION GetInnerIRCameraTemp();
|
||||
THERMALSDK_API void CALL_CONVENTION GetInnerIRCameraSerial(char * serial);
|
||||
|
||||
THERMALSDK_API void CALL_CONVENTION SetEmissivity(double emis);
|
||||
THERMALSDK_API bool CALL_CONVENTION Trigger();
|
||||
|
||||
|
||||
THERMALSDK_API void CALL_CONVENTION GetTCMVersion(char *version);
|
||||
THERMALSDK_API void CALL_CONVENTION SetFirmwareData(const unsigned char* firm, int length);
|
||||
THERMALSDK_API void CALL_CONVENTION SetUpdateCallback(UpdateCallback call);
|
||||
THERMALSDK_API void CALL_CONVENTION StartUpdate();
|
||||
|
||||
THERMALSDK_API void CALL_CONVENTION SetLimitEventListener(INewLimitEvent eventListener);
|
||||
THERMALSDK_API bool CALL_CONVENTION LimitReset();
|
||||
THERMALSDK_API bool CALL_CONVENTION SoftResetTCM();
|
||||
|
||||
|
||||
THERMALSDK_API bool CALL_CONVENTION UpdatePreset(int offsetX, int offsetY, const char* serial);
|
||||
THERMALSDK_API bool CALL_CONVENTION HasPreset();
|
||||
THERMALSDK_API int CALL_CONVENTION GetPresetOffsetX();
|
||||
THERMALSDK_API int CALL_CONVENTION GetPresetOffsetY();
|
||||
THERMALSDK_API void CALL_CONVENTION GetDefaultCalibration(int *data);
|
||||
THERMALSDK_API void CALL_CONVENTION GetPresetSerial(char* serial);
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
#include "basewidget.h"
|
||||
#include "ui_basewidget.h"
|
||||
#include "ThermalSDK.h"
|
||||
#include "CameraSDK.h"
|
||||
#include "elouvccameraconverter.h"
|
||||
#include <thread>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#endif
|
||||
BaseWidget *thiz = nullptr;
|
||||
|
||||
int getCameraIndex_linux() {
|
||||
int ret = 0;
|
||||
FILE *fp = popen("ls -al /dev/video*", "r");
|
||||
if (fp == NULL) {
|
||||
return ret;
|
||||
}
|
||||
while (!feof(fp)) {
|
||||
char buffer[1024];
|
||||
fgets(buffer, 1024, fp);
|
||||
std::string str = buffer;
|
||||
auto pos = str.find("/dev/video");
|
||||
if (pos != std::string::npos) {
|
||||
std::string substr = str.substr(pos + 10);
|
||||
ret = atoi(substr.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
pclose(fp);
|
||||
return ret;
|
||||
}
|
||||
void onUVC(const unsigned char* buffer, int width, int height, int channel) {
|
||||
if (thiz) {
|
||||
thiz->onUVCFrame(buffer, width, height, channel);
|
||||
}
|
||||
}
|
||||
void onIR(const unsigned char*buffer, int width, int height, int channel) {
|
||||
if (thiz) {
|
||||
thiz->onIRFrame(buffer, width, height, channel);
|
||||
}
|
||||
}
|
||||
void onDist(float distance) {
|
||||
if (thiz) {
|
||||
thiz->onDistance(distance);
|
||||
}
|
||||
}
|
||||
void onLimit(bool inplace) {
|
||||
if (thiz) {
|
||||
thiz->onLimitEvent(inplace);
|
||||
}
|
||||
}
|
||||
|
||||
void onUpdate(bool isSuc, int prog) {
|
||||
if (thiz) {
|
||||
thiz->onUpdateCallback(isSuc, prog);
|
||||
}
|
||||
}
|
||||
|
||||
void onDistError() {
|
||||
if (thiz) {
|
||||
thiz->onDistanceError();
|
||||
}
|
||||
}
|
||||
BaseWidget::BaseWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::BaseWidget)
|
||||
, _qRGBImage(nullptr)
|
||||
, _qIRImage(nullptr)
|
||||
, _RGBImageView(nullptr)
|
||||
, _IRImageView(nullptr)
|
||||
, _isUnitUS(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
onStart();
|
||||
|
||||
//Use default
|
||||
int defaults[2] = {0,0};
|
||||
GetDefaultCalibration(defaults);
|
||||
EloUVCCameraConverter::setOffset(defaults[0], defaults[1]);
|
||||
|
||||
//Or manually calibration
|
||||
int x = EloUVCCameraConverter::getDefaultX();
|
||||
int y = EloUVCCameraConverter::getDefaultY();
|
||||
EloUVCCameraConverter::setOffset(x, y);
|
||||
|
||||
thiz = this;
|
||||
}
|
||||
|
||||
BaseWidget::~BaseWidget()
|
||||
{
|
||||
onStop();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BaseWidget::closeIR() {
|
||||
SetNewIRFrameDelegate(nullptr);
|
||||
SetNewDistanceDelegate(nullptr);
|
||||
SetDistanceError(nullptr);
|
||||
SetLimitEventListener(nullptr);
|
||||
SetUpdateCallback(nullptr);
|
||||
Stop();
|
||||
}
|
||||
void BaseWidget::openIR() {
|
||||
Start();
|
||||
SetNewIRFrameDelegate(onIR);
|
||||
SetNewDistanceDelegate(onDist);
|
||||
SetDistanceError(onDistError);
|
||||
SetLimitEventListener(onLimit);
|
||||
SetUpdateCallback(onUpdate);
|
||||
}
|
||||
void BaseWidget::openCamera() {
|
||||
#if defined(Q_OS_WIN)
|
||||
int cameraIndex = 0;
|
||||
#else
|
||||
int cameraIndex = getCameraIndex_linux();
|
||||
#endif
|
||||
OpenCamera(cameraIndex, 640, 480);
|
||||
SetNewUVCFrame(onUVC);
|
||||
}
|
||||
void BaseWidget::closeCamera() {
|
||||
SetNewUVCFrame(nullptr);
|
||||
CloseCamera();
|
||||
}
|
||||
void BaseWidget::onStart() {
|
||||
openCamera();
|
||||
openIR();
|
||||
|
||||
if (_isUnitUS)
|
||||
{
|
||||
SetUnitMode(Thermal_Unit_US);
|
||||
SetTempBoundary(30 * 1.8 + 32, 44 * 1.8 + 32, 37 * 1.8 + 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetUnitMode(Thermal_Unit_Metric);
|
||||
SetTempBoundary(30, 44, 37);
|
||||
}
|
||||
}
|
||||
void BaseWidget::onStop() {
|
||||
closeIR();
|
||||
closeCamera();
|
||||
}
|
||||
|
||||
|
||||
void BaseWidget::onUVCFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
if (channel != 3) {
|
||||
return;
|
||||
}
|
||||
if (_qRGBImage == NULL) {
|
||||
_qRGBImage = new QImage(width, height,
|
||||
QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
memcpy(_qRGBImage->bits(), buffer, width*height*channel);
|
||||
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
_convBmp = EloUVCCameraConverter::UVCBitmapWithIRSize(_qRGBImage);
|
||||
#else
|
||||
_convBmp = EloUVCCameraConverter::UVCBitmapWithIRSize(_qRGBImage).rgbSwapped();
|
||||
#endif
|
||||
|
||||
if (_RGBImageView) {
|
||||
_RGBImageView->updateImage(&_convBmp);
|
||||
}
|
||||
}
|
||||
void BaseWidget::onIRFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
if (channel != 3) {
|
||||
return;
|
||||
}
|
||||
if (_qIRImage == NULL) {
|
||||
_qIRImage = new QImage(width, height,
|
||||
QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
memcpy(_qIRImage->bits(), buffer, width*height*channel);
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
_irBmp = _qIRImage->rgbSwapped();
|
||||
if (_IRImageView) {
|
||||
_IRImageView->updateImage(&_irBmp);
|
||||
}
|
||||
#else
|
||||
if (_IRImageView) {
|
||||
_IRImageView->updateImage(_qIRImage);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void BaseWidget::onDistance(float distance) {
|
||||
}
|
||||
void BaseWidget::onDistanceError() {
|
||||
}
|
||||
void BaseWidget::onLimitEvent(bool inplace) {
|
||||
|
||||
}
|
||||
void BaseWidget::onUpdateCallback(bool isSuc, int prog) {
|
||||
|
||||
}
|
||||
|
||||
void BaseWidget::onUpdateImageView(ImageView* imgview) {
|
||||
imgview->update();
|
||||
}
|
||||
void BaseWidget::onNormal() {
|
||||
|
||||
}
|
||||
void BaseWidget::onAbnormal() {
|
||||
|
||||
}
|
||||
void BaseWidget::onNobody() {
|
||||
|
||||
}
|
||||
void BaseWidget::rotate(int angle) {
|
||||
Rotate(angle);
|
||||
}
|
||||
void BaseWidget::trigger() {
|
||||
Trigger();
|
||||
}
|
||||
int BaseWidget::getCurrentTime() {
|
||||
#if defined(Q_OS_WIN)
|
||||
return GetTickCount();
|
||||
#else
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef BASEWIDGET_H
|
||||
#define BASEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "imageview.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class BaseWidget; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class BaseWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BaseWidget(QWidget *parent = nullptr);
|
||||
~BaseWidget();
|
||||
|
||||
protected:
|
||||
virtual void onStart();
|
||||
virtual void onStop();
|
||||
|
||||
virtual void rotate(int angle);
|
||||
virtual void trigger();
|
||||
|
||||
QImage* _qRGBImage;
|
||||
QImage* _qIRImage;
|
||||
QImage _convBmp;
|
||||
QImage _irBmp;
|
||||
ImageView *_RGBImageView;
|
||||
ImageView *_IRImageView;
|
||||
|
||||
public:
|
||||
virtual void onUVCFrame(const unsigned char* buffer, int width, int height, int channel);
|
||||
virtual void onIRFrame(const unsigned char* buffer, int width, int height, int channel);
|
||||
virtual void onDistance(float distance);
|
||||
virtual void onDistanceError();
|
||||
virtual void onLimitEvent(bool inplace);
|
||||
virtual void onUpdateCallback(bool isSuc, int prog);
|
||||
|
||||
virtual void onNormal();
|
||||
virtual void onAbnormal();
|
||||
virtual void onNobody();
|
||||
static int getCurrentTime();
|
||||
|
||||
bool _isUnitUS;
|
||||
|
||||
signals:
|
||||
void updateImageView(ImageView* imgview);
|
||||
private slots:
|
||||
void onUpdateImageView(ImageView* imgview);
|
||||
|
||||
protected:
|
||||
void closeIR();
|
||||
void openIR();
|
||||
void openCamera();
|
||||
void closeCamera();
|
||||
|
||||
Ui::BaseWidget *ui;
|
||||
|
||||
};
|
||||
#endif // BASEWIDGET_H
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BaseWidget</class>
|
||||
<widget class="QWidget" name="BaseWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>BaseWidget</string>
|
||||
</property>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "elouvccameraconverter.h"
|
||||
#include "INIParser.h"
|
||||
|
||||
int EloUVCCameraConverter::UVC_WIDTH = 640;
|
||||
int EloUVCCameraConverter::UVC_HEIGHT = 480;
|
||||
|
||||
int EloUVCCameraConverter::IR_WIDTH = 160;
|
||||
int EloUVCCameraConverter::IR_HEIGHT = 120;
|
||||
|
||||
int EloUVCCameraConverter::IR_SCALED_WIDTH = 320;
|
||||
int EloUVCCameraConverter::IR_SCALED_HEIGHT = 240;
|
||||
|
||||
float EloUVCCameraConverter::IR_SCALE = (float)IR_SCALED_HEIGHT / UVC_HEIGHT;
|
||||
|
||||
//(0,0) is at Left/Bottom
|
||||
int EloUVCCameraConverter::CAMERAS_OFFSET_X = 81; //+:上面往左
|
||||
int EloUVCCameraConverter::CAMERAS_OFFSET_Y = 65; //-:上面往上
|
||||
|
||||
std::string PATH = "./conf.ini";
|
||||
QImage EloUVCCameraConverter::UVCBitmapWithIRSize(QImage *uvcImage)
|
||||
{
|
||||
return uvcImage->copy(CAMERAS_OFFSET_X,
|
||||
UVC_HEIGHT - CAMERAS_OFFSET_Y - IR_SCALED_HEIGHT,
|
||||
IR_SCALED_WIDTH,
|
||||
IR_SCALED_HEIGHT);
|
||||
|
||||
}
|
||||
QImage EloUVCCameraConverter::UVCBitmapWithIRWidth(QImage *uvcImage)
|
||||
{
|
||||
return uvcImage->copy(CAMERAS_OFFSET_X,
|
||||
0,
|
||||
IR_SCALED_WIDTH,
|
||||
UVC_HEIGHT);
|
||||
}
|
||||
|
||||
std::vector<RectF> EloUVCCameraConverter::openCVRect2Local(std::vector<Rect> rects)
|
||||
{
|
||||
std::vector<RectF> ret;
|
||||
|
||||
if (rects.size() > 0)
|
||||
{
|
||||
for (int i = 0; i < rects.size(); ++i)
|
||||
{
|
||||
Rect rect = rects[i];
|
||||
RectF rectF;
|
||||
rectF.x = (double)rect.x / IR_SCALED_WIDTH;
|
||||
rectF.width = (double)rect.width / IR_SCALED_WIDTH;
|
||||
rectF.y = (double)(IR_SCALED_HEIGHT + CAMERAS_OFFSET_Y - rect.y- rect.height) / IR_SCALED_HEIGHT;
|
||||
rectF.height = (double)rect.height / IR_SCALED_HEIGHT;
|
||||
ret.push_back(rectF);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
void EloUVCCameraConverter::setOffset(int x, int y){
|
||||
CAMERAS_OFFSET_X = x;
|
||||
CAMERAS_OFFSET_Y = y;
|
||||
}
|
||||
int EloUVCCameraConverter::getOffsetX(){
|
||||
return CAMERAS_OFFSET_X;
|
||||
}
|
||||
int EloUVCCameraConverter::getOffsetY(){
|
||||
return CAMERAS_OFFSET_Y;
|
||||
}
|
||||
int EloUVCCameraConverter::adjustX(int adj){
|
||||
CAMERAS_OFFSET_X += adj;
|
||||
return CAMERAS_OFFSET_X;
|
||||
}
|
||||
int EloUVCCameraConverter::adjustY(int adj) {
|
||||
CAMERAS_OFFSET_Y += adj;
|
||||
return CAMERAS_OFFSET_Y;
|
||||
}
|
||||
int EloUVCCameraConverter::getDefaultX() {
|
||||
INIParser iniParse;
|
||||
iniParse.ReadINI(PATH);
|
||||
std::string str = iniParse.GetValue("UVC", "DefaultX");
|
||||
if (str.length() == 0) {
|
||||
return CAMERAS_OFFSET_X;
|
||||
}
|
||||
else {
|
||||
return atoi(str.c_str());
|
||||
}
|
||||
}
|
||||
int EloUVCCameraConverter::getDefaultY() {
|
||||
INIParser iniParse;
|
||||
iniParse.ReadINI(PATH);
|
||||
std::string str = iniParse.GetValue("UVC", "DefaultY");
|
||||
if (str.length() == 0) {
|
||||
return CAMERAS_OFFSET_Y;
|
||||
}
|
||||
else {
|
||||
return atoi(str.c_str());
|
||||
}
|
||||
}
|
||||
void EloUVCCameraConverter::setDefaultX(int x) {
|
||||
INIParser iniParse;
|
||||
iniParse.ReadINI(PATH);
|
||||
char buf[100] = {0};
|
||||
sprintf(buf, "%d", x);
|
||||
std::string str = buf;
|
||||
iniParse.SetValue("UVC", "DefaultX", str);
|
||||
iniParse.WriteINI(PATH);
|
||||
}
|
||||
void EloUVCCameraConverter::setDefaultY(int y) {
|
||||
INIParser iniParse;
|
||||
iniParse.ReadINI(PATH);
|
||||
char buf[100] = {0};
|
||||
sprintf(buf, "%d", y);
|
||||
std::string str = buf;
|
||||
iniParse.SetValue("UVC", "DefaultY", str);
|
||||
iniParse.WriteINI(PATH);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef ELOUVCCAMERACONVERTER_H
|
||||
#define ELOUVCCAMERACONVERTER_H
|
||||
#include <QWidget>
|
||||
#include "Def.h"
|
||||
|
||||
class EloUVCCameraConverter
|
||||
{
|
||||
public:
|
||||
EloUVCCameraConverter();
|
||||
|
||||
static QImage UVCBitmapWithIRSize(QImage *uvcImage);
|
||||
static QImage UVCBitmapWithIRWidth(QImage *uvcImage);
|
||||
static std::vector<RectF> openCVRect2Local(std::vector<Rect> rects);
|
||||
|
||||
static void setOffset(int x, int y);
|
||||
static int getOffsetX();
|
||||
static int getOffsetY();
|
||||
static int adjustX(int adj);
|
||||
static int adjustY(int adj);
|
||||
|
||||
static int getDefaultX();
|
||||
static int getDefaultY();
|
||||
static void setDefaultX(int x);
|
||||
static void setDefaultY(int y);
|
||||
|
||||
|
||||
|
||||
static int UVC_WIDTH ;
|
||||
static int UVC_HEIGHT;
|
||||
|
||||
static int IR_WIDTH;
|
||||
static int IR_HEIGHT;
|
||||
|
||||
static int IR_SCALED_WIDTH;
|
||||
static int IR_SCALED_HEIGHT;
|
||||
|
||||
static float IR_SCALE;
|
||||
|
||||
//(0,0) is at Left/Bottom
|
||||
static int CAMERAS_OFFSET_X; //+:上面往左
|
||||
static int CAMERAS_OFFSET_Y; //-:上面往上
|
||||
|
||||
};
|
||||
|
||||
#endif // ELOUVCCAMERACONVERTER_H
|
||||
@@ -0,0 +1,120 @@
|
||||
#include "expertwidget.h"
|
||||
#include "ui_expertwidget.h"
|
||||
#include "ThermalSDK.h"
|
||||
#include <stdlib.h>
|
||||
#include "elouvccameraconverter.h"
|
||||
|
||||
ExpertWidget::ExpertWidget(BaseWidget *parent) :
|
||||
BaseWidget(parent),
|
||||
ui(new Ui::ExpertWidget)
|
||||
{
|
||||
lastIRTime = -1;
|
||||
lastDistance = -1;
|
||||
lastValidDistance = -1;
|
||||
lastValidDistanceTime = -1;
|
||||
|
||||
connect(this, SIGNAL(updateImageView(ImageView*)), this,
|
||||
SLOT(onUpdateImageView(ImageView*)));
|
||||
initUI();
|
||||
|
||||
int x, y;
|
||||
bool hasPreset = HasPreset();
|
||||
if (hasPreset) {
|
||||
x = GetPresetOffsetX();
|
||||
y = GetPresetOffsetY();
|
||||
}
|
||||
else {
|
||||
x = EloUVCCameraConverter::getDefaultX();
|
||||
y = EloUVCCameraConverter::getDefaultY();
|
||||
}
|
||||
EloUVCCameraConverter::setOffset(x, y);
|
||||
}
|
||||
|
||||
ExpertWidget::~ExpertWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void ExpertWidget::initUI() {
|
||||
ui->setupUi(this);
|
||||
|
||||
this->_RGBImageView = ui->rgbImage;
|
||||
this->_IRImageView = ui->irImage;
|
||||
|
||||
ui->imgNormal->setVisible(false);
|
||||
ui->imgAbnormal->setVisible(false);
|
||||
}
|
||||
void ExpertWidget::onUVCFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
BaseWidget::onUVCFrame(buffer, width, height, channel);
|
||||
|
||||
if (_RGBImageView) {
|
||||
emit updateImageView(_RGBImageView);
|
||||
}
|
||||
}
|
||||
|
||||
void ExpertWidget::onIRFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
int curTime = getCurrentTime();
|
||||
if (curTime - lastIRTime >= 1000)
|
||||
{
|
||||
if (curTime - lastValidDistanceTime <= 500)
|
||||
{
|
||||
TemperatureResult result;
|
||||
ReadTemperatureAtPoint(80,40, (unsigned char *)&result);
|
||||
_IRImageView->updateSingleResult(&result);
|
||||
|
||||
switch (result.judgement)
|
||||
{
|
||||
case Thermal_Judgement_Normal:
|
||||
onNormal();
|
||||
break;
|
||||
case Thermal_Judgement_Fever:
|
||||
onAbnormal();
|
||||
break;
|
||||
case Thermal_Judgement_Beyond_Boundary:
|
||||
onNobody();
|
||||
break;
|
||||
case Thermal_Judgement_Illegal_Temp:
|
||||
onNobody();
|
||||
break;
|
||||
default:
|
||||
onNobody();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_IRImageView->updateSingleResult(NULL);
|
||||
onNobody();
|
||||
}
|
||||
lastIRTime = curTime;
|
||||
}
|
||||
|
||||
BaseWidget::onIRFrame(buffer, width, height, channel);
|
||||
|
||||
if (_IRImageView) {
|
||||
emit updateImageView(_IRImageView);
|
||||
}
|
||||
}
|
||||
void ExpertWidget::onDistance(float distance) {
|
||||
if (distance > 0)
|
||||
{
|
||||
lastValidDistanceTime = getCurrentTime();
|
||||
lastValidDistance = distance;
|
||||
}
|
||||
lastDistance = distance;
|
||||
}
|
||||
void ExpertWidget::onNormal() {
|
||||
ui->imgNormal->setVisible(true);
|
||||
ui->imgAbnormal->setVisible(false);
|
||||
}
|
||||
void ExpertWidget::onAbnormal() {
|
||||
ui->imgNormal->setVisible(false);
|
||||
ui->imgAbnormal->setVisible(true);
|
||||
}
|
||||
void ExpertWidget::onNobody() {
|
||||
ui->imgNormal->setVisible(false);
|
||||
ui->imgAbnormal->setVisible(false);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef ExpertWidget_H
|
||||
#define ExpertWidget_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "basewidget.h"
|
||||
|
||||
namespace Ui {
|
||||
class ExpertWidget;
|
||||
}
|
||||
|
||||
class ExpertWidget : public BaseWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ExpertWidget(BaseWidget *parent = nullptr);
|
||||
~ExpertWidget();
|
||||
|
||||
protected:
|
||||
void initUI();
|
||||
|
||||
virtual void onUVCFrame(const unsigned char* buffer, int width, int height, int channel) override;
|
||||
virtual void onIRFrame(const unsigned char* buffer, int width, int height, int channel) override;
|
||||
virtual void onDistance(float distance) override;
|
||||
|
||||
virtual void onNormal() override;
|
||||
virtual void onAbnormal() override;
|
||||
virtual void onNobody() override;
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
|
||||
private:
|
||||
|
||||
Ui::ExpertWidget *ui;
|
||||
|
||||
volatile int lastIRTime;
|
||||
volatile float lastDistance;
|
||||
volatile float lastValidDistance;
|
||||
volatile int lastValidDistanceTime;
|
||||
};
|
||||
|
||||
#endif // ExpertWidget_H
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ExpertWidget</class>
|
||||
<widget class="QWidget" name="ExpertWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>930</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Expert</string>
|
||||
</property>
|
||||
<widget class="ImageView" name="rgbImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="ImageView" name="irImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>360</y>
|
||||
<width>480</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="imgNormal">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>165</x>
|
||||
<y>720</y>
|
||||
<width>270</width>
|
||||
<height>240</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="image.qrc">:/new/prefix1/image/normal.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="imgAbnormal">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>165</x>
|
||||
<y>720</y>
|
||||
<width>270</width>
|
||||
<height>240</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="image.qrc">:/new/prefix1/image/abnormal.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="imgCover">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="image.qrc">:/new/prefix1/image/mask2.png</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ImageView</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>imageview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="image.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="/new/prefix1">
|
||||
<file>image/abnormal.png</file>
|
||||
<file>image/mask.png</file>
|
||||
<file>image/mask2.png</file>
|
||||
<file>image/mask_empty.png</file>
|
||||
<file>image/normal.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,117 @@
|
||||
#include <iostream>
|
||||
#include <QPainter>
|
||||
#include <QFont>
|
||||
#include "imageview.h"
|
||||
#include <QApplication>
|
||||
|
||||
ImageView::ImageView(QWidget *parent)
|
||||
: QLabel(parent),
|
||||
_image(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void ImageView::paintEvent(QPaintEvent *) {
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
_drawImage(painter);
|
||||
|
||||
std::vector<TemperatureResult> result;
|
||||
std::vector<RectF> rects;
|
||||
std::vector<TemperatureResult> results;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(_mutexResult);
|
||||
result = _result;
|
||||
rects = _rects;
|
||||
results = _results;
|
||||
}
|
||||
|
||||
if (result.size() > 0) {
|
||||
_drawWithResult(painter, result[0]);
|
||||
}
|
||||
else if ((results.size() > 0) && (rects.size() == results.size())) {
|
||||
for (int i = 0; i < (int)results.size(); ++i) {
|
||||
_drawWithResult(painter, results[i]);
|
||||
_drawWithRect(painter, rects[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageView::updateImage(QImage *image) {
|
||||
_image = image;
|
||||
}
|
||||
void ImageView::updateSingleResult(TemperatureResult* result) {
|
||||
std::lock_guard<std::mutex> lck(_mutexResult);
|
||||
_result.clear();
|
||||
if (result != NULL) {
|
||||
_result.push_back(*result);
|
||||
}
|
||||
}
|
||||
void ImageView::updateFacesAndResults(std::vector<RectF> rects, std::vector<TemperatureResult> results) {
|
||||
std::lock_guard<std::mutex> lck(_mutexResult);
|
||||
_results = results;
|
||||
_rects = rects;
|
||||
}
|
||||
void ImageView::_drawImage(QPainter& painter)
|
||||
{
|
||||
if (_image != NULL) {
|
||||
painter.drawImage(0, 0, _image->mirrored(false, false).scaled(size(), Qt::KeepAspectRatio));
|
||||
}
|
||||
}
|
||||
void ImageView::_drawWithResult(QPainter& painter, TemperatureResult result) {
|
||||
QColor color = QColor(0,255,0);
|
||||
switch (result.judgement) {
|
||||
case Thermal_Judgement_Normal:
|
||||
color = QColor(0,255,0);
|
||||
break;
|
||||
case Thermal_Judgement_Fever:
|
||||
color = QColor(255,0,0);
|
||||
break;
|
||||
case Thermal_Judgement_Beyond_Boundary:
|
||||
color = QColor(255,0,0);
|
||||
break;
|
||||
case Thermal_Judgement_Illegal_Temp:
|
||||
color = QColor(0,0,0,0);
|
||||
break;
|
||||
default:
|
||||
color = QColor(0,0,0,0);
|
||||
break;
|
||||
}
|
||||
|
||||
int lineWidth = 12;
|
||||
painter.setFont(QFont("arial", 12, 2));
|
||||
painter.setPen(color);
|
||||
|
||||
QSize qsize = size();
|
||||
|
||||
//Calc +
|
||||
PointF point = result.point;
|
||||
double X = point.x * qsize.width();
|
||||
double Y = point.y * qsize.height();
|
||||
|
||||
painter.drawLine(X-lineWidth, Y, X+lineWidth, Y);
|
||||
painter.drawLine(X, Y-lineWidth, X, Y+lineWidth);
|
||||
|
||||
|
||||
//Calc String
|
||||
int unitMode = result.unit;
|
||||
std::string strUnit = (unitMode == Thermal_Unit_Metric) ? "°C" : "°F";
|
||||
QString s = QString::asprintf("%.1f %.1f %s", result.tempArm, result.tempRaw, strUnit.c_str());
|
||||
painter.drawText(X+lineWidth, Y+lineWidth*.5, s);
|
||||
}
|
||||
|
||||
void ImageView::_drawWithRect(QPainter& painter, RectF rect) {
|
||||
QSize qsize = size();
|
||||
|
||||
//Draw Rect
|
||||
double left = rect.x * qsize.width();
|
||||
double right = (rect.x + rect.width) * qsize.width();
|
||||
double top = (rect.y) * qsize.height();
|
||||
double bottom = (rect.y + rect.height) * qsize.height();
|
||||
|
||||
painter.drawLine(left, top, left, bottom);
|
||||
painter.drawLine(right, top, right, bottom);
|
||||
painter.drawLine(left, top, right, top);
|
||||
painter.drawLine(left, bottom, right, bottom);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef IMAGE_VIEW
|
||||
#define IMAGE_VIEW
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPoint>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#include "ThermalSDK.h"
|
||||
class ImageView : public QLabel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImageView(QWidget *parent = 0);
|
||||
void updateImage(QImage *image);
|
||||
void updateSingleResult(TemperatureResult* result);
|
||||
void updateFacesAndResults(std::vector<RectF> rects, std::vector<TemperatureResult> results);
|
||||
|
||||
signals:
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *);
|
||||
|
||||
void _drawImage(QPainter& painter);
|
||||
void _drawWithResult(QPainter& painter, TemperatureResult result);
|
||||
void _drawWithRect(QPainter& painter, RectF rect);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
private:
|
||||
QImage* _image;
|
||||
std::vector<TemperatureResult> _result;
|
||||
std::vector<RectF> _rects;
|
||||
std::vector<TemperatureResult> _results;
|
||||
|
||||
std::mutex _mutexResult;
|
||||
};
|
||||
|
||||
#endif // IMAGE_VIEW
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_core.so.4.4.0
|
||||
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_imgcodecs.so.4.4.0
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_imgproc.so.4.4.0
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_videoio.so.4.4.0
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
#include "testwidget.h"
|
||||
#include "expertwidget.h"
|
||||
#include "smartwidget.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
|
||||
if (argc > 1) {
|
||||
std::string str = argv[1];
|
||||
if (str.find("expert") != std::string::npos) {
|
||||
ExpertWidget w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
else if (str.find("smart") != std::string::npos) {
|
||||
SmartWidget w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
else {
|
||||
TestWidget w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
}
|
||||
|
||||
TestWidget w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
|
||||
win32 {
|
||||
LIB_WIN_PATH = $${PWD}/../../release-lib/win
|
||||
LIBS += -L$${LIB_WIN_PATH}
|
||||
LIBS += -lThermalSDK
|
||||
LIBS += -lCameraSDK
|
||||
LIBS += -lFaceTrackingSDK
|
||||
}
|
||||
|
||||
unix {
|
||||
LIB_PATH = $${PWD}/lib
|
||||
LIBS += -L$${LIB_PATH}
|
||||
|
||||
LIBS += -lthermalSDK -lmagcore -lcameraSDK \
|
||||
-lfaceTrackingSDK -fopenmp \
|
||||
-lopencv_core -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc
|
||||
}
|
||||
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any Qt feature that has been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
INIParser.cpp \
|
||||
elouvccameraconverter.cpp \
|
||||
expertwidget.cpp \
|
||||
smartwidget.cpp \
|
||||
imageview.cpp \
|
||||
main.cpp \
|
||||
basewidget.cpp \
|
||||
testwidget.cpp
|
||||
|
||||
HEADERS += \
|
||||
CameraSDK.h \
|
||||
Def.h \
|
||||
FaceTrackingSDK.h \
|
||||
INIParser.h \
|
||||
ThermalSDK.h \
|
||||
basewidget.h \
|
||||
elouvccameraconverter.h \
|
||||
expertwidget.h \
|
||||
smartwidget.h \
|
||||
imageview.h \
|
||||
testwidget.h
|
||||
|
||||
FORMS += \
|
||||
basewidget.ui \
|
||||
expertwidget.ui \
|
||||
smartwidget.ui \
|
||||
testwidget.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
RESOURCES += \
|
||||
image.qrc
|
||||
@@ -0,0 +1,303 @@
|
||||
#include "smartwidget.h"
|
||||
#include "ui_smartwidget.h"
|
||||
#include "ThermalSDK.h"
|
||||
#include <stdlib.h>
|
||||
#include "elouvccameraconverter.h"
|
||||
#include "FaceTrackingSDK.h"
|
||||
#include "CameraSDK.h"
|
||||
#include <vector>
|
||||
|
||||
FaceTrackingThread::FaceTrackingThread(QObject *parent) : QThread(parent)
|
||||
{
|
||||
lastValidUVCTime = -1;
|
||||
nextRotateTime = -1;
|
||||
}
|
||||
|
||||
void FaceTrackingThread::run()
|
||||
{
|
||||
isActive = true;
|
||||
isProcessing = false;
|
||||
|
||||
QImage trackImage;
|
||||
SmartWidget *smartWidget = (SmartWidget*)this->parent();
|
||||
|
||||
while (isActive) {
|
||||
{
|
||||
mutexImage.lock();
|
||||
trackImage = _trackImage;
|
||||
isProcessing = true;
|
||||
mutexImage.unlock();
|
||||
}
|
||||
|
||||
int curTime = BaseWidget::getCurrentTime();
|
||||
Rect outRects[100];
|
||||
int count = DetectFaces(trackImage.bits(), trackImage.width(), trackImage.height(), 3, (unsigned char*)outRects, 100, 30);
|
||||
printf("FaceTrackingThread run %d\n", BaseWidget::getCurrentTime() - curTime);
|
||||
fflush(stdout);
|
||||
|
||||
std::vector<Rect> faces;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
faces.push_back(outRects[i]);
|
||||
}
|
||||
|
||||
std::vector<RectF> rectfs = EloUVCCameraConverter::openCVRect2Local(faces);
|
||||
if (rectfs.size() > 0) {
|
||||
lastValidUVCTime = curTime;
|
||||
|
||||
smartWidget->onUpdateFaceRects(rectfs);
|
||||
|
||||
if (curTime > nextRotateTime)
|
||||
{
|
||||
double sumCenterY = 0;
|
||||
for (int i = 0; i < rectfs.size(); ++i)
|
||||
{
|
||||
sumCenterY += rectfs[i].y + rectfs[i].height*.5;
|
||||
}
|
||||
double centerY = sumCenterY / rectfs.size();
|
||||
int step = (int)((centerY - 0.5) * -0.20 * EloUVCCameraConverter::IR_HEIGHT);
|
||||
|
||||
if (step != 0)
|
||||
{
|
||||
if (centerY > 0.6)
|
||||
{
|
||||
emit updateRotate(step);
|
||||
}
|
||||
else if (centerY < 0.4)
|
||||
{
|
||||
emit updateRotate(step);
|
||||
}
|
||||
nextRotateTime = curTime + std::abs(step) * 10 + 80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curTime - lastValidUVCTime >= 1000)
|
||||
{
|
||||
rectfs.clear();
|
||||
smartWidget->onUpdateFaceRects(rectfs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
{
|
||||
mutexImage.lock();
|
||||
isProcessing = false;
|
||||
mutexImage.unlock();
|
||||
}
|
||||
|
||||
msleep(300);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
void FaceTrackingThread::updateImage(QImage image) {
|
||||
if (isProcessing == false) {
|
||||
mutexImage.lock();
|
||||
_trackImage = image;
|
||||
mutexImage.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SmartWidget::SmartWidget(BaseWidget *parent) :
|
||||
BaseWidget(parent),
|
||||
ui(new Ui::SmartWidget)
|
||||
{
|
||||
lastIRTime = -1;
|
||||
lastDistance = -1;
|
||||
lastValidDistance = -1;
|
||||
lastValidDistanceTime = -1;
|
||||
|
||||
|
||||
connect(this, SIGNAL(updateImageView(ImageView*)), this,
|
||||
SLOT(onUpdateImageView(ImageView*)));
|
||||
|
||||
faceTrackingThread = NULL;
|
||||
bool isSuccess = LoadNetwork();
|
||||
if (isSuccess) {
|
||||
faceTrackingThread = new FaceTrackingThread(this);
|
||||
connect(faceTrackingThread, &FaceTrackingThread::updateRotate, this, &SmartWidget::onUpdateRotate);
|
||||
|
||||
faceTrackingThread->start(QThread::InheritPriority);
|
||||
}
|
||||
|
||||
initUI();
|
||||
|
||||
int x, y;
|
||||
bool hasPreset = HasPreset();
|
||||
if (hasPreset) {
|
||||
x = GetPresetOffsetX();
|
||||
y = GetPresetOffsetY();
|
||||
}
|
||||
else {
|
||||
x = EloUVCCameraConverter::getDefaultX();
|
||||
y = EloUVCCameraConverter::getDefaultY();
|
||||
}
|
||||
EloUVCCameraConverter::setOffset(x, y);
|
||||
}
|
||||
|
||||
SmartWidget::~SmartWidget()
|
||||
{
|
||||
delete ui;
|
||||
|
||||
if (faceTrackingThread) {
|
||||
faceTrackingThread->isActive = false;
|
||||
faceTrackingThread->wait(1000);
|
||||
delete faceTrackingThread;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SmartWidget::initUI() {
|
||||
ui->setupUi(this);
|
||||
|
||||
this->_RGBImageView = ui->rgbImage;
|
||||
this->_IRImageView = ui->irImage;
|
||||
|
||||
ui->imgNormal->setVisible(false);
|
||||
ui->imgAbnormal->setVisible(false);
|
||||
}
|
||||
void SmartWidget::onUVCFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
BaseWidget::onUVCFrame(buffer, width, height, channel);
|
||||
|
||||
if (_RGBImageView) {
|
||||
emit updateImageView(_RGBImageView);
|
||||
}
|
||||
|
||||
if (faceTrackingThread && faceTrackingThread->isActive) {
|
||||
if (faceTrackingThread->isProcessing == false) {
|
||||
QImage trackImage = EloUVCCameraConverter::UVCBitmapWithIRWidth(_qRGBImage);
|
||||
faceTrackingThread->updateImage(trackImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SmartWidget::onIRFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
int curTime = getCurrentTime();
|
||||
|
||||
//Update every 500ms
|
||||
if (curTime - lastIRTime >= 500)
|
||||
{
|
||||
std::vector<RectF> faces;
|
||||
{
|
||||
mutexFaces.lock();
|
||||
faces = lastValidFaces;
|
||||
mutexFaces.unlock();
|
||||
}
|
||||
if (faces.size() > 0)
|
||||
{
|
||||
int countAbnormal = 0;
|
||||
int countNormal = 0;
|
||||
|
||||
std::vector<TemperatureResult> results;
|
||||
for (int i = 0; i < faces.size(); ++i)
|
||||
{
|
||||
TemperatureResult result;
|
||||
RectF faceF = faces[i];
|
||||
|
||||
ReadTemperatureInRect(faceF.x*IR_WIDTH,
|
||||
faceF.y*IR_HEIGHT,
|
||||
faceF.width*IR_WIDTH,
|
||||
faceF.height*IR_HEIGHT,
|
||||
(unsigned char *)&result);
|
||||
|
||||
if (result.judgement == Thermal_Judgement_Fever)
|
||||
{
|
||||
countAbnormal++;
|
||||
}
|
||||
else if (result.judgement == Thermal_Judgement_Normal)
|
||||
{
|
||||
countNormal++;
|
||||
}
|
||||
results.push_back(result);
|
||||
}
|
||||
|
||||
_IRImageView->updateFacesAndResults(faces, results);
|
||||
_RGBImageView->updateFacesAndResults(faces, results);
|
||||
|
||||
if (countAbnormal > 0)
|
||||
{
|
||||
onAbnormal();
|
||||
}
|
||||
else if (countNormal > 0)
|
||||
{
|
||||
onNormal();
|
||||
}
|
||||
else
|
||||
{
|
||||
onNobody();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<TemperatureResult> results;
|
||||
|
||||
_IRImageView->updateFacesAndResults(faces, results);
|
||||
_RGBImageView->updateFacesAndResults(faces, results);
|
||||
|
||||
onNobody();
|
||||
}
|
||||
lastIRTime = curTime;
|
||||
}
|
||||
|
||||
BaseWidget::onIRFrame(buffer, width, height, channel);
|
||||
|
||||
if (_IRImageView) {
|
||||
emit updateImageView(_IRImageView);
|
||||
}
|
||||
if (_RGBImageView) {
|
||||
emit updateImageView(_RGBImageView);
|
||||
}
|
||||
}
|
||||
|
||||
void SmartWidget::onUpdateFaceRects(std::vector<RectF> faces) {
|
||||
mutexFaces.lock();
|
||||
lastValidFaces = faces;
|
||||
mutexFaces.unlock();
|
||||
if (faces.size() > 0) {
|
||||
printf("onUpdateFaceRects %d\n", faces.size());
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
void SmartWidget::onUpdateRotate(int unit) {
|
||||
rotate(unit);
|
||||
}
|
||||
void SmartWidget::onDistance(float distance) {
|
||||
if (distance > 0)
|
||||
{
|
||||
lastValidDistanceTime = getCurrentTime();
|
||||
lastValidDistance = distance;
|
||||
}
|
||||
lastDistance = distance;
|
||||
}
|
||||
void SmartWidget::onNormal() {
|
||||
ui->imgNormal->setVisible(true);
|
||||
ui->imgAbnormal->setVisible(false);
|
||||
}
|
||||
void SmartWidget::onAbnormal() {
|
||||
ui->imgNormal->setVisible(false);
|
||||
ui->imgAbnormal->setVisible(true);
|
||||
}
|
||||
void SmartWidget::onNobody() {
|
||||
ui->imgNormal->setVisible(false);
|
||||
ui->imgAbnormal->setVisible(false);
|
||||
}
|
||||
|
||||
void SmartWidget::on_btnRGBDefault_clicked() {
|
||||
SetCameraLightParameter(0,1,100);
|
||||
}
|
||||
|
||||
void SmartWidget::on_btnRGBLighter_clicked() {
|
||||
SetCameraLightParameter(64,3,300);
|
||||
|
||||
}
|
||||
|
||||
void SmartWidget::on_btnTrackDefault_clicked() {
|
||||
SetThreshold(0.8f,0.8f,0.6f);
|
||||
}
|
||||
|
||||
void SmartWidget::on_btnTrackMore_clicked() {
|
||||
SetThreshold(0.5f,0.5f,0.5f);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#ifndef SmartWidget_H
|
||||
#define SmartWidget_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "basewidget.h"
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
|
||||
namespace Ui {
|
||||
class SmartWidget;
|
||||
}
|
||||
|
||||
|
||||
class FaceTrackingThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FaceTrackingThread(QObject *parent = 0);
|
||||
volatile bool isActive;
|
||||
volatile bool isProcessing;
|
||||
|
||||
void updateImage(QImage);
|
||||
signals:
|
||||
void updateRotate(int);
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
public slots:
|
||||
private:
|
||||
QImage _trackImage;
|
||||
volatile int lastValidUVCTime;
|
||||
volatile int nextRotateTime;
|
||||
|
||||
QMutex mutexImage;
|
||||
};
|
||||
|
||||
class SmartWidget : public BaseWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SmartWidget(BaseWidget *parent = nullptr);
|
||||
~SmartWidget();
|
||||
|
||||
void onUpdateFaceRects(std::vector<RectF>);
|
||||
|
||||
protected:
|
||||
void initUI();
|
||||
|
||||
virtual void onUVCFrame(const unsigned char* buffer, int width, int height, int channel) override;
|
||||
virtual void onIRFrame(const unsigned char* buffer, int width, int height, int channel) override;
|
||||
virtual void onDistance(float distance) override;
|
||||
|
||||
virtual void onNormal() override;
|
||||
virtual void onAbnormal() override;
|
||||
virtual void onNobody() override;
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void onUpdateRotate(int);
|
||||
|
||||
void on_btnRGBDefault_clicked();
|
||||
|
||||
void on_btnRGBLighter_clicked();
|
||||
|
||||
void on_btnTrackDefault_clicked();
|
||||
|
||||
void on_btnTrackMore_clicked();
|
||||
|
||||
private:
|
||||
|
||||
Ui::SmartWidget *ui;
|
||||
|
||||
volatile int lastIRTime;
|
||||
volatile float lastDistance;
|
||||
volatile float lastValidDistance;
|
||||
volatile int lastValidDistanceTime;
|
||||
|
||||
QMutex mutexFaces;
|
||||
std::vector<RectF> lastValidFaces;
|
||||
|
||||
FaceTrackingThread *faceTrackingThread;
|
||||
};
|
||||
|
||||
#endif // SmartWidget_H
|
||||
@@ -0,0 +1,147 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SmartWidget</class>
|
||||
<widget class="QWidget" name="SmartWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>930</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Smart</string>
|
||||
</property>
|
||||
<widget class="ImageView" name="rgbImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="ImageView" name="irImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>360</y>
|
||||
<width>480</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="imgNormal">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>165</x>
|
||||
<y>720</y>
|
||||
<width>270</width>
|
||||
<height>240</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="image.qrc">:/new/prefix1/image/normal.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="imgAbnormal">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>165</x>
|
||||
<y>720</y>
|
||||
<width>270</width>
|
||||
<height>240</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="image.qrc">:/new/prefix1/image/abnormal.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnRGBLighter">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>760</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>RGB Lighter</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnTrackDefault">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>790</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Track Def</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnTrackMore">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>820</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Track More</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnRGBDefault">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>730</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>RGB Def</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ImageView</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>imageview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="image.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,260 @@
|
||||
#include "testwidget.h"
|
||||
#include "ui_testwidget.h"
|
||||
#include "ThermalSDK.h"
|
||||
#include <stdlib.h>
|
||||
#include "elouvccameraconverter.h"
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
TestWidget::TestWidget(BaseWidget *parent) :
|
||||
BaseWidget(parent),
|
||||
ui(new Ui::TestWidget)
|
||||
, _txOffset(nullptr)
|
||||
, _txDistance(nullptr)
|
||||
, _txTemp(nullptr)
|
||||
, _txTCMVersion(nullptr)
|
||||
, _txSDKVersion(nullptr)
|
||||
, _txSerial(nullptr)
|
||||
{
|
||||
initUI();
|
||||
|
||||
connect(this, SIGNAL(updateLabel(QLabel*, QString)), this,
|
||||
SLOT(onUpdateLabel(QLabel*, QString)));
|
||||
connect(this, SIGNAL(updateEdit(QLineEdit*, QString)), this,
|
||||
SLOT(onUpdateEdit(QLineEdit*, QString)));
|
||||
connect(this, SIGNAL(updateImageView(ImageView*)), this,
|
||||
SLOT(onUpdateImageView(ImageView*)));
|
||||
|
||||
int sdk = GetSDKVersion();
|
||||
|
||||
char buff[50] = {0};
|
||||
GetTCMVersion(buff);
|
||||
|
||||
emit updateLabel(_txSDKVersion, QString::asprintf("SDK:%d", sdk));
|
||||
emit updateLabel(_txTCMVersion, QString::asprintf("TCM:%s", buff));
|
||||
|
||||
int x, y;
|
||||
bool hasPreset = HasPreset();
|
||||
if (hasPreset) {
|
||||
x = GetPresetOffsetX();
|
||||
y = GetPresetOffsetY();
|
||||
char serial[50] = {0};
|
||||
GetPresetSerial(serial);
|
||||
emit updateEdit(_txSerial, QString::asprintf("%s", serial));
|
||||
|
||||
}
|
||||
else {
|
||||
x = EloUVCCameraConverter::getOffsetX();
|
||||
y = EloUVCCameraConverter::getOffsetY();
|
||||
}
|
||||
EloUVCCameraConverter::setOffset(x, y);
|
||||
updateOffset();
|
||||
}
|
||||
|
||||
TestWidget::~TestWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void TestWidget::initUI() {
|
||||
ui->setupUi(this);
|
||||
|
||||
this->_RGBImageView = ui->rgbImage;
|
||||
this->_IRImageView = ui->irImage;
|
||||
|
||||
this->_txOffset = ui->txOffset;
|
||||
this->_txDistance = ui->txDistance;
|
||||
this->_txTemp = ui->txTemp;
|
||||
this->_txTCMVersion = ui->txTCMVersion;
|
||||
this->_txSDKVersion = ui->txSDKVersion;
|
||||
this->_txSerial = ui->txSerial;
|
||||
|
||||
}
|
||||
void TestWidget::onUVCFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
BaseWidget::onUVCFrame(buffer, width, height, channel);
|
||||
|
||||
if (_RGBImageView) {
|
||||
emit updateImageView(_RGBImageView);
|
||||
}
|
||||
}
|
||||
|
||||
void TestWidget::onIRFrame(const unsigned char* buffer, int width, int height, int channel)
|
||||
{
|
||||
double inner = GetInnerIRCameraTemp();
|
||||
emit updateLabel(_txTemp, QString::asprintf("IR:inner %.1f", inner));
|
||||
|
||||
if (true) {
|
||||
TemperatureResult result;
|
||||
ReadTemperatureAtPoint(80,40, (unsigned char *)&result);
|
||||
|
||||
_IRImageView->updateSingleResult(&result);
|
||||
}
|
||||
else {
|
||||
TemperatureResult result;
|
||||
RectF rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = 0.25;
|
||||
rect.height = 0.25;
|
||||
|
||||
ReadTemperatureInRect(rect.x*IR_WIDTH, rect.y*IR_HEIGHT,
|
||||
rect.width*IR_WIDTH, rect.height*IR_HEIGHT,
|
||||
(unsigned char *)&result);
|
||||
|
||||
emit updateLabel(_txDistance, QString::asprintf("%.1f", result.tempArm));
|
||||
|
||||
std::vector<RectF> rects = {rect};
|
||||
std::vector<TemperatureResult> results = {result};
|
||||
_IRImageView->updateFacesAndResults(rects, results);
|
||||
}
|
||||
|
||||
|
||||
BaseWidget::onIRFrame(buffer, width, height, channel);
|
||||
|
||||
if (_IRImageView) {
|
||||
emit updateImageView(_IRImageView);
|
||||
}
|
||||
}
|
||||
void TestWidget::onDistance(float distance) {
|
||||
if (_isUnitUS) {
|
||||
emit updateLabel(_txDistance, QString::asprintf("%.0f inch", distance));
|
||||
}
|
||||
else {
|
||||
emit updateLabel(_txDistance, QString::asprintf("%.0f mm", distance));
|
||||
}
|
||||
}
|
||||
void TestWidget::onDistanceError() {
|
||||
emit updateLabel(_txDistance, QString::asprintf("onDistanceError"));
|
||||
}
|
||||
void TestWidget::onLimitEvent(bool inplace) {
|
||||
if (inplace) {
|
||||
emit updateLabel(_txSDKVersion, QString::asprintf("Limit:true"));
|
||||
}
|
||||
else {
|
||||
emit updateLabel(_txSDKVersion, QString::asprintf("Limit:false"));
|
||||
}
|
||||
}
|
||||
void TestWidget::onUpdateCallback(bool isSuc, int prog) {
|
||||
if (isSuc) {
|
||||
emit updateLabel(_txTCMVersion, QString::asprintf("Update:%d Suc", prog));
|
||||
}
|
||||
else {
|
||||
emit updateLabel(_txTCMVersion, QString::asprintf("Update:%d Fail", prog));
|
||||
}
|
||||
|
||||
}
|
||||
void TestWidget::onUpdateLabel(QLabel* label, QString str) {
|
||||
label->setText(str);
|
||||
}
|
||||
void TestWidget::onUpdateEdit(QLineEdit* label, QString str) {
|
||||
label->setText(str);
|
||||
}
|
||||
void TestWidget::on_btnUp_clicked()
|
||||
{
|
||||
rotate(10);
|
||||
}
|
||||
|
||||
void TestWidget::on_btnDown_clicked()
|
||||
{
|
||||
rotate(-10);
|
||||
}
|
||||
|
||||
void TestWidget::on_btnTrigger_clicked()
|
||||
{
|
||||
trigger();
|
||||
}
|
||||
void TestWidget::on_btnLimit_clicked()
|
||||
{
|
||||
LimitReset();
|
||||
}
|
||||
|
||||
void TestWidget::on_btnFirmUpdate_clicked() {
|
||||
QFileDialog *fileDialog = new QFileDialog(this);
|
||||
fileDialog->setWindowTitle(tr("Open File"));
|
||||
fileDialog->setDirectory(".");
|
||||
fileDialog->setNameFilter(tr("Firmware Files(*.bin)"));
|
||||
if(fileDialog->exec() == QDialog::Accepted) {
|
||||
QString path = fileDialog->selectedFiles()[0];
|
||||
if (path.isEmpty() == false) {
|
||||
QFile file (path);
|
||||
bool isOk = file.open(QIODevice::ReadOnly);
|
||||
if (isOk)
|
||||
{
|
||||
QByteArray array = file.readAll();
|
||||
int length = array.size();
|
||||
char* firm = array.data();
|
||||
SetFirmwareData((const unsigned char*)firm, length);
|
||||
file.close();
|
||||
|
||||
StartUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestWidget::on_btnSavePreset_clicked()
|
||||
{
|
||||
QString serial = _txSerial->text();
|
||||
if (serial.length() == 0) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Serial empty!"));
|
||||
return;
|
||||
}
|
||||
else if (serial.length() > 12) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Serial too long!"));
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray arr;
|
||||
arr.append(serial);
|
||||
const char *str = arr.data();
|
||||
bool isOK = UpdatePreset(EloUVCCameraConverter::getOffsetX(),
|
||||
EloUVCCameraConverter::getOffsetY(),
|
||||
str);
|
||||
|
||||
if (isOK) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Save success!"));
|
||||
}
|
||||
else {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Save failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
void TestWidget::on_btnTCMReset_clicked() {
|
||||
SoftResetTCM();
|
||||
}
|
||||
void TestWidget::on_btnXPlus_clicked()
|
||||
{
|
||||
EloUVCCameraConverter::adjustX(1);
|
||||
updateOffset();
|
||||
}
|
||||
|
||||
void TestWidget::on_btnXMinus_clicked()
|
||||
{
|
||||
EloUVCCameraConverter::adjustX(-1);
|
||||
updateOffset();
|
||||
}
|
||||
|
||||
void TestWidget::on_btnYPlus_clicked()
|
||||
{
|
||||
EloUVCCameraConverter::adjustY(1);
|
||||
updateOffset();
|
||||
}
|
||||
|
||||
void TestWidget::on_btnYMinus_clicked()
|
||||
{
|
||||
EloUVCCameraConverter::adjustY(-1);
|
||||
updateOffset();
|
||||
}
|
||||
void TestWidget::updateOffset() {
|
||||
int x = EloUVCCameraConverter::getOffsetX();
|
||||
int y = EloUVCCameraConverter::getOffsetY();
|
||||
|
||||
EloUVCCameraConverter::setDefaultX(x);
|
||||
EloUVCCameraConverter::setDefaultY(y);
|
||||
|
||||
emit updateLabel(_txOffset, QString::asprintf("%d-%d", x, y));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef TESTWIDGET_H
|
||||
#define TESTWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "basewidget.h"
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace Ui {
|
||||
class TestWidget;
|
||||
}
|
||||
|
||||
class TestWidget : public BaseWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TestWidget(BaseWidget *parent = nullptr);
|
||||
~TestWidget();
|
||||
|
||||
protected:
|
||||
void initUI();
|
||||
|
||||
virtual void onUVCFrame(const unsigned char* buffer, int width, int height, int channel) override;
|
||||
virtual void onIRFrame(const unsigned char* buffer, int width, int height, int channel) override;
|
||||
virtual void onDistance(float distance) override;
|
||||
virtual void onDistanceError() override;
|
||||
virtual void onLimitEvent(bool inplace) override;
|
||||
virtual void onUpdateCallback(bool isSuc, int prog) override;
|
||||
|
||||
signals:
|
||||
void updateLabel(QLabel* label, QString str);
|
||||
void updateEdit(QLineEdit* label, QString str);
|
||||
|
||||
|
||||
private slots:
|
||||
void on_btnUp_clicked();
|
||||
|
||||
void on_btnDown_clicked();
|
||||
|
||||
void on_btnTrigger_clicked();
|
||||
|
||||
void on_btnLimit_clicked();
|
||||
|
||||
void on_btnFirmUpdate_clicked();
|
||||
|
||||
void on_btnXPlus_clicked();
|
||||
|
||||
void on_btnXMinus_clicked();
|
||||
|
||||
void on_btnYPlus_clicked();
|
||||
|
||||
void on_btnYMinus_clicked();
|
||||
|
||||
void on_btnSavePreset_clicked();
|
||||
|
||||
void on_btnTCMReset_clicked();
|
||||
|
||||
void onUpdateLabel(QLabel* label, QString str);
|
||||
void onUpdateEdit(QLineEdit* label, QString str);
|
||||
|
||||
private:
|
||||
virtual void updateOffset();
|
||||
|
||||
Ui::TestWidget *ui;
|
||||
|
||||
QLabel* _txOffset;
|
||||
QLabel* _txDistance;
|
||||
QLabel* _txTemp;
|
||||
QLabel* _txTCMVersion;
|
||||
QLabel* _txSDKVersion;
|
||||
QLineEdit* _txSerial;
|
||||
|
||||
};
|
||||
|
||||
#endif // TESTWIDGET_H
|
||||
@@ -0,0 +1,285 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TestWidget</class>
|
||||
<widget class="QWidget" name="TestWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>930</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
<widget class="ImageView" name="rgbImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="ImageView" name="irImage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>360</y>
|
||||
<width>480</width>
|
||||
<height>360</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnUp">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>730</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnDown">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>760</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnTrigger">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>790</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trigger</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnFirmUpdate">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>850</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnXPlus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>730</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X+</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnXMinus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>760</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X-</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnYPlus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>790</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Y+</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnYMinus">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>820</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Y-</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="txOffset">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>860</y>
|
||||
<width>90</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="txDistance">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>730</y>
|
||||
<width>200</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="txTemp">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>770</y>
|
||||
<width>200</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="txTCMVersion">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>810</y>
|
||||
<width>200</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="txSDKVersion">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>850</y>
|
||||
<width>200</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnLimit">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>820</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnTCMReset">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>880</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset TCM</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="btnSavePreset">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<y>890</y>
|
||||
<width>84</width>
|
||||
<height>28</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="txSerial">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>200</x>
|
||||
<y>880</y>
|
||||
<width>200</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ImageView</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>imageview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,3 @@
|
||||
[UVC]
|
||||
DefaultX=110
|
||||
DefaultY=110
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_core.so.4.4.0
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_imgcodecs.so.4.4.0
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_imgproc.so.4.4.0
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
libopencv_videoio.so.4.4.0
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
V1.2.2
|
||||
1. Add feature: GetDefaultCalibration(), wrapper for simply using.
|
||||
2. Add feature: SetThreshold(), opening interface for threshold adjustment.
|
||||
3. Add feature: SetCameraLightParameter(), using for low-lux environment.
|
||||
|
||||
V1.2.1
|
||||
1. Add feature: notify sensor failure: onFail() in INewDistance (available on TCM version:V1.21 210120 or above)
|
||||
2. Add feature: soft reset TCM SoftResetTCM(), which can be used if sensor is malfunctional. (available on TCM version:V1.21 210120 or above)
|
||||
|
||||
V1.1.0
|
||||
1. Add feature: store/load calibration data on hardware (available on TCM version:V1.1 201117 or above)
|
||||
2. Add notification: limit switch on/off
|
||||
3. Fix some bugs.
|
||||
|
||||
|
||||
V1.0.1
|
||||
1. Add smart mode
|
||||
|
||||
V1.0.0
|
||||
1. First release.
|
||||
@@ -0,0 +1,167 @@
|
||||
Coding Tips V1.2.2:
|
||||
1. We add GetDefaultCalibration() method, which used for get default calibration X,Y.
|
||||
Code logic:
|
||||
a) Getting from hardware. Return if yes, otherwise,
|
||||
b) Getting from pre-calibration data. Return if yes, otherwise,
|
||||
c) Return default X,Y
|
||||
|
||||
Sample codes:
|
||||
int defaults[2] = {0,0};
|
||||
GetDefaultCalibration(defaults);
|
||||
EloUVCCameraConverter::setOffset(defaults[0], defaults[1]);
|
||||
|
||||
For early version of IRKit, we strongly recommand ISV do manual calibration rather than using default X,Y
|
||||
|
||||
|
||||
2. We add SetThreshold(), interface for threshold adjustment.
|
||||
* Default thershold is 0.8f, 0.8f, 0.6f (values are different from Android Version!!!)
|
||||
You can set threshold of face tracking algorithm now. Decrease threshold can increase possibility of finding facing. But it will increase false negative (FN) as well.
|
||||
Sample codes in SmartWidget:
|
||||
SetThreshold(0.5f,0.5f,0.5f);
|
||||
|
||||
|
||||
|
||||
|
||||
3. We add SetCameraLightParameter(), using for low-lux environment. (values are different from Android Version!!!)
|
||||
The higher value leads to the brighter(more white) image.
|
||||
|
||||
For example:
|
||||
|
||||
SetCameraLightParameter(0, 1, 100); //Reset to default in normal environment
|
||||
|
||||
Or,
|
||||
|
||||
SetCameraLightParameter(64, 3, 300); //setting brightness, backlightComp and gamma, in dark environment.
|
||||
|
||||
|
||||
Coding Tips V1.2.1:
|
||||
1. In order to use new feature, firmware update in required.
|
||||
The path of TCM's firmware is under firmware/IR V1.21 210120.bin.
|
||||
|
||||
2. SoftResetTCM() can be used if sensor is malfunctional.
|
||||
|
||||
3. A whole machine power off/on is required after firmware update, please do not use SoftResetTCM() instead.
|
||||
|
||||
|
||||
Coding Tips V1.1.0:
|
||||
1. What's new in firmware of TCM V1.1? Do I need to update firmware?
|
||||
|
||||
The firmware of TCM V1.1 includes calibartion data saving (offsetX and offsetY).
|
||||
|
||||
If you are working well and do the calibration by your own, you don't have to update the firmware.
|
||||
If you want to save/load the calibration data between AIOs, you can consider upgrading the firmware.
|
||||
|
||||
* Please notice: In SDK 1.0.1 and before, the cabibration data is saved on values of application.
|
||||
Therefore, if you re-install application or move IR Kit to another AIO will lead to an extra calibration.
|
||||
|
||||
|
||||
2. How to update firmware if I have an older Kit?
|
||||
The IR Kit in DVT stage or later supports firmware upgrade.
|
||||
The path of TCM's firmware is under firmware/IR V1.1b.bin.
|
||||
|
||||
Reference code (see in testwidget.cpp):
|
||||
|
||||
QFileDialog *fileDialog = new QFileDialog(this);
|
||||
fileDialog->setWindowTitle(tr("Open File"));
|
||||
fileDialog->setDirectory(".");
|
||||
fileDialog->setNameFilter(tr("Firmware Files(*.bin)"));
|
||||
if(fileDialog->exec() == QDialog::Accepted) {
|
||||
QString path = fileDialog->selectedFiles()[0];
|
||||
if (path.isEmpty() == false) {
|
||||
QFile file (path);
|
||||
bool isOk = file.open(QIODevice::ReadOnly);
|
||||
if (isOk)
|
||||
{
|
||||
QByteArray array = file.readAll();
|
||||
int length = array.size();
|
||||
char* firm = array.data();
|
||||
SetFirmwareData((const unsigned char*)firm, length);
|
||||
file.close();
|
||||
|
||||
StartUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Callback:
|
||||
SetUpdateCallback(onUpdate);
|
||||
|
||||
void TestWidget::onUpdateCallback(bool isSuc, int prog) {
|
||||
if (isSuc) {
|
||||
emit updateLabel(_txTCMVersion, QString::asprintf("Update:%d Suc", prog));
|
||||
}
|
||||
else {
|
||||
emit updateLabel(_txTCMVersion, QString::asprintf("Update:%d Fail", prog));
|
||||
}
|
||||
}
|
||||
|
||||
* "isSuc == true and prog == 100" means update successfully.
|
||||
|
||||
Important!!
|
||||
a) Please DO NOT disconnect or power off IR Kit when you are updating firmware (prog != 100).
|
||||
b) No matter the update is successful or not, you are required to switch off/on the whole machine to make changes valid. (Power off entire AIO and IR Kit, then power on).
|
||||
|
||||
|
||||
3. How to use feature: store/load calibration data on hardware (available on TCM version:V1.1 201117 or above)
|
||||
If IR kit on your side is V1.1 already, you can use this feature already. The calibration data is preseted. (640*480 resolution).
|
||||
If you are updating to V1.1, you are required to save data at the first time,
|
||||
|
||||
|
||||
void TestWidget::on_btnSavePreset_clicked()
|
||||
{
|
||||
QString serial = _txSerial->text();
|
||||
if (serial.length() == 0) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Serial empty!"));
|
||||
return;
|
||||
}
|
||||
else if (serial.length() > 12) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Serial too long!"));
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray arr;
|
||||
arr.append(serial);
|
||||
const char *str = arr.data();
|
||||
bool isOK = UpdatePreset(EloUVCCameraConverter::getOffsetX(),
|
||||
EloUVCCameraConverter::getOffsetY(),
|
||||
str);
|
||||
|
||||
if (isOK) {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Save success!"));
|
||||
}
|
||||
else {
|
||||
QMessageBox::information(NULL, tr("Warn"), tr("Save failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Then, you can get data via method
|
||||
|
||||
int x, y;
|
||||
bool hasPreset = HasPreset();
|
||||
if (hasPreset) {
|
||||
x = GetPresetOffsetX();
|
||||
y = GetPresetOffsetY();
|
||||
char serial[50] = {0};
|
||||
GetPresetSerial(serial);
|
||||
emit updateEdit(_txSerial, QString::asprintf("%s", serial));
|
||||
|
||||
}
|
||||
else {
|
||||
x = EloUVCCameraConverter::getOffsetX();
|
||||
y = EloUVCCameraConverter::getOffsetY();
|
||||
}
|
||||
EloUVCCameraConverter::setOffset(x, y);
|
||||
updateOffset();
|
||||
|
||||
|
||||
4. What's limit notification?
|
||||
Limit notification is a notification which indicate the motor is reached to the bottom of the IR Kit, or gives a zero-point of the angle of rotation.
|
||||
|
||||
You can add code like this:
|
||||
|
||||
SetLimitEventListener(onLimit);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user