21 ROS_INFO(
"Received a new configuration via dynamic_reconfigure");
45 std::map<std::string, ParameterInfo> ssParams;
50 }
catch(visiontransfer::ParameterException& e) {
51 ROS_ERROR(
"ParameterException while connecting to parameter service: %s", e.what());
56 }
catch(visiontransfer::TransferException& e) {
57 ROS_ERROR(
"TransferException while obtaining parameter enumeration: %s", e.what());
59 }
catch(visiontransfer::ParameterException& e) {
60 ROS_ERROR(
"ParameterException while obtaining parameter enumeration: %s", e.what());
66 dynReconfServer.reset(
new dynamic_reconfigure::Server<nerian_stereo::NerianStereoConfig>());
80 std::string intensityChannel =
"mono8";
81 privateNh.
getParam(
"point_cloud_intensity_channel", intensityChannel);
82 if(intensityChannel ==
"none") {
84 }
else if(intensityChannel ==
"rgb8") {
86 }
else if(intensityChannel ==
"rgb32f") {
145 "/nerian_stereo/disparity_map", 5)));
147 "/nerian_stereo/left_image", 5)));
149 "/nerian_stereo/right_image", 5)));
154 "/nerian_stereo/stereo_camera_info", 1)));
156 "/nerian_stereo/point_cloud", 5)));
162 useTcp ? ImageProtocol::PROTOCOL_TCP : ImageProtocol::PROTOCOL_UDP));
168 if(!
asyncTransfer->collectReceivedImagePair(imagePair, 0.5)) {
177 int secs = 0, microsecs = 0;
178 imagePair.getTimestamp(secs, microsecs);
184 if(imagePair.isImageDisparityPair()) {
218 ROS_WARN(
"No camera calibration file configured. Cannot publish detailed camera information!");
220 bool success =
false;
229 ROS_WARN(
"Error reading calibration file: %s\n" 230 "Cannot publish detailed camera information!",
calibFile.c_str());
244 cvImg.
header.stamp = stamp;
245 cvImg.
header.seq = imagePair.getSequenceNumber();
247 bool format12Bit = (imagePair.getPixelFormat(imageIndex) == ImagePair::FORMAT_12_BIT_MONO);
248 cv::Mat monoImg(imagePair.getHeight(), imagePair.getWidth(),
249 format12Bit ? CV_16UC1 : CV_8UC1,
250 imagePair.getPixelData(imageIndex), imagePair.getRowStride(imageIndex));
251 string encoding =
"";
254 cvImg.
image = monoImg;
255 encoding = (format12Bit ?
"mono16":
"mono8");
258 int dispMin = 0, dispMax = 0;
259 imagePair.getDisparityRange(dispMin, dispMax);
262 colorCodeDispMap ==
"rainbow" ? ColorCoder::COLOR_RAINBOW_BGR : ColorCoder::COLOR_RED_BLUE_BGR,
263 dispMin*16, dispMax*16,
true,
true));
268 colDispMap = cv::Mat_<cv::Vec3b>(monoImg.rows, monoImg.cols);
272 cv::Mat_<cv::Vec3b> dispSection =
colDispMap(cv::Rect(0, 0, monoImg.cols, monoImg.rows));
274 colCoder->codeImage(cv::Mat_<unsigned short>(monoImg), dispSection);
279 sensor_msgs::ImagePtr msg = cvImg.
toImageMsg();
280 msg->encoding = encoding;
285 dst[0] = src[8]; dst[1] = src[9];
286 dst[2] = src[10]; dst[3] = src[11];
288 dst[4] = -src[0]; dst[5] = -src[1];
289 dst[6] = -src[2]; dst[7] = -src[3];
291 dst[8] = -src[4]; dst[9] = -src[5];
292 dst[10] = -src[6]; dst[11] = -src[7];
294 dst[12] = src[12]; dst[13] = src[13];
295 dst[14] = src[14]; dst[15] = src[15];
299 if(imagePair.getPixelFormat(1) != ImagePair::FORMAT_12_BIT_MONO) {
305 static std::vector<float> q;
307 imagePair.setQMatrix(&q[0]);
314 imagePair.setQMatrix(qRos);
318 float* pointMap =
nullptr;
320 pointMap =
recon3d->createPointMap(imagePair, 0);
321 }
catch(std::exception& ex) {
322 cerr <<
"Error creating point cloud: " << ex.what() << endl;
332 if(
pointCloudMsg->data.size() != imagePair.getWidth()*imagePair.getHeight()*4*
sizeof(float)) {
334 pointCloudMsg->data.resize(imagePair.getWidth()*imagePair.getHeight()*4*
sizeof(float));
348 imagePair.getWidth()*imagePair.getHeight()*4*
sizeof(float));
352 copyPointCloudClamped<0>(pointMap,
reinterpret_cast<float*
>(&
pointCloudMsg->data[0]),
353 imagePair.getWidth()*imagePair.getHeight());
355 copyPointCloudClamped<2>(pointMap,
reinterpret_cast<float*
>(&
pointCloudMsg->data[0]),
356 imagePair.getWidth()*imagePair.getHeight());
363 copyPointCloudIntensity<INTENSITY>(imagePair);
366 copyPointCloudIntensity<RGB_COMBINED>(imagePair);
369 copyPointCloudIntensity<RGB_SEPARATE>(imagePair);
382 + imagePair.getWidth()*imagePair.getHeight()*4*
sizeof(float);
384 if(imagePair.getPixelFormat(0) == ImagePair::FORMAT_8_BIT_MONO) {
386 unsigned char* imagePtr = imagePair.getPixelData(0);
387 unsigned char* rowEndPtr = imagePtr + imagePair.getWidth();
388 int rowIncrement = imagePair.getRowStride(0) - imagePair.getWidth();
390 for(
unsigned char* cloudPtr = cloudStart + 3*
sizeof(
float);
391 cloudPtr < cloudEnd; cloudPtr+= 4*
sizeof(float)) {
393 *
reinterpret_cast<float*
>(cloudPtr) = static_cast<float>(*imagePtr) / 255.0F;
395 const unsigned char intensity = *imagePtr;
396 *
reinterpret_cast<unsigned int*
>(cloudPtr) = (intensity << 16) | (intensity << 8) | intensity;
398 *cloudPtr = *imagePtr;
402 if(imagePtr == rowEndPtr) {
404 imagePtr += rowIncrement;
405 rowEndPtr = imagePtr + imagePair.getWidth();
408 }
else if(imagePair.getPixelFormat(0) == ImagePair::FORMAT_12_BIT_MONO) {
410 unsigned short* imagePtr =
reinterpret_cast<unsigned short*
>(imagePair.getPixelData(0));
411 unsigned short* rowEndPtr = imagePtr + imagePair.getWidth();
412 int rowIncrement = imagePair.getRowStride(0) - 2*imagePair.getWidth();
414 for(
unsigned char* cloudPtr = cloudStart + 3*
sizeof(
float);
415 cloudPtr < cloudEnd; cloudPtr+= 4*
sizeof(float)) {
418 *
reinterpret_cast<float*
>(cloudPtr) = static_cast<float>(*imagePtr) / 4095.0F;
420 const unsigned char intensity = *imagePtr/16;
421 *
reinterpret_cast<unsigned int*
>(cloudPtr) = (intensity << 16) | (intensity << 8) | intensity;
423 *cloudPtr = *imagePtr/16;
427 if(imagePtr == rowEndPtr) {
429 imagePtr += rowIncrement;
430 rowEndPtr = imagePtr + imagePair.getWidth();
433 }
else if(imagePair.getPixelFormat(0) == ImagePair::FORMAT_8_BIT_RGB) {
435 unsigned char* imagePtr = imagePair.getPixelData(0);
436 unsigned char* rowEndPtr = imagePtr + imagePair.getWidth();
437 int rowIncrement = imagePair.getRowStride(0) - imagePair.getWidth();
439 static bool warned =
false;
442 ROS_WARN(
"RGBF32 is not supported for color images. Please use RGB8!");
445 for(
unsigned char* cloudPtr = cloudStart + 3*
sizeof(
float);
446 cloudPtr < cloudEnd; cloudPtr+= 4*
sizeof(float)) {
448 *
reinterpret_cast<float*
>(cloudPtr) = static_cast<float>(imagePtr[2]) / 255.0F;
450 *
reinterpret_cast<unsigned int*
>(cloudPtr) = (imagePtr[0] << 16) | (imagePtr[1] << 8) | imagePtr[2];
452 *cloudPtr = (imagePtr[0] + imagePtr[1]*2 + imagePtr[2])/4;
456 if(imagePtr == rowEndPtr) {
458 imagePtr += rowIncrement;
459 rowEndPtr = imagePtr + imagePair.getWidth();
463 throw std::runtime_error(
"Invalid pixel format!");
469 float* endPtr = src + 4*size;
470 for(
float *srcPtr = src, *dstPtr = dst; srcPtr < endPtr; srcPtr+=4, dstPtr+=4) {
472 dstPtr[0] = std::numeric_limits<float>::quiet_NaN();
473 dstPtr[1] = std::numeric_limits<float>::quiet_NaN();
474 dstPtr[2] = std::numeric_limits<float>::quiet_NaN();
476 dstPtr[0] = srcPtr[0];
477 dstPtr[1] = srcPtr[1];
478 dstPtr[2] = srcPtr[2];
487 recon3d.reset(
new Reconstruct3D);
493 sensor_msgs::PointField fieldX;
496 fieldX.datatype = sensor_msgs::PointField::FLOAT32;
500 sensor_msgs::PointField fieldY;
502 fieldY.offset =
sizeof(float);
503 fieldY.datatype = sensor_msgs::PointField::FLOAT32;
507 sensor_msgs::PointField fieldZ;
509 fieldZ.offset = 2*
sizeof(float);
510 fieldZ.datatype = sensor_msgs::PointField::FLOAT32;
515 sensor_msgs::PointField fieldI;
516 fieldI.name =
"intensity";
517 fieldI.offset = 3*
sizeof(float);
518 fieldI.datatype = sensor_msgs::PointField::UINT8;
523 sensor_msgs::PointField fieldRed;
525 fieldRed.offset = 3*
sizeof(float);
526 fieldRed.datatype = sensor_msgs::PointField::FLOAT32;
530 sensor_msgs::PointField fieldGreen;
531 fieldGreen.name =
"g";
532 fieldGreen.offset = 3*
sizeof(float);
533 fieldGreen.datatype = sensor_msgs::PointField::FLOAT32;
534 fieldGreen.count = 1;
537 sensor_msgs::PointField fieldBlue;
539 fieldBlue.offset = 3*
sizeof(float);
540 fieldBlue.datatype = sensor_msgs::PointField::FLOAT32;
544 sensor_msgs::PointField fieldRGB;
545 fieldRGB.name =
"rgb";
546 fieldRGB.offset = 3*
sizeof(float);
547 fieldRGB.datatype = sensor_msgs::PointField::UINT32;
556 camInfoMsg.reset(
new nerian_stereo::StereoCameraInfo);
559 camInfoMsg->header.seq = imagePair.getSequenceNumber();
562 std::vector<int> sizeVec;
564 if(sizeVec.size() != 2) {
565 std::runtime_error(
"Calibration file format error!");
571 camInfoMsg->left_info.distortion_model =
"plumb_bob";
587 camInfoMsg->right_info.distortion_model =
"plumb_bob";
594 camInfoMsg->right_info.roi.do_rectify =
false;
609 const float* qMatrix = imagePair.getQMatrix();
610 if(qMatrix[0] != 0.0) {
611 for(
int i=0; i<16; i++) {
612 camInfoMsg->Q[i] =
static_cast<double>(qMatrix[i]);
627 std::vector<double> doubleVec;
630 if(doubleVec.size() != dest.size()) {
631 std::runtime_error(
"Calibration file format error!");
634 std::copy(doubleVec.begin(), doubleVec.end(), dest.begin());
virtual ros::NodeHandle & getPrivateNH()=0
void prepareAsyncTransfer()
Connects to the image service to request the stream of image pairs.
sensor_msgs::PointCloud2Ptr pointCloudMsg
boost::scoped_ptr< dynamic_reconfigure::Server< nerian_stereo::NerianStereoConfig > > dynReconfServer
boost::scoped_ptr< ColorCoder > colCoder
void publish(const boost::shared_ptr< M > &message) const
virtual ros::NodeHandle & getNH()=0
void loadCameraCalibration()
Loads a camera calibration file if configured.
nerian_stereo::StereoCameraInfoPtr camInfoMsg
bool initialConfigReceived
boost::scoped_ptr< ros::Publisher > rightImagePublisher
void publishCameraInfo(ros::Time stamp, const ImagePair &imagePair)
Publishes the camera info once per second.
void copyPointCloudIntensity(ImagePair &imagePair)
Copies the intensity or RGB data to the point cloud.
void publishPointCloudMsg(ImagePair &imagePair, ros::Time stamp)
Reconstructs the 3D locations form the disparity map and publishes them as point cloud.
void autogen_updateParameterServerFromDevice(std::map< std::string, ParameterInfo > &cfg)
Auto-generated code to set initial parameters according to those obtained from the device...
void autogen_updateDynamicReconfigureFromDevice(std::map< std::string, ParameterInfo > &cfg)
Auto-generated code to override the dynamic_reconfigure limits and defaults for all parameters...
void dynamicReconfigureCallback(nerian_stereo::NerianStereoConfig &config, uint32_t level)
cv::FileStorage calibStorage
cv::Mat_< cv::Vec3b > colDispMap
PointCloudColorMode pointCloudColorMode
boost::scoped_ptr< SceneScanParameters > sceneScanParameters
void initPointCloud()
Performs all neccessary initializations for point cloud+ publishing.
void readCalibrationArray(const char *key, T &dest)
Reads a vector from the calibration file to a boost:array.
boost::scoped_ptr< Reconstruct3D > recon3d
void initDynamicReconfigure()
ros::Time lastCamInfoPublish
boost::scoped_ptr< ros::Publisher > cloudPublisher
boost::scoped_ptr< ros::Publisher > disparityPublisher
void publishImageMsg(const ImagePair &imagePair, int imageIndex, ros::Time stamp, bool allowColorCode, ros::Publisher *publisher)
Publishes the disparity map as 16-bit grayscale image or color coded RGB image.
uint32_t getNumSubscribers() const
bool getParam(const std::string &key, std::string &s) const
A driver node that receives data from SceneScan/SP1 and forwards it to ROS.
boost::scoped_ptr< ros::Publisher > leftImagePublisher
void updateParameterServerFromDevice(std::map< std::string, ParameterInfo > &cfg)
void updateDynamicReconfigureFromDevice(std::map< std::string, ParameterInfo > &cfg)
void copyPointCloudClamped(float *src, float *dst, int size)
Copies all points in a point cloud that have a depth smaller than maxDepth. Other points are set to N...
void processOneImagePair()
std::string colorCodeDispMap
void qMatrixToRosCoords(const float *src, float *dst)
Transform Q matrix to match the ROS coordinate system: Swap y/z axis, then swap x/y axis...
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
sensor_msgs::ImagePtr toImageMsg() const
void init()
Performs general initializations.
void autogen_dynamicReconfigureCallback(nerian_stereo::NerianStereoConfig &config, uint32_t level)
Auto-generated code to check for parameter changes and forward them to the device.
boost::scoped_ptr< ros::Publisher > cameraInfoPublisher
nerian_stereo::NerianStereoConfig lastKnownConfig
boost::scoped_ptr< AsyncTransfer > asyncTransfer