I am working on a stereo vision system using ROS in order to read and publish data between some programs using topics.
I know that de actual formula is z = fT/d
and I have all the parameters of my system as:
f: 1660 m/px
T: 0.1395m
Angle between lens: 10º
And then I get a disparity map using OpenCv SGBM algorithm.
Then, using tracking algorithm (specifically Open TLD for ROS), I get a ROI in which I iterate over all pixels getting a disparity average of this region.
The point is, I have been doing tests, and I found that the system is not really accurate.
My last trial has been trying to get a constant that suits in z = k / d
but also, I found that the value is changing every loop.
My main question would be, what am I missing?
I leave you here my code:
/*
* Its implements stereo vision in order to get geometrical position
* of objets in selected in screen in the three axis.
*
* Publisher: /perception/object_position
* Subscriber: /left/tracking
* Subscriber: /left/camera_info
* Subscriber: /right/tracking
* Subscriber: /right/camera_info
*
*/
/**
* @author César Hoyos
*/
// Generic libraries
#include <stdio.h>
#include <string.h>
#include <vector>
#include <math.h>
// Ros libraries
#include "ros/ros.h"
#include "std_msgs/String.h"
#include "std_msgs/Time.h"
#include <image_transport/image_transport.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/PolygonStamped.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/image_encodings.h>
#include <stereo_msgs/DisparityImage.h>
#include <cv_bridge/cv_bridge.h>
// OpenCv libraries
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/calib3d/calib3d.hpp>
/*!
* Defines
*/
#define WIDTH 600
#define HEIGHT 800
#define FOCAL_LENGHT 1660.2266
#define BASE_LINE 0.139586
#define pass (void)0
/*!
* Namespaces used
*/
namespace enc = sensor_msgs::image_encodings;
/*!
* Global variable to set and send object_position
*/
image_transport::Publisher image_pub; //!< Image publisher
cv_bridge::CvImageConstPtr cv_ptr_right; //!< Opencv bridge for right image
cv_bridge::CvImageConstPtr cv_ptr_left; //!< Opencv bridge for left image
cv::Mat image_right;
cv::Mat image_left;
cv::Mat right_for_disp;
cv::Mat left_for_disp;
cv_bridge::CvImageConstPtr disp_pub;
cv::Mat disp, disp8; //!< Disparity image
volatile bool disp_ini = false;
int xl_s, xr_s, xl_e, xr_e, yl_s, yr_s, yl_e, yr_e; //!< Get ROI from both tlds
int x_s, y_s, x_e, y_e; //!< Actual ROI in disparity image
/*!
* @brief When a new image arrays, we recalculate disparities between both and show it.
*/
void disparity_image_SGBM(){
// Initialize disparity algorithm. The data has been chosen with rqt_reconfigure
int SADwindow_size = 3;
int min_disp = -16;
int num_disp = 256;
cv::StereoSGBM ssgbm(
min_disp,
num_disp,//numDisparity / disparity range
SADwindow_size,// sadwindowSize
8 * 3 * SADwindow_size * SADwindow_size, //P1
32 * 3 * SADwindow_size * SADwindow_size, //P2
1,//disp12MaxDiff
16, //Prefiltercap
6, //uniquenessratio
1000,//specklewindowsize
4, //specklerange
false//fulldp
);
uchar * p;
int i,j;
if(!image_left.empty() && !image_right.empty()){
try{
ssgbm(left_for_disp, right_for_disp, disp);
normalize(disp, disp8, 0, 255, CV_MINMAX, CV_8U);
disp_ini = true;
cv::imshow("Disparity", disp8);
cv::waitKey(1);
/*sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "mono8", disp).toImageMsg();
image_pub.publish(msg);
ROS_INFO("Disparity image");*/
//cv::destroyAllWindows();
}catch(cv::Exception& e){
ROS_ERROR("cv exception: [%s]", e.what());
}
}
}
/*!
* @brief When a new image mgs is published in topic /right/image_rect this functions is
* triggered in order to handle this.
*/
void right_handler(const sensor_msgs::ImageConstPtr& msg){
try{
cv_ptr_right = cv_bridge::toCvCopy(msg, "bgr8");
cvtColor(cv_ptr_right->image, image_right, CV_BGR2GRAY);
resize(image_right, right_for_disp, cv::Size(), 0.5, 0.5);
disparity_image_SGBM();
}catch( cv_bridge::Exception& e){
ROS_ERROR("cv_bridge exception: [%s]", e.what());
}
}
/*!
* @brief When a new image mgs is published in topic /left/image_rect this
functions is
* triggered in order to handle this.
*/
void left_handler(const sensor_msgs::ImageConstPtr& msg){
try{
cv_ptr_left = cv_bridge::toCvCopy(msg, "bgr8");
cvtColor(cv_ptr_left->image, image_left, CV_BGR2GRAY);
resize(image_left, left_for_disp, cv::Size(), 0.5, 0.5);
disparity_image_SGBM();
}catch( cv_bridge::Exception& e){
ROS_ERROR("cv_bridge exception: [%s]", e.what());
}
}
void refresh_ROI(){
x_s = floor((xl_s + xr_s)/2);
y_s = floor((yl_s + yr_s)/2);
x_e = ceil((xl_e + xr_e)/2);
y_e = ceil((yl_e + yr_e)/2);
cv::Mat disp_t = disp8.clone();
cv::rectangle(disp_t, cv::Point(x_s, y_s), cv::Point(x_e, y_e), cv::Scalar(255, 255, 255), -1, 8);
cv::imshow("ROI", disp_t);
cv::waitKey(1);
}
void get_ROI_from_polygon_right(const geometry_msgs::PolygonStamped::ConstPtr& msg){
/* Get ROI from topic */
geometry_msgs::Polygon polygon = geometry_msgs::Polygon(msg->polygon);
xr_s = floor(polygon.points[0].x / 2);
yr_s = floor(polygon.points[0].y / 2);
xr_e = ceil(polygon.points[1].x / 2);
yr_e = ceil(polygon.points[1].y / 2);
/* Se dibuja el roi sobre la imagen y se muestra */
if(xr_s != -1 && disp_ini){
refresh_ROI();
}else{
pass;
}
}
void get_ROI_from_polygon_left(const geometry_msgs::PolygonStamped::ConstPtr& msg){
/* Get ROI from topic */
geometry_msgs::Polygon polygon = geometry_msgs::Polygon(msg->polygon);
xl_s = floor(polygon.points[0].x / 2);
yl_s = floor(polygon.points[0].y / 2);
xl_e = ceil(polygon.points[1].x / 2);
yl_e = ceil(polygon.points[1].y / 2);
/* Se dibuja el roi sobre la imagen y se muestra */
if(xl_s != -1 && disp_ini){
refresh_ROI();
}else{
pass;
}
}
int main(int argc, char **argv)
{
//Ros stuff
ros::init(argc, argv, "DepthFromDisparity"); //!< Initialize ros node with name StereoTracker (but then in *.launch its name will be reasigned)
ros::NodeHandle my_node; //!< The get an instance object from NodeHandle. This creates the node
image_transport::ImageTransport it(my_node);
image_pub = it.advertise("probe/image", 1);
image_transport::Subscriber right_ima = it.subscribe( "/right/image_rect", 1, right_handler); //!< Image transport subscriber on topic /right
image_transport::Subscriber left_ima = it.subscribe("/left/image_rect", 1, left_handler); //!< Image transport subscriber on topic /left
ros::Subscriber pose_tld_l = my_node.subscribe("/left/tracking", 1, get_ROI_from_polygon_left);
ros::Subscriber pose_tld_r = my_node.subscribe("/right/tracking", 1, get_ROI_from_polygon_right);
ros::Rate loop_rate(1000000); //!< Set loop rate at 10Hz (msgs each 0.1s)
// Declarations of variables
uchar * p, * q;
int i,j;
float sum = 0;
float disparity = 0;
float depth = 0;
int count = 0;
int errors = 0;
float k = 0;
// Main node loop
while(ros::ok()){
if(disp_ini && x_s != -1){
sum = 0;
depth = 0;
disparity = 0;
count = 0;
errors = 0;
for(i = ((x_s + x_e)/2 - 2); i < ((x_e + x_s)/2 + 2); i++){
p = disp8.ptr<uchar> (i);
q = disp.ptr<uchar> (i);
for(j = y_s; j < y_e; j++){
if(q[j] > 0){
sum += p[j];
disparity += q[j];
count++;
}else{
errors++;
}
}
}
if(disparity){
disparity /= count;
//depth = FOCAL_LENGTH * BASE_LINE / disparity;
depth = 1.30;
k = depth * disparity;
ROS_INFO("Constant: [%f]", k);
}else{
ROS_ERROR("ERROR: No disparity");
}
}else{
ROS_ERROR("ERROR: No tracking");
}
ros::spinOnce(); //!< It is here to proccess callbacks
loop_rate.sleep(); //!< Keeps rate as set before loop
}
return 0;
}
Thanks for your suggestions and help.
Aucun commentaire:
Enregistrer un commentaire