| 287 |
Kevin |
1 |
#include "OpenNI.h"
|
|
|
2 |
|
|
|
3 |
#define CHECK_RC(rc, what) \
|
|
|
4 |
if (rc != XN_STATUS_OK) { \
|
|
|
5 |
QString error = QString(QString(what) + "failed: "); \
|
|
|
6 |
error += QString(xnGetStatusString(rc)); \
|
|
|
7 |
emit setStatusString(error); \
|
|
|
8 |
exit(rc); \
|
|
|
9 |
return; \
|
|
|
10 |
}
|
|
|
11 |
|
|
|
12 |
using namespace xn;
|
|
|
13 |
|
|
|
14 |
extern QSemaphore processorBuffer;
|
|
|
15 |
|
|
|
16 |
XnBool OpenNI::fileExists(const char *fn) {
|
|
|
17 |
XnBool exists;
|
|
|
18 |
xnOSDoesFileExist(fn, &exists);
|
|
|
19 |
return exists;
|
|
|
20 |
}
|
|
|
21 |
|
|
|
22 |
OpenNI::OpenNI(QObject *parent)
|
|
|
23 |
: QThread(parent) {
|
|
|
24 |
|
|
|
25 |
moveToThread(this);
|
|
|
26 |
}
|
|
|
27 |
|
|
|
28 |
OpenNI::~OpenNI() {
|
|
|
29 |
|
|
|
30 |
}
|
|
|
31 |
|
|
|
32 |
void OpenNI::run() {
|
|
|
33 |
|
|
|
34 |
XnStatus nRetVal = XN_STATUS_OK;
|
|
|
35 |
Context context;
|
|
|
36 |
ScriptNode scriptNode;
|
|
|
37 |
EnumerationErrors errors;
|
|
|
38 |
|
|
|
39 |
// Check if the config file exists
|
|
|
40 |
const char *fn = NULL;
|
| 289 |
Kevin |
41 |
if (fileExists(CONFIG_XML_PATH)) fn = CONFIG_XML_PATH;
|
|
|
42 |
else if (fileExists(CONFIG_XML_PATH_LOCAL)) fn = CONFIG_XML_PATH_LOCAL;
|
| 287 |
Kevin |
43 |
else {
|
| 289 |
Kevin |
44 |
QString error = QString("Could not find " + QString(CONFIG_XML_PATH) + " nor " + QString(CONFIG_XML_PATH_LOCAL));
|
| 287 |
Kevin |
45 |
emit setStatusString(error);
|
|
|
46 |
exit(XN_STATUS_ERROR);
|
|
|
47 |
return;
|
|
|
48 |
}
|
|
|
49 |
// Load the config file
|
|
|
50 |
nRetVal = context.InitFromXmlFile(fn, scriptNode, &errors);
|
|
|
51 |
|
|
|
52 |
// Check to see if a sensor is connected
|
|
|
53 |
if (nRetVal == XN_STATUS_NO_NODE_PRESENT) {
|
|
|
54 |
XnChar strError[1024];
|
|
|
55 |
errors.ToString(strError, 1024);
|
|
|
56 |
emit setStatusString(QString(strError));
|
|
|
57 |
exit(nRetVal);
|
|
|
58 |
return;
|
|
|
59 |
} else if (nRetVal != XN_STATUS_OK) {
|
|
|
60 |
QString error = QString("Open failed: " + QString(xnGetStatusString(nRetVal)));
|
|
|
61 |
emit setStatusString(error);
|
|
|
62 |
exit(nRetVal);
|
|
|
63 |
return;
|
|
|
64 |
}
|
|
|
65 |
|
|
|
66 |
// Connect to the attached sensor
|
|
|
67 |
DepthGenerator depth;
|
|
|
68 |
nRetVal = context.FindExistingNode(XN_NODE_TYPE_DEPTH, depth);
|
|
|
69 |
CHECK_RC(nRetVal, "Find depth generator");
|
|
|
70 |
|
|
|
71 |
// Pull FPS and depth data
|
|
|
72 |
XnFPSData xnFPS;
|
|
|
73 |
nRetVal = xnFPSInit(&xnFPS, 180);
|
|
|
74 |
CHECK_RC(nRetVal, "FPS Init");
|
|
|
75 |
|
|
|
76 |
DepthMetaData depthMD;
|
|
|
77 |
|
|
|
78 |
short min = 9999, max = 0;
|
|
|
79 |
|
|
|
80 |
// If this point is reached, notify that the sensor is ready
|
|
|
81 |
emit sensorConnected();
|
|
|
82 |
|
|
|
83 |
while (1) {
|
|
|
84 |
// Ensure that the processing queue isnt too long
|
|
|
85 |
processorBuffer.acquire(1);
|
|
|
86 |
|
|
|
87 |
// Wait for an updated frame from the sensor
|
|
|
88 |
nRetVal = context.WaitOneUpdateAll(depth);
|
|
|
89 |
if (nRetVal != XN_STATUS_OK) {
|
|
|
90 |
QString error = QString("UpdateData failed: " + QString(xnGetStatusString(nRetVal)));
|
|
|
91 |
emit setStatusString(error);
|
|
|
92 |
break;
|
|
|
93 |
}
|
|
|
94 |
|
|
|
95 |
// Mark the frame (for determining FPS)
|
|
|
96 |
xnFPSMarkFrame(&xnFPS);
|
|
|
97 |
|
|
|
98 |
// Grab the depth data
|
|
|
99 |
depth.GetMetaData(depthMD);
|
|
|
100 |
|
|
|
101 |
// Grab the size and FOV of the sensor
|
|
|
102 |
int X = depthMD.XRes();
|
|
|
103 |
int Y = depthMD.YRes();
|
|
|
104 |
|
|
|
105 |
XnFieldOfView fov;
|
|
|
106 |
depth.GetFieldOfView(fov);
|
|
|
107 |
|
|
|
108 |
emit setFOV(fov.fHFOV, fov.fVFOV);
|
|
|
109 |
|
|
|
110 |
// Show the size/FOV/FPS/frame
|
|
|
111 |
QString status = "Res: " + QString::number(X) + " x " + QString::number(Y);
|
|
|
112 |
//status += " / FoV (rad): " + QString::number(fov.fHFOV) + " (H) " + QString::number(fov.fVFOV) + " (V)";
|
|
|
113 |
min = qMin(min, (short)depthMD(depthMD.XRes() / 2, depthMD.YRes() / 2));
|
|
|
114 |
max = qMax(max, (short)depthMD(depthMD.XRes() / 2, depthMD.YRes() / 2));
|
|
|
115 |
|
|
|
116 |
status += " / Center: " + QString::number(depthMD(depthMD.XRes() / 2, depthMD.YRes() / 2));
|
|
|
117 |
status += " / Min: " + QString::number(min) + " / Max: " + QString::number(max);
|
|
|
118 |
emit setStatusString(status);
|
|
|
119 |
emit setFPSString(QString::number(xnFPSCalc(&xnFPS)));
|
|
|
120 |
emit setFrameString(QString::number(depthMD.FrameID()));
|
|
|
121 |
|
|
|
122 |
// Allocate a new cv::Mat
|
| 289 |
Kevin |
123 |
cv::Mat depthData = cv::Mat(Y_RES, X_RES, CV_16UC1);
|
| 287 |
Kevin |
124 |
|
|
|
125 |
// Save the depth data (mirrored horizontally)
|
|
|
126 |
ushort *p;
|
|
|
127 |
for (int y = 0; y < Y; ++y) {
|
|
|
128 |
p = depthData.ptr<ushort>(y);
|
|
|
129 |
for (int x = 0; x < X; ++x) {
|
|
|
130 |
short pixel = depthMD.Data()[(y * X) + (X - x - 1)];
|
|
|
131 |
p[x] = pixel;
|
|
|
132 |
}
|
|
|
133 |
}
|
|
|
134 |
|
|
|
135 |
// Send the depth data for processing
|
|
|
136 |
emit processDepthData(depthData);
|
|
|
137 |
}
|
|
|
138 |
|
|
|
139 |
depth.Release();
|
|
|
140 |
scriptNode.Release();
|
|
|
141 |
context.Release();
|
|
|
142 |
}
|