Initial commit

This commit is contained in:
marek
2015-10-15 17:07:34 +02:00
parent da44352544
commit 9ebff446fa
239 changed files with 375645 additions and 0 deletions
+177
View File
@@ -0,0 +1,177 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "icp.h"
#include "opencv\cv.h"
void FindClosestPointForEach(PointCloud &sourceCloud, cv::Mat &destPoints, vector<float> &distances, vector<size_t> &indices)
{
int nVerts2 = destPoints.rows;
typedef nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<float, PointCloud>, PointCloud, 3> kdTree;
kdTree tree(3, sourceCloud);
tree.buildIndex();
#pragma omp parallel for
for (int i = 0; i < nVerts2; i++)
{
nanoflann::KNNResultSet<float> resultSet(1);
resultSet.init(&indices[i], &distances[i]);
tree.findNeighbors(resultSet, (float*)destPoints.row(i).data, nanoflann::SearchParams());
}
}
float GetStandardDeviation(vector<float> &data)
{
float mean = 0;
for (size_t i = 0; i < data.size(); i++)
{
mean += data[i];
}
mean /= data.size();
float std = 0;
for (size_t i = 0; i < data.size(); i++)
{
std += pow(data[i] - mean, 2);
}
std /= data.size();
std = sqrt(std);
return std;
}
void RejectOutlierMatches(vector<Point3f> &matches1, vector<Point3f> &matches2, vector<float> &matchDistances, float maxStdDev)
{
float distanceStandardDev = GetStandardDeviation(matchDistances);
vector<Point3f> filteredMatches1;
vector<Point3f> filteredMatches2;
for (size_t i = 0; i < matches1.size(); i++)
{
if (matchDistances[i] > maxStdDev * distanceStandardDev)
continue;
filteredMatches1.push_back(matches1[i]);
filteredMatches2.push_back(matches2[i]);
}
matches1 = filteredMatches1;
matches2 = filteredMatches2;
}
ICP_API float __stdcall ICP(Point3f *verts1, Point3f *verts2, int nVerts1, int nVerts2, float *R, float *t, int maxIter)
{
PointCloud cloud1;
cloud1.pts = vector<Point3f>(verts1, verts1 + nVerts1);
cv::Mat matR(3, 3, CV_32F, R);
cv::Mat matT(1, 3, CV_32F, t);
cv::Mat verts2Mat(nVerts2, 3, CV_32F, (float*)verts2);
float error = 1;
for (int iter = 0; iter < maxIter; iter++)
{
vector<Point3f> matched1, matched2;
vector<float> distances(nVerts2);
vector<size_t> indices(nVerts2);
FindClosestPointForEach(cloud1, verts2Mat, distances, indices);
vector<float> matchDistances;
vector<int> matchIdxs(nVerts1, -1);
for (int i = 0; i < nVerts2; i++)
{
int pos = matchIdxs[indices[i]];
if (pos != -1)
{
if (matchDistances[pos] < distances[i])
continue;
}
Point3f temp;
temp.X = verts2Mat.at<float>(i, 0);
temp.Y = verts2Mat.at<float>(i, 1);
temp.Z = verts2Mat.at<float>(i, 2);
if (pos == -1)
{
matched1.push_back(verts1[indices[i]]);
matched2.push_back(temp);
matchDistances.push_back(distances[i]);
matchIdxs[indices[i]] = matched1.size() - 1;
}
else
{
matched2[pos] = temp;
matchDistances[pos] = distances[i];
}
}
RejectOutlierMatches(matched1, matched2, matchDistances, 2.5);
//error = 0;
//for (int i = 0; i < matchDistances.size(); i++)
//{
// error += sqrt(matchDistances[i]);
//}
//error /= matchDistances.size();
//cout << error << endl;
cv::Mat matched1MatCv(matched1.size(), 3, CV_32F, matched1.data());
cv::Mat matched2MatCv(matched2.size(), 3, CV_32F, matched2.data());
cv::Mat tempT;
cv::reduce(matched1MatCv - matched2MatCv, tempT, 0, CV_REDUCE_AVG);
for (int i = 0; i < verts2Mat.rows; i++)
{
verts2Mat.row(i) += tempT;
}
for (int i = 0; i < matched2MatCv.rows; i++)
{
matched2MatCv.row(i) += tempT;
}
cv::Mat M = matched2MatCv.t() * matched1MatCv;
cv::SVD svd;
svd(M);
cv::Mat tempR = svd.u * svd.vt;
double det = cv::determinant(tempR);
if (det < 0)
{
cv::Mat temp = cv::Mat::eye(3, 3, CV_32F);
temp.at<float>(2, 2) = -1;
tempR = svd.u * temp * svd.vt;
}
verts2Mat = verts2Mat * tempR;
matT += tempT * matR.t();
matR = matR * tempR;
}
memcpy(verts2, verts2Mat.data, verts2Mat.rows * sizeof(float) * 3);
memcpy(R, matR.data, 9 * sizeof(float));
memcpy(t, matT.data, 3 * sizeof(float));
return error;
}
+128
View File
@@ -0,0 +1,128 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include <stdio.h>
#include <vector>
#include "icp.h"
#include "opencv\cv.h"
using namespace std;
struct RGB
{
unsigned char R, G, B;
};
void savePLY(std::string filename, std::vector<Point3f> vertices, std::vector<RGB> colors)
{
unsigned int numVertices = vertices.size();
unsigned int numColors = colors.size();
// Open File
FILE *meshFile = NULL;
errno_t err = fopen_s(&meshFile, filename.c_str(), "wt");
// Write the header line
std::string header = "ply\nformat ascii 1.0\n";
fwrite(header.c_str(), sizeof(char), header.length(), meshFile);
const unsigned int bufSize = 1000 * 3;
char outStr[bufSize];
int written = 0;
// Elements are: x,y,z, r,g,b
written = sprintf_s(outStr, bufSize, "element vertex %u\nproperty float x\nproperty float y\nproperty float z\nproperty uchar red\nproperty uchar green\nproperty uchar blue\n", numVertices);
fwrite(outStr, sizeof(char), written, meshFile);
written = sprintf_s(outStr, bufSize, "end_header\n");
fwrite(outStr, sizeof(char), written, meshFile);
// Sequentially write the 3 vertices of the triangle, for each triangle
for (unsigned int vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
{
unsigned int color0 = colors[vertexIndex].R;
unsigned int color1 = colors[vertexIndex].G;
unsigned int color2 = colors[vertexIndex].B;
written = sprintf_s(outStr, bufSize, "%f %f %f %u %u %u\n",
vertices[vertexIndex].X, vertices[vertexIndex].Y, vertices[vertexIndex].Z,
((color0)& 255), ((color1)& 255), (color2 & 255));
fwrite(outStr, sizeof(char), written, meshFile);
}
fflush(meshFile);
fclose(meshFile);
}
void loadPLY(string filename, vector<Point3f> &verts, vector<RGB> &colors)
{
FILE *f;
int nVerts;
fopen_s(&f, filename.c_str(), "r");
char buffer[100];
fgets(buffer, 100, f);
fgets(buffer, 100, f);
fgets(buffer, 100, f);
sscanf_s(buffer, "element vertex %d\n", &nVerts);
for (int i = 0; i < 7; i++)
fgets(buffer, 100, f);
for (int i = 0; i < nVerts; i++)
{
fgets(buffer, 100, f);
Point3f point;
RGB rgb;
int R, G, B;
sscanf_s(buffer, "%f %f %f %d %d %d\n", &point.X, &point.Y, &point.Z, &R, &G, &B);
rgb.R = R;
rgb.G = G;
rgb.B = B;
verts.push_back(point);
colors.push_back(rgb);
}
fclose(f);
}
//This function here can be used to test the ICP functionality, it aligns the points clouds in "test1.ply" and "test2.ply"
int main()
{
vector<Point3f> verts1, verts2;
vector<RGB> colors1, colors2;
loadPLY("../test1.ply", verts1, colors1);
loadPLY("../test2.ply", verts2, colors2);
cv::Mat R = cv::Mat::eye(3, 3, CV_32F);
cv::Mat t(1, 3, CV_32F, cv::Scalar(0));
cv::Mat verts2Mat(verts2.size(), 3, CV_32F, (float*)verts2.data());
ICP(verts1.data(), verts2.data(), verts1.size(), verts2.size(), (float*)R.data, (float*)t.data, 1);
savePLY("../testResult.ply", verts2, colors2);
return 0;
}
+257
View File
@@ -0,0 +1,257 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "calibration.h"
#include "Kinect.h"
#include "opencv\cv.h"
Calibration::Calibration()
{
bCalibrated = false;
nSampleCounter = 0;
nRequiredSamples = 20;
pDetector = new MarkerDetector();
}
Calibration::~Calibration()
{
if (pDetector != NULL)
{
delete pDetector;
pDetector = NULL;
}
}
bool Calibration::Calibrate(RGB *pBuffer, Point3f *pCameraCoordinates, int cColorWidth, int cColorHeight)
{
MarkerInfo marker;
bool res = pDetector->GetMarker(pBuffer, cColorHeight, cColorWidth, marker);
if (!res)
return false;
int indexInPoses = -1;
for (unsigned int j = 0; j < markerPoses.size(); j++)
{
if (marker.id == markerPoses[j].markerId)
{
indexInPoses = j;
break;
}
}
if (indexInPoses == -1)
return false;
MarkerPose markerPose = markerPoses[indexInPoses];
iUsedMarkerId = markerPose.markerId;
vector<Point3f> marker3D(marker.corners.size());
bool success = GetMarkerCorners3D(marker3D, marker, pCameraCoordinates, cColorWidth, cColorHeight);
if (!success)
{
return false;
}
marker3DSamples.push_back(marker3D);
nSampleCounter++;
if (nSampleCounter < nRequiredSamples)
return false;
for (size_t i = 0; i < marker3D.size(); i++)
{
marker3D[i] = Point3f();
for (int j = 0; j < nRequiredSamples; j++)
{
marker3D[i].X += marker3DSamples[j][i].X / (float)nRequiredSamples;
marker3D[i].Y += marker3DSamples[j][i].Y / (float)nRequiredSamples;
marker3D[i].Z += marker3DSamples[j][i].Z / (float)nRequiredSamples;
}
}
Procrustes(marker, marker3D, worldT, worldR);
vector<vector<float>> Rcopy = worldR;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
worldR[i][j] = 0;
for (int k = 0; k < 3; k++)
{
worldR[i][j] += markerPose.R[i][k] * Rcopy[k][j];
}
}
}
cameraR = worldR;
cameraT = RotatePoint(worldT, cameraR);
vector<float> translationIncr(3);
translationIncr[0] = markerPose.t[0];
translationIncr[1] = markerPose.t[1];
translationIncr[2] = markerPose.t[2];
cameraT[0] += translationIncr[0];
cameraT[1] += translationIncr[1];
cameraT[2] += translationIncr[2];
translationIncr = InverseRotatePoint(translationIncr, worldR);
worldT[0] += translationIncr[0];
worldT[1] += translationIncr[1];
worldT[2] += translationIncr[2];
bCalibrated = true;
marker3DSamples.clear();
nSampleCounter = 0;
return true;
}
void Calibration::Procrustes(MarkerInfo &marker, vector<Point3f> &markerInWorld, vector<float> &worldToMarkerT, vector<vector<float>> &worldToMarkerR)
{
int nVertices = marker.points.size();
Point3f markerCenterInWorld;
Point3f markerCenter;
for (int i = 0; i < nVertices; i++)
{
markerCenterInWorld.X += markerInWorld[i].X / nVertices;
markerCenterInWorld.Y += markerInWorld[i].Y / nVertices;
markerCenterInWorld.Z += markerInWorld[i].Z / nVertices;
markerCenter.X += marker.points[i].X / nVertices;
markerCenter.Y += marker.points[i].Y / nVertices;
markerCenter.Z += marker.points[i].Z / nVertices;
}
worldToMarkerT.resize(3);
worldToMarkerT[0] = -markerCenterInWorld.X;
worldToMarkerT[1] = -markerCenterInWorld.Y;
worldToMarkerT[2] = -markerCenterInWorld.Z;
vector<Point3f> markerInWorldTranslated(nVertices);
vector<Point3f> markerTranslated(nVertices);
for (int i = 0; i < nVertices; i++)
{
markerInWorldTranslated[i].X = markerInWorld[i].X + worldToMarkerT[0];
markerInWorldTranslated[i].Y = markerInWorld[i].Y + worldToMarkerT[1];
markerInWorldTranslated[i].Z = markerInWorld[i].Z + worldToMarkerT[2];
markerTranslated[i].X = marker.points[i].X - markerCenter.X;
markerTranslated[i].Y = marker.points[i].Y - markerCenter.Y;
markerTranslated[i].Z = marker.points[i].Z - markerCenter.Z;
}
cv::Mat A(nVertices, 3, CV_64F);
cv::Mat B(nVertices, 3, CV_64F);
for (int i = 0; i < nVertices; i++)
{
A.at<double>(i, 0) = markerTranslated[i].X;
A.at<double>(i, 1) = markerTranslated[i].Y;
A.at<double>(i, 2) = markerTranslated[i].Z;
B.at<double>(i, 0) = markerInWorldTranslated[i].X;
B.at<double>(i, 1) = markerInWorldTranslated[i].Y;
B.at<double>(i, 2) = markerInWorldTranslated[i].Z;
}
cv::Mat M = A.t() * B;
cv::SVD svd;
svd(M);
cv::Mat R = svd.u * svd.vt;
double det = cv::determinant(R);
if (det < 0)
{
cv::Mat temp = cv::Mat::eye(3, 3, CV_64F);
temp.at<double>(2, 2) = -1;
R = svd.u * temp * svd.vt;
}
worldToMarkerR.resize(3);
for (int i = 0; i < 3; i++)
{
worldToMarkerR[i].resize(3);
for (int j = 0; j < 3; j++)
{
worldToMarkerR[i][j] = static_cast<float>(R.at<double>(i, j));
}
}
}
bool Calibration::GetMarkerCorners3D(vector<Point3f> &marker3D, MarkerInfo &marker, Point3f *pCameraCoordinates, int cColorWidth, int cColorHeight)
{
for (unsigned int i = 0; i < marker.corners.size(); i++)
{
int minX = static_cast<int>(marker.corners[i].X);
int maxX = minX + 1;
int minY = static_cast<int>(marker.corners[i].Y);
int maxY = minY + 1;
float dx = marker.corners[i].X - minX;
float dy = marker.corners[i].Y - minY;
Point3f pointMin = pCameraCoordinates[minX + minY * cColorWidth];
Point3f pointXMaxYMin = pCameraCoordinates[maxX + minY * cColorWidth];
Point3f pointXMinYMax = pCameraCoordinates[minX + maxY * cColorWidth];
Point3f pointMax = pCameraCoordinates[maxX + maxY * cColorWidth];
if (pointMin.Z < 0 || pointXMaxYMin.Z < 0 || pointXMinYMax.Z < 0 || pointMax.Z < 0)
return false;
marker3D[i].X = (1 - dx) * (1 - dy) * pointMin.X + dx * (1 - dy) * pointXMaxYMin.X + (1 - dx) * dy * pointXMinYMax.X + dx * dy * pointMax.X;
marker3D[i].Y = (1 - dx) * (1 - dy) * pointMin.Y + dx * (1 - dy) * pointXMaxYMin.Y + (1 - dx) * dy * pointXMinYMax.Y + dx * dy * pointMax.Y;
marker3D[i].Z = (1 - dx) * (1 - dy) * pointMin.Z + dx * (1 - dy) * pointXMaxYMin.Z + (1 - dx) * dy * pointXMinYMax.Z + dx * dy * pointMax.Z;
}
return true;
}
vector<float> InverseRotatePoint(vector<float> &point, std::vector<std::vector<float>> &R)
{
vector<float> res(3);
res[0] = point[0] * R[0][0] + point[1] * R[1][0] + point[2] * R[2][0];
res[1] = point[0] * R[0][1] + point[1] * R[1][1] + point[2] * R[2][1];
res[2] = point[0] * R[0][2] + point[1] * R[1][2] + point[2] * R[2][2];
return res;
}
vector<float> RotatePoint(vector<float> &point, std::vector<std::vector<float>> &R)
{
vector<float> res(3);
res[0] = point[0] * R[0][0] + point[1] * R[0][1] + point[2] * R[0][2];
res[1] = point[0] * R[1][0] + point[1] * R[1][1] + point[2] * R[1][2];
res[2] = point[0] * R[2][0] + point[1] * R[2][1] + point[2] * R[2][2];
return res;
}
+75
View File
@@ -0,0 +1,75 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "filter.h"
using namespace std;
vector<KNNeighborsResult> KNNeighbors(PointCloud &cloud, kdTree &tree, int k)
{
vector<KNNeighborsResult> result(cloud.pts.size());
int nCloudPts = static_cast<int>(cloud.pts.size());
#pragma omp parallel for
for (int i = 0; i < nCloudPts; i++)
{
result[i].neighbors.resize(k);
result[i].distances.resize(k);
tree.knnSearch((float*)(cloud.pts.data() + i), k, (size_t*)result[i].neighbors.data(), result[i].distances.data());
result[i].kDistance = result[i].distances[k - 1];
}
return result;
}
void filter(std::vector<Point3f> &vertices, std::vector<RGB> &colors, int k, float maxDist)
{
if (k <= 0 || maxDist <= 0)
return;
PointCloud cloud;
cloud.pts = vertices;
kdTree tree(3, cloud);
tree.buildIndex();
vector<KNNeighborsResult> knn = KNNeighbors(cloud, tree, k);
vector<int> indicesToRemove;
float distThreshold = pow(maxDist, 2);
for (unsigned int i = 0; i < cloud.pts.size(); i++)
{
if (knn[i].kDistance > distThreshold)
indicesToRemove.push_back(i);
}
int lastElemIdx = 0;
unsigned int idxToCheck = 0;
for (unsigned int i = 0; i < vertices.size(); i++)
{
if (idxToCheck < indicesToRemove.size() && i == indicesToRemove[idxToCheck])
{
idxToCheck++;
continue;
}
vertices[lastElemIdx] = vertices[i];
colors[lastElemIdx] = colors[i];
lastElemIdx++;
}
vertices.resize(lastElemIdx);
colors.resize(lastElemIdx);
}
+43
View File
@@ -0,0 +1,43 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "ICapture.h"
ICapture::ICapture()
{
bInitialized = false;
nColorFrameHeight = 0;
nColorFrameWidth = 0;
nDepthFrameHeight = 0;
nDepthFrameWidth = 0;
pDepth = NULL;
pColorRGBX = NULL;
}
ICapture::~ICapture()
{
if (pDepth != NULL)
{
delete[] pDepth;
pDepth = NULL;
}
if (pColorRGBX != NULL)
{
delete[] pColorRGBX;
pColorRGBX = NULL;
}
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "IMarker.h"
+166
View File
@@ -0,0 +1,166 @@
//------------------------------------------------------------------------------
// <copyright file="ImageRenderer.cpp" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
#include "stdafx.h"
#include "ImageRenderer.h"
/// <summary>
/// Constructor
/// </summary>
ImageRenderer::ImageRenderer() :
m_hWnd(0),
m_sourceWidth(0),
m_sourceHeight(0),
m_sourceStride(0),
m_pD2DFactory(NULL),
m_pRenderTarget(NULL),
m_pBitmap(0)
{
}
/// <summary>
/// Destructor
/// </summary>
ImageRenderer::~ImageRenderer()
{
DiscardResources();
SafeRelease(m_pD2DFactory);
}
/// <summary>
/// Ensure necessary Direct2d resources are created
/// </summary>
/// <returns>indicates success or failure</returns>
HRESULT ImageRenderer::EnsureResources()
{
HRESULT hr = S_OK;
if (NULL == m_pRenderTarget)
{
D2D1_SIZE_U size = D2D1::SizeU(m_sourceWidth, m_sourceHeight);
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
// Create a hWnd render target, in order to render to the window set in initialize
hr = m_pD2DFactory->CreateHwndRenderTarget(
rtProps,
D2D1::HwndRenderTargetProperties(m_hWnd, size),
&m_pRenderTarget
);
if (FAILED(hr))
{
return hr;
}
// Create a bitmap that we can copy image data into and then render to the target
hr = m_pRenderTarget->CreateBitmap(
size,
D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)),
&m_pBitmap
);
if (FAILED(hr))
{
SafeRelease(m_pRenderTarget);
return hr;
}
}
return hr;
}
/// <summary>
/// Dispose of Direct2d resources
/// </summary>
void ImageRenderer::DiscardResources()
{
SafeRelease(m_pRenderTarget);
SafeRelease(m_pBitmap);
}
/// <summary>
/// Set the window to draw to as well as the video format
/// Implied bits per pixel is 32
/// </summary>
/// <param name="hWnd">window to draw to</param>
/// <param name="pD2DFactory">already created D2D factory object</param>
/// <param name="sourceWidth">width (in pixels) of image data to be drawn</param>
/// <param name="sourceHeight">height (in pixels) of image data to be drawn</param>
/// <param name="sourceStride">length (in bytes) of a single scanline</param>
/// <returns>indicates success or failure</returns>
HRESULT ImageRenderer::Initialize(HWND hWnd, ID2D1Factory* pD2DFactory, int sourceWidth, int sourceHeight, int sourceStride)
{
if (NULL == pD2DFactory)
{
return E_INVALIDARG;
}
m_hWnd = hWnd;
// One factory for the entire application so save a pointer here
m_pD2DFactory = pD2DFactory;
m_pD2DFactory->AddRef();
// Get the frame size
m_sourceWidth = sourceWidth;
m_sourceHeight = sourceHeight;
m_sourceStride = sourceStride;
return S_OK;
}
/// <summary>
/// Draws a 32 bit per pixel image of previously specified width, height, and stride to the associated hwnd
/// </summary>
/// <param name="pImage">image data in RGBX format</param>
/// <param name="cbImage">size of image data in bytes</param>
/// <returns>indicates success or failure</returns>
HRESULT ImageRenderer::Draw(BYTE* pImage, unsigned long cbImage)
{
// incorrectly sized image data passed in
if (cbImage < ((m_sourceHeight - 1) * m_sourceStride) + (m_sourceWidth * 4))
{
return E_INVALIDARG;
}
// create the resources for this draw device
// they will be recreated if previously lost
HRESULT hr = EnsureResources();
if (FAILED(hr))
{
return hr;
}
// Copy the image that was passed in into the direct2d bitmap
hr = m_pBitmap->CopyFromMemory(NULL, pImage, m_sourceStride);
if (FAILED(hr))
{
return hr;
}
m_pRenderTarget->BeginDraw();
// Draw the bitmap stretched to the size of the window
m_pRenderTarget->DrawBitmap(m_pBitmap);
hr = m_pRenderTarget->EndDraw();
// Device lost, need to recreate the render target
// We'll dispose it now and retry drawing
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardResources();
}
return hr;
}
+163
View File
@@ -0,0 +1,163 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "KinectCapture.h"
#include <chrono>
KinectCapture::KinectCapture()
{
pKinectSensor = NULL;
pCoordinateMapper = NULL;
pMultiSourceFrameReader = NULL;
}
KinectCapture::~KinectCapture()
{
SafeRelease(pKinectSensor);
SafeRelease(pCoordinateMapper);
SafeRelease(pMultiSourceFrameReader);
}
bool KinectCapture::Initialize()
{
HRESULT hr;
hr = GetDefaultKinectSensor(&pKinectSensor);
if (FAILED(hr))
{
bInitialized = false;
return bInitialized;
}
if (pKinectSensor)
{
pKinectSensor->get_CoordinateMapper(&pCoordinateMapper);
hr = pKinectSensor->Open();
if (SUCCEEDED(hr))
{
pKinectSensor->OpenMultiSourceFrameReader(FrameSourceTypes::FrameSourceTypes_Color | FrameSourceTypes::FrameSourceTypes_Depth, &pMultiSourceFrameReader);
}
}
bInitialized = SUCCEEDED(hr);
if (bInitialized)
{
std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
bool bTemp;
do
{
bTemp = AcquireFrame();
std::chrono::duration<double> elapsedSeconds = std::chrono::system_clock::now() - start;
if (elapsedSeconds.count() > 5.0)
{
bInitialized = false;
break;
}
} while (!bTemp);
}
return bInitialized;
}
bool KinectCapture::AcquireFrame()
{
if (!bInitialized)
{
return false;
}
//Multi frame
IMultiSourceFrame* pMultiFrame = NULL;
HRESULT hr = pMultiSourceFrameReader->AcquireLatestFrame(&pMultiFrame);
if (!SUCCEEDED(hr))
{
return false;
}
//Depth frame
IDepthFrameReference* pDepthFrameReference = NULL;
IDepthFrame* pDepthFrame = NULL;
pMultiFrame->get_DepthFrameReference(&pDepthFrameReference);
hr = pDepthFrameReference->AcquireFrame(&pDepthFrame);
if (SUCCEEDED(hr))
{
if (pDepth == NULL)
{
IFrameDescription* pFrameDescription = NULL;
hr = pDepthFrame->get_FrameDescription(&pFrameDescription);
pFrameDescription->get_Width(&nDepthFrameWidth);
pFrameDescription->get_Height(&nDepthFrameHeight);
pDepth = new UINT16[nDepthFrameHeight * nDepthFrameWidth];
SafeRelease(pFrameDescription);
}
UINT nBufferSize = nDepthFrameHeight * nDepthFrameWidth;
hr = pDepthFrame->CopyFrameDataToArray(nBufferSize, pDepth);
}
SafeRelease(pDepthFrame);
SafeRelease(pDepthFrameReference);
//Color frame
IColorFrameReference* pColorFrameReference = NULL;
IColorFrame* pColorFrame = NULL;
pMultiFrame->get_ColorFrameReference(&pColorFrameReference);
hr = pColorFrameReference->AcquireFrame(&pColorFrame);
if (SUCCEEDED(hr))
{
if (pColorRGBX == NULL)
{
IFrameDescription* pFrameDescription = NULL;
hr = pColorFrame->get_FrameDescription(&pFrameDescription);
hr = pFrameDescription->get_Width(&nColorFrameWidth);
hr = pFrameDescription->get_Height(&nColorFrameHeight);
pColorRGBX = new RGB[nColorFrameWidth * nColorFrameHeight];
SafeRelease(pFrameDescription);
}
UINT nBufferSize = nColorFrameWidth * nColorFrameHeight * sizeof(RGB);
hr = pColorFrame->CopyConvertedFrameDataToArray(nBufferSize, reinterpret_cast<BYTE*>(pColorRGBX), ColorImageFormat_Bgra);
}
SafeRelease(pColorFrame);
SafeRelease(pColorFrameReference);
return true;
}
void KinectCapture::MapDepthFrameToCameraSpace(Point3f *pCameraSpacePoints)
{
pCoordinateMapper->MapDepthFrameToCameraSpace(nDepthFrameWidth * nDepthFrameHeight, pDepth, nDepthFrameWidth * nDepthFrameHeight, (CameraSpacePoint*)pCameraSpacePoints);
}
void KinectCapture::MapColorFrameToCameraSpace(Point3f *pCameraSpacePoints)
{
pCoordinateMapper->MapColorFrameToCameraSpace(nDepthFrameWidth * nDepthFrameHeight, pDepth, nColorFrameWidth * nColorFrameHeight, (CameraSpacePoint*)pCameraSpacePoints);
}
void KinectCapture::MapDepthFrameToColorSpace(Point2f *pColorSpacePoints)
{
pCoordinateMapper->MapDepthFrameToColorSpace(nDepthFrameWidth * nDepthFrameHeight, pDepth, nDepthFrameWidth * nDepthFrameHeight, (ColorSpacePoint*)pColorSpacePoints);
}
void KinectCapture::MapColorFrameToDepthSpace(Point2f *pDepthSpacePoints)
{
pCoordinateMapper->MapColorFrameToDepthSpace(nDepthFrameWidth * nDepthFrameHeight, pDepth, nColorFrameWidth * nColorFrameHeight, (DepthSpacePoint*)pDepthSpacePoints);;
}
+735
View File
@@ -0,0 +1,735 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "stdafx.h"
#include "resource.h"
#include "LiveScanClient.h"
#include "filter.h"
#include <chrono>
#include <strsafe.h>
#include <fstream>
std::mutex m_mSocketThreadMutex;
int APIENTRY wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nShowCmd
)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
LiveScanClient application;
application.Run(hInstance, nShowCmd);
}
LiveScanClient::LiveScanClient() :
m_hWnd(NULL),
m_nLastCounter(0),
m_nFramesSinceUpdate(0),
m_fFreq(0),
m_nNextStatusTime(0LL),
m_pD2DFactory(NULL),
m_pDrawColor(NULL),
m_pDepthRGBX(NULL),
m_pCameraSpaceCoordinates(NULL),
m_bCalibrate(false),
m_bFilter(false),
m_bCaptureFrame(false),
m_bConnected(false),
m_bConfirmCaptured(false),
m_bConfirmCalibrated(false),
m_bShowDepth(false),
m_bSocketThread(true),
m_pClientSocket(NULL),
m_nFilterNeighbors(10),
m_fFilterThreshold(0.01f)
{
pCapture = new KinectCapture();
LARGE_INTEGER qpf = {0};
if (QueryPerformanceFrequency(&qpf))
{
m_fFreq = double(qpf.QuadPart);
}
m_vBounds.push_back(-0.5);
m_vBounds.push_back(-0.5);
m_vBounds.push_back(-0.5);
m_vBounds.push_back(0.5);
m_vBounds.push_back(0.5);
m_vBounds.push_back(0.5);
}
LiveScanClient::~LiveScanClient()
{
// clean up Direct2D renderer
if (m_pDrawColor)
{
delete m_pDrawColor;
m_pDrawColor = NULL;
}
if (pCapture)
{
delete pCapture;
pCapture = NULL;
}
if (m_pDepthRGBX)
{
delete[] m_pDepthRGBX;
m_pDepthRGBX = NULL;
}
if (m_pCameraSpaceCoordinates)
{
delete[] m_pCameraSpaceCoordinates;
m_pCameraSpaceCoordinates = NULL;
}
if (m_pColorCoordinates)
{
delete[] m_pColorCoordinates;
m_pColorCoordinates = NULL;
}
if (m_pClientSocket)
{
delete m_pClientSocket;
m_pClientSocket = NULL;
}
// clean up Direct2D
SafeRelease(m_pD2DFactory);
}
int LiveScanClient::Run(HINSTANCE hInstance, int nCmdShow)
{
MSG msg = {0};
WNDCLASS wc;
// Dialog custom window class
ZeroMemory(&wc, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(IDI_APP));
wc.lpfnWndProc = DefDlgProcW;
wc.lpszClassName = L"LiveScanClientAppDlgWndClass";
if (!RegisterClassW(&wc))
{
return 0;
}
// Create main application window
HWND hWndApp = CreateDialogParamW(
NULL,
MAKEINTRESOURCE(IDD_APP),
NULL,
(DLGPROC)LiveScanClient::MessageRouter,
reinterpret_cast<LPARAM>(this));
// Show window
ShowWindow(hWndApp, nCmdShow);
std::thread t1(&LiveScanClient::SocketThreadFunction, this);
// Main message loop
while (WM_QUIT != msg.message)
{
//HandleSocket();
UpdateFrame();
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
// If a dialog message will be taken care of by the dialog proc
if (hWndApp && IsDialogMessageW(hWndApp, &msg))
{
continue;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
m_bSocketThread = false;
t1.join();
return static_cast<int>(msg.wParam);
}
void LiveScanClient::UpdateFrame()
{
if (!pCapture->bInitialized)
{
return;
}
bool bNewFrameAcquired = pCapture->AcquireFrame();
if (!bNewFrameAcquired)
return;
pCapture->MapDepthFrameToCameraSpace(m_pCameraSpaceCoordinates);
pCapture->MapDepthFrameToColorSpace(m_pColorCoordinates);
{
std::lock_guard<std::mutex> lock(m_mSocketThreadMutex);
StoreFrame(m_pCameraSpaceCoordinates, m_pColorCoordinates, pCapture->pColorRGBX);
if (m_bCaptureFrame)
{
m_vGatheredVertices.push_back(m_vLastFrameVertices);
m_vGatheredRGBPoints.push_back(m_vLastFrameRGB);
m_bConfirmCaptured = true;
m_bCaptureFrame = false;
}
}
if (m_bCalibrate)
{
std::lock_guard<std::mutex> lock(m_mSocketThreadMutex);
Point3f *pCameraCoordinates = new Point3f[pCapture->nColorFrameWidth * pCapture->nColorFrameHeight];
pCapture->MapColorFrameToCameraSpace(pCameraCoordinates);
bool res = calibration.Calibrate(pCapture->pColorRGBX, pCameraCoordinates, pCapture->nColorFrameWidth, pCapture->nColorFrameHeight);
delete[] pCameraCoordinates;
if (res)
{
m_bConfirmCalibrated = true;
m_bCalibrate = false;
}
}
if (!m_bShowDepth)
ProcessColor(pCapture->pColorRGBX, pCapture->nColorFrameWidth, pCapture->nColorFrameHeight);
else
ProcessDepth(pCapture->pDepth, pCapture->nDepthFrameWidth, pCapture->nDepthFrameHeight);
ShowFPS();
}
LRESULT CALLBACK LiveScanClient::MessageRouter(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LiveScanClient* pThis = NULL;
if (WM_INITDIALOG == uMsg)
{
pThis = reinterpret_cast<LiveScanClient*>(lParam);
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
}
else
{
pThis = reinterpret_cast<LiveScanClient*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
}
if (pThis)
{
return pThis->DlgProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK LiveScanClient::DlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
{
// Bind application window handle
m_hWnd = hWnd;
// Init Direct2D
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
// Get and initialize the default Kinect sensor
bool res = pCapture->Initialize();
if (res)
{
m_pDepthRGBX = new RGB[pCapture->nColorFrameWidth * pCapture->nColorFrameHeight];
m_pCameraSpaceCoordinates = new Point3f[pCapture->nDepthFrameWidth * pCapture->nDepthFrameHeight];
m_pColorCoordinates = new Point2f[pCapture->nDepthFrameWidth * pCapture->nDepthFrameHeight];
}
else
{
SetStatusMessage(L"Capture device failed to initialize!", 10000, true);
}
// Create and initialize a new Direct2D image renderer (take a look at ImageRenderer.h)
// We'll use this to draw the data we receive from the Kinect to the screen
HRESULT hr;
m_pDrawColor = new ImageRenderer();
hr = m_pDrawColor->Initialize(GetDlgItem(m_hWnd, IDC_VIDEOVIEW), m_pD2DFactory, pCapture->nColorFrameWidth, pCapture->nColorFrameHeight, pCapture->nColorFrameWidth * sizeof(RGB));
if (FAILED(hr))
{
SetStatusMessage(L"Failed to initialize the Direct2D draw device.", 10000, true);
}
ReadIPFromFile();
}
break;
// If the titlebar X is clicked, destroy app
case WM_CLOSE:
WriteIPToFile();
DestroyWindow(hWnd);
break;
case WM_DESTROY:
// Quit the main message pump
PostQuitMessage(0);
break;
// Handle button press
case WM_COMMAND:
if (IDC_BUTTON_CONNECT == LOWORD(wParam) && BN_CLICKED == HIWORD(wParam))
{
std::lock_guard<std::mutex> lock(m_mSocketThreadMutex);
if (m_bConnected)
{
delete m_pClientSocket;
m_pClientSocket = NULL;
m_bConnected = false;
SetDlgItemTextA(m_hWnd, IDC_BUTTON_CONNECT, "Connect");
}
else
{
m_vGatheredVertices.clear();
m_vGatheredRGBPoints.clear();
try
{
char address[20];
GetDlgItemTextA(m_hWnd, IDC_IP, address, 20);
m_pClientSocket = new SocketClient(address, 48001);
m_bConnected = true;
SetDlgItemTextA(m_hWnd, IDC_BUTTON_CONNECT, "Disconnect");
//Clear the status bar so that the "Failed to connect..." disappears.
SetStatusMessage(L"", 1, true);
}
catch (...)
{
SetStatusMessage(L"Failed to connect. Did you start the server?", 10000, true);
}
}
}
if (IDC_BUTTON_SWITCH == LOWORD(wParam) && BN_CLICKED == HIWORD(wParam))
{
m_bShowDepth = !m_bShowDepth;
if (m_bShowDepth)
{
SetDlgItemTextA(m_hWnd, IDC_BUTTON_SWITCH, "Show color");
}
else
{
SetDlgItemTextA(m_hWnd, IDC_BUTTON_SWITCH, "Show depth");
}
}
break;
}
return FALSE;
}
void LiveScanClient::ProcessDepth(const UINT16* pBuffer, int nWidth, int nHeight)
{
// Make sure we've received valid data
if (m_pDepthRGBX && pBuffer && (nWidth == pCapture->nDepthFrameWidth) && (nHeight == pCapture->nDepthFrameHeight))
{
// end pixel is start + width*height - 1
const UINT16* pBufferEnd = pBuffer + (nWidth * nHeight);
Point2f *pDepthSpacePoints = new Point2f[pCapture->nColorFrameWidth * pCapture->nColorFrameHeight];
pCapture->MapColorFrameToDepthSpace(pDepthSpacePoints);
for (int i = 0; i < pCapture->nColorFrameWidth * pCapture->nColorFrameHeight; i++)
{
Point2f depthPoint = pDepthSpacePoints[i];
BYTE intensity = 0;
if (depthPoint.X >= 0 && depthPoint.Y >= 0)
{
int depthIdx = (int)(depthPoint.X + depthPoint.Y * pCapture->nDepthFrameWidth);
USHORT depth = pBuffer[depthIdx];
intensity = static_cast<BYTE>(depth % 256);
}
m_pDepthRGBX[i].rgbRed = intensity;
m_pDepthRGBX[i].rgbGreen = intensity;
m_pDepthRGBX[i].rgbBlue = intensity;
}
// Draw the data with Direct2D
m_pDrawColor->Draw(reinterpret_cast<BYTE*>(m_pDepthRGBX), pCapture->nColorFrameWidth * pCapture->nColorFrameHeight * sizeof(RGB));
delete[] pDepthSpacePoints;
}
}
void LiveScanClient::ProcessColor(RGB* pBuffer, int nWidth, int nHeight)
{
// Make sure we've received valid data
if (pBuffer && (nWidth == pCapture->nColorFrameWidth) && (nHeight == pCapture->nColorFrameHeight))
{
// Draw the data with Direct2D
m_pDrawColor->Draw(reinterpret_cast<BYTE*>(pBuffer), pCapture->nColorFrameWidth * pCapture->nColorFrameHeight * sizeof(RGB));
}
}
bool LiveScanClient::SetStatusMessage(_In_z_ WCHAR* szMessage, DWORD nShowTimeMsec, bool bForce)
{
INT64 now = GetTickCount64();
if (m_hWnd && (bForce || (m_nNextStatusTime <= now)))
{
SetDlgItemText(m_hWnd, IDC_STATUS, szMessage);
m_nNextStatusTime = now + nShowTimeMsec;
return true;
}
return false;
}
void LiveScanClient::SocketThreadFunction()
{
while (m_bSocketThread)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
HandleSocket();
}
}
void LiveScanClient::HandleSocket()
{
char byteToSend;
std::lock_guard<std::mutex> lock(m_mSocketThreadMutex);
if (!m_bConnected)
{
return;
}
string received = m_pClientSocket->ReceiveBytes();
for (unsigned int i = 0; i < received.length(); i++)
{
//capture a frame
if (received[i] == MSG_CAPTURE_FRAME)
m_bCaptureFrame = true;
//calibrate
else if (received[i] == MSG_CALIBRATE)
m_bCalibrate = true;
//receive settings
//TODO: what if packet is split?
else if (received[i] == MSG_RECEIVE_SETTINGS)
{
vector<float> bounds(6);
i++;
int nBytes = *(int*)(received.c_str() + i);
i += sizeof(int);
for (int j = 0; j < 6; j++)
{
bounds[j] = *(float*)(received.c_str() + i);
i += sizeof(float);
}
m_bFilter = (received[i]!=0);
i++;
m_nFilterNeighbors = *(int*)(received.c_str() + i);
i += sizeof(int);
m_fFilterThreshold = *(float*)(received.c_str() + i);
i += sizeof(float);
m_vBounds = bounds;
int nMarkers = *(int*)(received.c_str() + i);
i += sizeof(int);
calibration.markerPoses.resize(nMarkers);
for (int j = 0; j < nMarkers; j++)
{
for (int k = 0; k < 3; k++)
{
for (int l = 0; l < 3; l++)
{
calibration.markerPoses[j].R[k][l] = *(float*)(received.c_str() + i);
i += sizeof(float);
}
}
for (int k = 0; k < 3; k++)
{
calibration.markerPoses[j].t[k] = *(float*)(received.c_str() + i);
i += sizeof(float);
}
calibration.markerPoses[j].markerId = *(int*)(received.c_str() + i);
i += sizeof(int);
}
//so that we do not lose the next character in the stream
i--;
}
//send stored frame
else if (received[i] == MSG_REQUEST_STORED_FRAME)
{
byteToSend = MSG_STORED_FRAME;
m_pClientSocket->SendBytes(&byteToSend, 1);
if (m_vGatheredRGBPoints.size() > 0)
{
int size = m_vGatheredRGBPoints[0].size() * (3 + 3 * sizeof(float));
//m_pClientSocket->SendLine(to_string(size));
m_pClientSocket->SendBytes((char*)&size, 4);
char *to_send = new char[size];
char *ptr1 = (char*)m_vGatheredRGBPoints[0].data();
char *ptr2 = (char*)m_vGatheredVertices[0].data();
int pos = 0, initial_pos;
for (unsigned int i = 0; i < m_vGatheredRGBPoints[0].size(); i++)
{
initial_pos = pos;
to_send[pos++] = m_vGatheredRGBPoints[0][i].rgbRed;
to_send[pos++] = m_vGatheredRGBPoints[0][i].rgbGreen;
to_send[pos++] = m_vGatheredRGBPoints[0][i].rgbBlue;
memcpy(to_send + pos, ptr2, sizeof(float)* 3);
ptr2 += sizeof(float)* 3;
pos += sizeof(float)* 3;
}
m_pClientSocket->SendBytes(to_send, size);
delete[]to_send;
m_vGatheredRGBPoints.erase(m_vGatheredRGBPoints.begin(), m_vGatheredRGBPoints.begin() + 1);
m_vGatheredVertices.erase(m_vGatheredVertices.begin(), m_vGatheredVertices.begin() + 1);
}
else
{
int size = 0;
m_pClientSocket->SendBytes((char*)&size, 4);
}
}
//send last frame
else if (received[i] == MSG_REQUEST_LAST_FRAME)
{
byteToSend = MSG_LAST_FRAME;
m_pClientSocket->SendBytes(&byteToSend, 1);
int size = m_vLastFrameRGB.size() * (3 + 3 * sizeof(float));
//m_pClientSocket->SendLine(to_string(size));
m_pClientSocket->SendBytes((char*)&size, 4);
char *buffer = new char[size];
char *ptr2 = (char*)m_vLastFrameVertices.data();
int pos = 0, initial_pos;
for (unsigned int i = 0; i < m_vLastFrameRGB.size(); i++)
{
initial_pos = pos;
buffer[pos++] = m_vLastFrameRGB[i].rgbRed;
buffer[pos++] = m_vLastFrameRGB[i].rgbGreen;
buffer[pos++] = m_vLastFrameRGB[i].rgbBlue;
memcpy(buffer + pos, ptr2, sizeof(float)* 3);
ptr2 += sizeof(float)* 3;
pos += sizeof(float)* 3;
}
m_pClientSocket->SendBytes(buffer, size);
delete[]buffer;
}
//receive calibration data
else if (received[i] == MSG_RECEIVE_CALIBRATION)
{
i++;
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
calibration.worldR[j][k] = *(float*)(received.c_str() + i);
i += sizeof(float);
}
}
for (int j = 0; j < 3; j++)
{
calibration.worldT[j] = *(float*)(received.c_str() + i);
i += sizeof(float);
}
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
calibration.cameraR[j][k] = *(float*)(received.c_str() + i);
i += sizeof(float);
}
}
for (int j = 0; j < 3; j++)
{
calibration.cameraT[j] = *(float*)(received.c_str() + i);
i += sizeof(float);
}
//so that we do not lose the next character in the stream
i--;
}
else if (received[i] == MSG_CLEAR_STORED_FRAMES)
{
m_vGatheredVertices.clear();
m_vGatheredRGBPoints.clear();
}
}
if (m_bConfirmCaptured)
{
byteToSend = MSG_CONFIRM_CAPTURED;
m_pClientSocket->SendBytes(&byteToSend, 1);
m_bConfirmCaptured = false;
}
if (m_bConfirmCalibrated)
{
int size = 2 * (9 + 3) * sizeof(float) + sizeof(int) + 1;
char *buffer = new char[size];
buffer[0] = MSG_CONFIRM_CALIBRATED;
int i = 1;
memcpy(buffer + i, &calibration.iUsedMarkerId, 1 * sizeof(int));
i += 1 * sizeof(int);
memcpy(buffer + i, calibration.worldR[0].data(), 3 * sizeof(float));
i += 3 * sizeof(float);
memcpy(buffer + i, calibration.worldR[1].data(), 3 * sizeof(float));
i += 3 * sizeof(float);
memcpy(buffer + i, calibration.worldR[2].data(), 3 * sizeof(float));
i += 3 * sizeof(float);
memcpy(buffer + i, calibration.worldT.data(), 3 * sizeof(float));
i += 3 * sizeof(float);
memcpy(buffer + i, calibration.cameraR[0].data(), 3 * sizeof(float));
i += 3 * sizeof(float);
memcpy(buffer + i, calibration.cameraR[1].data(), 3 * sizeof(float));
i += 3 * sizeof(float);
memcpy(buffer + i, calibration.cameraR[2].data(), 3 * sizeof(float));
i += 3 * sizeof(float);
memcpy(buffer + i, calibration.cameraT.data(), 3 * sizeof(float));
m_pClientSocket->SendBytes(buffer, size);
m_bConfirmCalibrated = false;
}
}
void LiveScanClient::StoreFrame(Point3f *vertices, Point2f *mapping, RGB *color)
{
std::vector<Point3f> goodVertices;
std::vector<RGB> goodColorPoints;
unsigned int nVertices = pCapture->nDepthFrameWidth * pCapture->nDepthFrameHeight;
for (unsigned int vertexIndex = 0; vertexIndex < nVertices; vertexIndex++)
{
if (vertices[vertexIndex].Z >= 0 && mapping[vertexIndex].Y >= 0 && mapping[vertexIndex].Y < pCapture->nColorFrameHeight)
{
Point3f temp = vertices[vertexIndex];
RGB tempColor = color[(int)mapping[vertexIndex].X + (int)mapping[vertexIndex].Y * pCapture->nColorFrameWidth];
if (calibration.bCalibrated)
{
temp.X += calibration.worldT[0];
temp.Y += calibration.worldT[1];
temp.Z += calibration.worldT[2];
temp = RotatePoint(temp, calibration.worldR);
if (temp.X < m_vBounds[0] || temp.X > m_vBounds[3]
|| temp.Y < m_vBounds[1] || temp.Y > m_vBounds[4]
|| temp.Z < m_vBounds[2] || temp.Z > m_vBounds[5])
continue;
}
goodVertices.push_back(temp);
goodColorPoints.push_back(tempColor);
}
}
if (m_bFilter)
filter(goodVertices, goodColorPoints, m_nFilterNeighbors, m_fFilterThreshold);
m_vLastFrameVertices = goodVertices;
m_vLastFrameRGB = goodColorPoints;
}
void LiveScanClient::ShowFPS()
{
if (m_hWnd)
{
double fps = 0.0;
LARGE_INTEGER qpcNow = { 0 };
if (m_fFreq)
{
if (QueryPerformanceCounter(&qpcNow))
{
if (m_nLastCounter)
{
m_nFramesSinceUpdate++;
fps = m_fFreq * m_nFramesSinceUpdate / double(qpcNow.QuadPart - m_nLastCounter);
}
}
}
WCHAR szStatusMessage[64];
StringCchPrintf(szStatusMessage, _countof(szStatusMessage), L" FPS = %0.2f", fps);
if (SetStatusMessage(szStatusMessage, 1000, false))
{
m_nLastCounter = qpcNow.QuadPart;
m_nFramesSinceUpdate = 0;
}
}
}
void LiveScanClient::ReadIPFromFile()
{
ifstream file;
file.open("lastIP.txt");
if (file.is_open())
{
char lastUsedIPAddress[20];
file.getline(lastUsedIPAddress, 20);
file.close();
SetDlgItemTextA(m_hWnd, IDC_IP, lastUsedIPAddress);
}
}
void LiveScanClient::WriteIPToFile()
{
ofstream file;
file.open("lastIP.txt");
char lastUsedIPAddress[20];
GetDlgItemTextA(m_hWnd, IDC_IP, lastUsedIPAddress, 20);
file << lastUsedIPAddress;
file.close();
}
+394
View File
@@ -0,0 +1,394 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "marker.h"
#include <opencv2/opencv.hpp>
using namespace std;
MarkerDetector::MarkerDetector()
{
nMinSize = 100;
nMaxSize = 1000000000;
nThreshold = 120;
dApproxPolyCoef = 0.12;
dMarkerFrame = 0.4;
nMarkerCorners = 5;
bDraw = true;
GetMarkerPointsForWarp(vPts);
}
bool MarkerDetector::GetMarker(cv::Mat &img, MarkerInfo &marker)
{
vector<MarkerInfo> markers;
cv::Mat img2, img3;
cv::cvtColor(img, img2, CV_BGR2GRAY);
cv::threshold(img2, img2, nThreshold, 255, CV_THRESH_BINARY);
img2.copyTo(img3);
vector<vector<cv::Point>> contours;
cv::findContours(img3, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
for (unsigned int i = 0; i < contours.size(); i++)
{
vector<cv::Point> corners;
double area = cv::contourArea(contours[i]);
if (area < nMinSize || area > nMaxSize)
continue;
cv::approxPolyDP(contours[i], corners, sqrt(area)*dApproxPolyCoef, true);
vector<cv::Point2f> cornersFloat;
for (unsigned int j = 0; j < corners.size(); j++)
{
cornersFloat.push_back(cv::Point2f((float)corners[j].x, (float)corners[j].y));
}
if (!cv::isContourConvex(corners) && corners.size() == nMarkerCorners && OrderCorners(cornersFloat))
{
bool order = true;
int code = GetCode(img2, vPts, cornersFloat);
if (code < 0)
{
reverse(cornersFloat.begin() + 1, cornersFloat.end());
code = GetCode(img2, vPts, cornersFloat);
if (code < 0)
continue;
order = false;
}
float test = cornersFloat[0].x - cornersFloat[1].x;
CornersSubPix(cornersFloat, contours[i], order);
vector<Point2f> cornersFloat2(nMarkerCorners);
vector<Point3f> points3D;
for (int i = 0; i < nMarkerCorners; i++)
{
cornersFloat2[i] = Point2f(cornersFloat[i].x, cornersFloat[i].y);
}
GetMarkerPoints(points3D);
markers.push_back(MarkerInfo(code, cornersFloat2, points3D));
if (bDraw)
{
for (unsigned int j = 0; j < corners.size(); j++)
{
cv::circle(img, cornersFloat[j], 2, cv::Scalar(0, 50 * j, 0), 1);
cv::line(img, cornersFloat[j], cornersFloat[(j + 1) % cornersFloat.size()], cv::Scalar(0, 0, 255), 2);
}
}
}
}
if (markers.size() > 0)
{
double maxArea = 0;
int maxInd = 0;
for (unsigned int i = 0; i < markers.size(); i++)
{
if (GetMarkerArea(markers[i]) > maxArea)
{
maxInd = i;
maxArea = GetMarkerArea(markers[i]);
}
}
marker = markers[maxInd];
if (bDraw)
{
for (int j = 0; j < nMarkerCorners; j++)
{
cv::Point2f pt1 = cv::Point2f(marker.corners[j].X, marker.corners[j].Y);
cv::Point2f pt2 = cv::Point2f(marker.corners[(j + 1) % nMarkerCorners].X, marker.corners[(j + 1) % nMarkerCorners].Y);
cv::line(img, pt1, pt2, cv::Scalar(0, 255, 0), 2);
}
}
return true;
}
else
return false;
}
bool MarkerDetector::GetMarker(RGB *img, int height, int width, MarkerInfo &marker)
{
cv::Mat cvImg(height, width, CV_8UC3);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
cvImg.at<cv::Vec3b>(i, j)[0] = img[j + width * i].rgbBlue;
cvImg.at<cv::Vec3b>(i, j)[1] = img[j + width * i].rgbGreen;
cvImg.at<cv::Vec3b>(i, j)[2] = img[j + width * i].rgbRed;
}
}
bool res = GetMarker(cvImg, marker);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
img[j + width * i].rgbBlue = cvImg.at<cv::Vec3b>(i, j)[0];
img[j + width * i].rgbGreen = cvImg.at<cv::Vec3b>(i, j)[1];
img[j + width * i].rgbRed = cvImg.at<cv::Vec3b>(i, j)[2];
}
}
return res;
}
bool MarkerDetector::OrderCorners(vector<cv::Point2f> &corners)
{
vector<int> hull;
cv::convexHull(corners, hull);
if (hull.size() != corners.size() - 1)
return false;
int index = -1;
for (unsigned int i = 0; i < corners.size(); i++)
{
bool found = false;
for (unsigned int j = 0; j < hull.size(); j++)
{
if (hull[j] == i)
{
found = true;
break;
}
}
if (!found)
{
index = i;
break;
}
}
vector<cv::Point2f> corners2;
for (unsigned int i = 0; i < corners.size(); i++)
{
corners2.push_back(corners[(index + i)%corners.size()]);
}
corners = corners2;
return true;
}
int MarkerDetector::GetCode(cv::Mat &img, vector<cv::Point2f> points, vector<cv::Point2f> corners)
{
cv::Mat H, img2;
int minX = 0, minY = 0;
double markerInterior = 2 - 2 * dMarkerFrame;
for (unsigned int i = 0; i < points.size(); i++)
{
points[i].x = static_cast<float>((points[i].x - dMarkerFrame + 1) * 50);
points[i].y = static_cast<float>((points[i].y - dMarkerFrame + 1) * 50);
}
H = cv::findHomography(corners, points);
cv::warpPerspective(img, img2, H, cv::Size((int)(50 * markerInterior), (int)(50 * markerInterior)));
int xdiff = img2.cols / 3;
int ydiff = img2.rows / 3;
int tot = xdiff * ydiff;
int vals[9];
cv::Mat integral;
cv::integral(img2, integral);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
int temp;
temp = integral.at<int>((i + 1) * xdiff, (j + 1) * ydiff);
temp += integral.at<int>(i * xdiff, j * ydiff);
temp -= integral.at<int>((i + 1) * xdiff, j * ydiff);
temp -= integral.at<int>(i * xdiff, (j + 1) * ydiff);
temp = temp / tot;
if (temp < 128)
vals[j + i * 3] = 0;
else if (temp >= 128)
vals[j + i * 3] = 1;
}
}
int ones = 0;
int code = 0;
for (int i = 0; i < 4; i++)
{
if (vals[i] == vals[i + 4])
return -1;
else if (vals[i] == 1)
{
code += static_cast<int>(pow(2, (double)(3 - i)));
ones++;
}
}
if (ones / 2 == (float)ones / 2.0)
{
if (vals[8] == 0)
return -1;
}
if (ones / 2 != ones / 2.0)
{
if (vals[8] == 1)
return -1;
}
return code;
}
void MarkerDetector::CornersSubPix(vector<cv::Point2f> &corners, vector<cv::Point> contour, bool order)
{
int *indices = new int[corners.size()];
for (unsigned int i = 0; i < corners.size(); i++)
{
for (unsigned int j = 0; j < contour.size(); j++)
{
if (corners[i].x == contour[j].x && corners[i].y == contour[j].y)
{
indices[i] = j;
break;
}
}
}
vector<cv::Point> *pts = new vector<cv::Point>[corners.size()];
for (unsigned int i = 0; i < corners.size(); i++)
{
int index1, index2;
if (order)
{
index1 = indices[i];
index2 = indices[(i + 1) % corners.size()];
}
else
{
index1 = indices[(i + 1) % corners.size()];
index2 = indices[i];
}
if (index1 < index2)
{
pts[i].resize(index2 - index1);
copy(contour.begin() + index1, contour.begin() + index2, pts[i].begin());
}
else
{
pts[i].resize(index2 + contour.size() - index1);
copy(contour.begin() + index1, contour.end(), pts[i].begin());
copy(contour.begin(), contour.begin() + index2, pts[i].end() - index2);
}
}
cv::Vec4f *lines = new cv::Vec4f[corners.size()];
for (unsigned int i = 0; i < corners.size(); i++)
{
cv::fitLine(pts[i], lines[i], CV_DIST_L2, 0, 0.01, 0.01);
}
vector<cv::Point2f> corners2;
for (unsigned int i = corners.size() - 1; i < 2 * corners.size() - 1; i++)
corners2.push_back(GetIntersection(lines[(i + 1) % corners.size()], lines[i % corners.size()]));
corners = corners2;
}
cv::Point2f MarkerDetector::GetIntersection(cv::Vec4f lin1, cv::Vec4f lin2)
{
float c1 = lin2[2] - lin1[2];
float c2 = lin2[3] - lin1[3];
float a1 = lin1[0];
float a2 = lin1[1];
float b1 = -lin2[0];
float b2 = -lin2[1];
cv::Mat A(2, 2, CV_32F);
cv::Mat b(2, 1, CV_32F);
cv::Mat dst(2, 1, CV_32F);
A.at<float>(0, 0) = a1;
A.at<float>(0, 1) = b1;
A.at<float>(1, 0) = a2;
A.at<float>(1, 1) = b2;
b.at<float>(0, 0) = c1;
b.at<float>(1, 0) = c2;
//rozwi¹zuje uk³ad równañ
cv::solve(A, b, dst);
cv::Point2f res(dst.at<float>(0, 0) * lin1[0] + lin1[2], dst.at<float>(0, 0) * lin1[1] + lin1[3]);
return res;
}
void MarkerDetector::GetMarkerPoints(vector<Point3f> &pts)
{
pts.push_back(Point3f(0.0f, -1.0f, 0.0f));
pts.push_back(Point3f(-1.0f, -1.6667f, 0.0f));
pts.push_back(Point3f(-1.0f, 1.0f, 0.0f));
pts.push_back(Point3f(1.0f, 1.0f, 0.0f));
pts.push_back(Point3f(1.0f, -1.6667f, 0.0f));
}
void MarkerDetector::GetMarkerPointsForWarp(vector<cv::Point2f> &pts)
{
pts.push_back(cv::Point2f(0, 1));
pts.push_back(cv::Point2f(-1, 1.6667f));
pts.push_back(cv::Point2f(-1, -1));
pts.push_back(cv::Point2f(1, -1));
pts.push_back(cv::Point2f(1, 1.6667f));
}
double MarkerDetector::GetMarkerArea(MarkerInfo &marker)
{
cv::Mat hull;
vector<cv::Point2f> cvCorners(nMarkerCorners);
for (int i = 0; i < nMarkerCorners; i++)
{
cvCorners[i] = cv::Point2f(marker.corners[i].X, marker.corners[i].Y);
}
cv::convexHull(cvCorners, hull);
return cv::contourArea(hull);
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
#include "utils.h"
Point3f RotatePoint(Point3f &point, std::vector<std::vector<float>> &R)
{
Point3f res;
res.X = point.X * R[0][0] + point.Y * R[0][1] + point.Z * R[0][2];
res.Y = point.X * R[1][0] + point.Y * R[1][1] + point.Z * R[1][2];
res.Z = point.X * R[2][0] + point.Y * R[2][1] + point.Z * R[2][2];
return res;
}
Point3f InverseRotatePoint(Point3f &point, std::vector<std::vector<float>> &R)
{
Point3f res;
res.X = point.X * R[0][0] + point.Y * R[1][0] + point.Z * R[2][0];
res.Y = point.X * R[0][1] + point.Y * R[1][1] + point.Z * R[2][1];
res.Z = point.X * R[0][2] + point.Y * R[1][2] + point.Z * R[2][2];
return res;
}
+226
View File
@@ -0,0 +1,226 @@
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "SocketCS.h"
#pragma comment(lib, "ws2_32.lib")
#include <iostream>
using namespace std;
int Socket::nofSockets_= 0;
void Socket::Start() {
if (!nofSockets_) {
WSADATA info;
if (WSAStartup(MAKEWORD(2,0), &info)) {
throw "Could not start WSA";
}
}
++nofSockets_;
}
void Socket::End() {
WSACleanup();
}
Socket::Socket() : s_(0) {
Start();
// UDP: use SOCK_DGRAM instead of SOCK_STREAM
s_ = socket(AF_INET,SOCK_STREAM,0);
if (s_ == INVALID_SOCKET) {
throw "INVALID_SOCKET";
}
refCounter_ = new int(1);
}
Socket::Socket(SOCKET s) : s_(s) {
Start();
refCounter_ = new int(1);
};
Socket::~Socket() {
if (! --(*refCounter_)) {
Close();
delete refCounter_;
}
--nofSockets_;
if (!nofSockets_) End();
}
Socket::Socket(const Socket& o) {
refCounter_=o.refCounter_;
(*refCounter_)++;
s_ =o.s_;
nofSockets_++;
}
Socket& Socket::operator=(Socket& o) {
(*o.refCounter_)++;
refCounter_=o.refCounter_;
s_ =o.s_;
nofSockets_++;
return *this;
}
void Socket::Close() {
closesocket(s_);
}
std::string Socket::ReceiveBytes() {
std::string ret;
char buf[1024];
while (1) {
u_long arg = 0;
if (ioctlsocket(s_, FIONREAD, &arg) != 0)
break;
if (arg == 0)
break;
if (arg > 1024) arg = 1024;
int rv = recv (s_, buf, arg, 0);
if (rv <= 0) break;
std::string t;
t.assign (buf, rv);
ret += t;
}
return ret;
}
std::string Socket::ReceiveLine() {
std::string ret;
while (1) {
char r;
switch(recv(s_, &r, 1, 0)) {
case 0: // not connected anymore;
// ... but last line sent
// might not end in \n,
// so return ret anyway.
return ret;
case -1:
return "";
// if (errno == EAGAIN) {
// return ret;
// } else {
// // not connected anymore
// return "";
// }
}
ret += r;
if (r == '\n') return ret;
}
}
void Socket::SendLine(std::string s) {
s += '\n';
send(s_,s.c_str(),s.length(),0);
}
void Socket::SendBytes(const char *buf, int len) {
send(s_,buf,len,0);
}
SocketServer::SocketServer(int port, int connections, TypeSocket type) {
sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = PF_INET;
sa.sin_port = htons(port);
s_ = socket(AF_INET, SOCK_STREAM, 0);
if (s_ == INVALID_SOCKET) {
throw "INVALID_SOCKET";
}
if(type==NonBlockingSocket) {
u_long arg = 1;
ioctlsocket(s_, FIONBIO, &arg);
}
/* bind the socket to the internet address */
if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) {
closesocket(s_);
throw "INVALID_SOCKET";
}
listen(s_, connections);
}
Socket* SocketServer::Accept() {
SOCKET new_sock = accept(s_, 0, 0);
if (new_sock == INVALID_SOCKET) {
int rc = WSAGetLastError();
if(rc==WSAEWOULDBLOCK) {
return 0; // non-blocking call, no request pending
}
else {
throw "Invalid Socket";
}
}
Socket* r = new Socket(new_sock);
return r;
}
SocketClient::SocketClient(const std::string& host, int port) : Socket() {
std::string error;
hostent *he;
if ((he = gethostbyname(host.c_str())) == 0) {
error = strerror(errno);
throw error;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr = *((in_addr *)he->h_addr);
memset(&(addr.sin_zero), 0, 8);
if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) {
error = strerror(WSAGetLastError());
throw error;
}
}
SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) {
FD_ZERO(&fds_);
FD_SET(const_cast<Socket*>(s1)->s_,&fds_);
if(s2) {
FD_SET(const_cast<Socket*>(s2)->s_,&fds_);
}
TIMEVAL tval;
tval.tv_sec = 0;
tval.tv_usec = 1;
TIMEVAL *ptval;
if(type==NonBlockingSocket) {
ptval = &tval;
}
else {
ptval = 0;
}
if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR)
throw "Error in select";
}
bool SocketSelect::Readable(Socket const* const s) {
if (FD_ISSET(s->s_,&fds_)) return true;
return false;
}