$search
00001 #include <boost/thread.hpp> 00002 00003 #include <ros/ros.h> 00004 #include <ros/time.h> 00005 00006 #include "uvc_cam/uvc_cam.h" 00007 #include "sensor_msgs/Image.h" 00008 #include "sensor_msgs/image_encodings.h" 00009 #include "sensor_msgs/CameraInfo.h" 00010 #include "camera_info_manager/camera_info_manager.h" 00011 #include "image_transport/image_transport.h" 00012 00013 #include "uvc_camera/stereocamera.h" 00014 00015 using namespace sensor_msgs; 00016 00017 /* Rotate an 8-bit, 3-channel image by 180 degrees. */ 00018 static inline void rotate(unsigned char *dst_chr, unsigned char *src_chr, int pixels) { 00019 struct pixel_t { 00020 unsigned char r, g, b; 00021 }; 00022 00023 struct pixel_t *src = (pixel_t *) src_chr; 00024 struct pixel_t *dst = &(((pixel_t *) dst_chr)[pixels - 1]); 00025 00026 for (int i = pixels; i != 0; --i) { 00027 *dst = *src; 00028 src++; 00029 dst--; 00030 } 00031 } 00032 00033 namespace uvc_camera { 00034 00035 StereoCamera::StereoCamera(ros::NodeHandle comm_nh, ros::NodeHandle param_nh) : 00036 node(comm_nh), pnode(param_nh), it(comm_nh), 00037 left_info_mgr(ros::NodeHandle(comm_nh, "left"), "left_camera"), 00038 right_info_mgr(ros::NodeHandle(comm_nh, "right"), "right_camera") { 00039 00040 /* default config values */ 00041 width = 640; 00042 height = 480; 00043 fps = 10; 00044 skip_frames = 0; 00045 frames_to_skip = 0; 00046 left_device = "/dev/video0"; 00047 right_device = "/dev/video1"; 00048 frame = "camera"; 00049 rotate_left = false; 00050 rotate_right = false; 00051 00052 /* set up information managers */ 00053 std::string left_url, right_url; 00054 00055 pnode.getParam("left/camera_info_url", left_url); 00056 pnode.getParam("right/camera_info_url", right_url); 00057 00058 left_info_mgr.loadCameraInfo(left_url); 00059 right_info_mgr.loadCameraInfo(right_url); 00060 00061 /* pull other configuration */ 00062 pnode.getParam("left/device", left_device); 00063 pnode.getParam("right/device", right_device); 00064 00065 pnode.getParam("fps", fps); 00066 pnode.getParam("skip_frames", skip_frames); 00067 00068 pnode.getParam("left/rotate", rotate_left); 00069 pnode.getParam("right/rotate", rotate_right); 00070 00071 pnode.getParam("width", width); 00072 pnode.getParam("height", height); 00073 00074 pnode.getParam("frame_id", frame); 00075 00076 /* advertise image streams and info streams */ 00077 left_pub = it.advertise("left/image_raw", 1); 00078 right_pub = it.advertise("right/image_raw", 1); 00079 00080 left_info_pub = node.advertise<CameraInfo>("left/camera_info", 1); 00081 right_info_pub = node.advertise<CameraInfo>("right/camera_info", 1); 00082 00083 /* initialize the cameras */ 00084 cam_left = 00085 new uvc_cam::Cam(left_device.c_str(), uvc_cam::Cam::MODE_RGB, 00086 width, height, fps); 00087 cam_left->set_motion_thresholds(100, -1); 00088 cam_right = 00089 new uvc_cam::Cam(right_device.c_str(), uvc_cam::Cam::MODE_RGB, 00090 width, height, fps); 00091 cam_right->set_motion_thresholds(100, -1); 00092 00093 /* and turn on the streamer */ 00094 ok = true; 00095 image_thread = boost::thread(boost::bind(&StereoCamera::feedImages, this)); 00096 } 00097 00098 void StereoCamera::sendInfo(ros::Time time) { 00099 CameraInfoPtr info_left(new CameraInfo(left_info_mgr.getCameraInfo())); 00100 CameraInfoPtr info_right(new CameraInfo(right_info_mgr.getCameraInfo())); 00101 00102 info_left->header.stamp = time; 00103 info_right->header.stamp = time; 00104 info_left->header.frame_id = frame; 00105 info_right->header.frame_id = frame; 00106 00107 left_info_pub.publish(info_left); 00108 right_info_pub.publish(info_right); 00109 } 00110 00111 00112 void StereoCamera::feedImages() { 00113 unsigned int pair_id = 0; 00114 while (ok) { 00115 unsigned char *frame_left = NULL, *frame_right = NULL; 00116 uint32_t bytes_used_left, bytes_used_right; 00117 00118 ros::Time capture_time = ros::Time::now(); 00119 00120 int left_idx = cam_left->grab(&frame_left, bytes_used_left); 00121 int right_idx = cam_right->grab(&frame_right, bytes_used_right); 00122 00123 /* Read in every frame the camera generates, but only send each 00124 * (skip_frames + 1)th frame. This reduces effective frame 00125 * rate, processing time and network usage while keeping the 00126 * images synchronized within the true framerate. 00127 */ 00128 if (skip_frames == 0 || frames_to_skip == 0) { 00129 if (frame_left && frame_right) { 00130 ImagePtr image_left(new Image); 00131 ImagePtr image_right(new Image); 00132 00133 image_left->height = height; 00134 image_left->width = width; 00135 image_left->step = 3 * width; 00136 image_left->encoding = image_encodings::RGB8; 00137 image_left->header.stamp = capture_time; 00138 image_left->header.seq = pair_id; 00139 00140 image_right->height = height; 00141 image_right->width = width; 00142 image_right->step = 3 * width; 00143 image_right->encoding = image_encodings::RGB8; 00144 image_right->header.stamp = capture_time; 00145 image_right->header.seq = pair_id; 00146 00147 image_left->header.frame_id = frame; 00148 image_right->header.frame_id = frame; 00149 00150 image_left->data.resize(image_left->step * image_left->height); 00151 image_right->data.resize(image_right->step * image_right->height); 00152 00153 if (rotate_left) 00154 rotate(&image_left->data[0], frame_left, width * height); 00155 else 00156 memcpy(&image_left->data[0], frame_left, width * height * 3); 00157 00158 if (rotate_right) 00159 rotate(&image_right->data[0], frame_right, width * height); 00160 else 00161 memcpy(&image_right->data[0], frame_right, width * height * 3); 00162 00163 left_pub.publish(image_left); 00164 right_pub.publish(image_right); 00165 00166 sendInfo(capture_time); 00167 00168 ++pair_id; 00169 } 00170 00171 frames_to_skip = skip_frames; 00172 } else { 00173 frames_to_skip--; 00174 } 00175 00176 if (frame_left) 00177 cam_left->release(left_idx); 00178 if (frame_right) 00179 cam_right->release(right_idx); 00180 } 00181 } 00182 00183 StereoCamera::~StereoCamera() { 00184 ok = false; 00185 image_thread.join(); 00186 if (cam_left) 00187 delete cam_left; 00188 if (cam_right) 00189 delete cam_right; 00190 } 00191 00192 };