diff --git a/RWR/src/mean-shift/catkin_simple b/RWR/src/mean-shift/catkin_simple new file mode 160000 index 0000000000000000000000000000000000000000..0e62848b12da76c8cc58a1add42b4f894d1ac21e --- /dev/null +++ b/RWR/src/mean-shift/catkin_simple @@ -0,0 +1 @@ +Subproject commit 0e62848b12da76c8cc58a1add42b4f894d1ac21e diff --git a/RWR/src/mean-shift/dvs_meanshift/.vscode/settings.json b/RWR/src/mean-shift/dvs_meanshift/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..c925ebcc2f19d9a7598fae22842622ffddaf96d2 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "C_Cpp.intelliSenseEngineFallback": "Disabled" +} \ No newline at end of file diff --git a/RWR/src/mean-shift/dvs_meanshift/CMakeLists.txt b/RWR/src/mean-shift/dvs_meanshift/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..033e4c8867fd73ff4a11926e83c2d0a553476466 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 2.8.3) +project(dvs_meanshift) + +## Find catkin macros and libraries +## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) +## is used, also find other catkin packages +find_package(catkin REQUIRED COMPONENTS + cv_bridge + dvs_msgs + image_transport + pcl_ros + roscpp + rospy + sensor_msgs + std_msgs +) + +## System dependencies are found with CMake's conventions +find_package(Boost REQUIRED) +find_package(OpenCV REQUIRED) +find_package(PCL 1.7 REQUIRED) + +include_directories(${PCL_INCLUDE_DIRS}) +link_directories(${PCL_LIBRARY_DIRS}) +add_definitions(${PCL_DEFINITIONS}) + +################################### +## catkin specific configuration ## +################################### +## The catkin_package macro generates cmake config files for your package +## Declare things to be passed to dependent projects +## INCLUDE_DIRS: uncomment this if you package contains header files +## LIBRARIES: libraries you create in this project that dependent projects also need +## CATKIN_DEPENDS: catkin_packages dependent projects also need +## DEPENDS: system dependencies of this project that dependent projects also need +catkin_package( + INCLUDE_DIRS include +# LIBRARIES dvs_meanshift + CATKIN_DEPENDS cv_bridge dvs_msgs image_transport pcl_ros roscpp rospy sensor_msgs std_msgs + DEPENDS OpenCV boost +) + +########### +## Build ## +########### + +## Specify additional locations of header files +## Your package locations should be listed before other locations +# include_directories(include) +include_directories( + include + ${catkin_INCLUDE_DIRS} + ${OpenCV_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} +) + +## Add cmake target dependencies of the library +## as an example, code may need to be generated before libraries +## either from message generation or dynamic reconfigure +# add_dependencies(dvs_meanshift ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Declare a C++ executable +# add_executable(dvs_meanshift_node src/dvs_meanshift_node.cpp) + +## Add cmake target dependencies of the executable +## same as for the library above +# add_dependencies(dvs_meanshift_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) + +## Specify libraries to link a library or executable target against +# target_link_libraries(dvs_meanshift_node +# ${catkin_LIBRARIES} +# ) + +add_executable(dvs_meanshift src/meanshift.cpp src/meanshift_node.cpp src/color_meanshift.cpp src/segment.cpp src/image_reconst.cpp) +target_link_libraries(dvs_meanshift ${catkin_LIBRARIES} ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES} ${OpenCV_LIBRARIES}) +add_dependencies(dvs_meanshift ${catkin_EXPORTED_TARGETS} ) diff --git a/RWR/src/mean-shift/dvs_meanshift/README.md b/RWR/src/mean-shift/dvs_meanshift/README.md new file mode 100755 index 0000000000000000000000000000000000000000..38ec2e83c7469b0fa76b7c4c45c429753dc53d04 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/README.md @@ -0,0 +1 @@ +# dvs_meanshift \ No newline at end of file diff --git a/RWR/src/mean-shift/dvs_meanshift/include/dvs_meanshift/color_meanshift.h b/RWR/src/mean-shift/dvs_meanshift/include/dvs_meanshift/color_meanshift.h new file mode 100755 index 0000000000000000000000000000000000000000..bd20d1b0b4edec2b1411e8887c4b0920d30b29ed --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/dvs_meanshift/color_meanshift.h @@ -0,0 +1,18 @@ +/* + * color_meanshift.h + * + * Created on: Nov 2, 2016 + * Author: fran + */ + +#ifndef COLOR_MEANSHIFT_H_ +#define COLOR_MEANSHIFT_H_ + +#include <ros/ros.h> +#include <opencv2/core/core.hpp> + +void colorMeanShiftFilt(double *newPixelsPtr, const double *pixelsPtr, int mPixels, int maxPixelDim, const double *imagePtr, int numRows, int numCols, float spaceDivider, char *kernelFun, int maxIterNum, float tolFun); +//void colorMeanShiftFilt(double *newPixelsPtr, const double *pixelsPtr, int mPixels, int maxPixelDim, const double *imagePtr, int numRows, int numCols, float spaceDivider, char *kernelFun, int maxIterNum, float tolFun, double *newImagePtr); +void meanshiftCluster_Gaussian(cv::Mat dataPts, std::vector<double> *clusterCenterX, std::vector<double> *clusterCenterY, std::vector<double> *clusterCenterZ, std::vector<int> *point2Clusters, double bandwidth); + +#endif /* COLOR_MEANSHIFT_H_ */ diff --git a/RWR/src/mean-shift/dvs_meanshift/include/dvs_meanshift/meanshift.h b/RWR/src/mean-shift/dvs_meanshift/include/dvs_meanshift/meanshift.h new file mode 100755 index 0000000000000000000000000000000000000000..a3f9200de5b647a9071f74515196be1df294c5df --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/dvs_meanshift/meanshift.h @@ -0,0 +1,144 @@ +/* + * dvs_meanshift.h + * + * Created on: Nov 2, 2016 + * Author: fran + */ + +#ifndef MEANSHIFT_H_ +#define MEANSHIFT_H_ + +#include <ros/ros.h> +#include <iostream> +#include <image_transport/image_transport.h> +#include <cv_bridge/cv_bridge.h> +#include <sensor_msgs/CameraInfo.h> +#include <sensor_msgs/Image.h> +#include <sensor_msgs/image_encodings.h> + +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/photo/photo.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <opencv2/video/video.hpp> + +#include <dvs_msgs/Event.h> +#include <dvs_msgs/EventArray.h> +#include "graph3d/segment.h" + +#define TEST 0 +#define KALMAN_FILTERING 1 +#define BG_FILTERING 1 + + +#define DVSW 240 //128 +#define DVSH 180 //128 + +//#define DVSW 240 +//#define DVSH 180 + +namespace dvs_meanshift +{ + +class Meanshift { +public: + Meanshift(ros::NodeHandle & nh, ros::NodeHandle nh_private); + virtual ~Meanshift(); + +private: + ros::NodeHandle nh_; + + void cameraInfoCallback(const sensor_msgs::CameraInfo::ConstPtr& msg); + void eventsCallback(const dvs_msgs::EventArray::ConstPtr& msg); + void eventsCallback_simple(const dvs_msgs::EventArray::ConstPtr& msg); + + //void assignClusterColor(std::vector<int> * positionClusterColor, int numClusters, std::vector<int> matches, std::vector<int> oldPositions); + void assignClusterColor(std::vector<int> * positionClusterColor, int numClusters, std::vector<int> matches, std::vector<int> oldPositions, std::vector<int> activeTrajectories); + //void createKalmanFilter(); + void createKalmanFilter(cv::KalmanFilter *kf, cv::Mat *state, cv::Mat *meas); + + int lastPositionClusterColor; + + cv::Mat camera_matrix_, dist_coeffs_; + + ros::Subscriber event_sub_; + ros::Subscriber camera_info_sub_; + + image_transport::Publisher image_pub_; + image_transport::Publisher image_segmentation_pub_; + + + //DEBUG + image_transport::Publisher image_debug1_pub_; + image_transport::Publisher image_debug2_pub_; + //NOT DEBUG + + + cv::Mat last_image_; + bool used_last_image_; + + enum DisplayMethod + { + GRAYSCALE, RED_BLUE + } display_method_; + + //Meanshift params + //computing image calibration + double *outputFeatures; + int mPixels, maxPixelDim; + double *pixelsPtr; + double *imagePtr; + //double *positionsPtr; + double *initializationPtr; + int numRows, numCols, maxIterNum; + float spaceDivider, timeDivider; + char kernelFun[8]; + float tolFun; + + //Params for graph3d segmentation + static const int MAX_NUM_CLUSTERS = 256; + static const int MAX_NUM_TRAJECTORY_POINTS=16; + std::vector<cv::Vec3b> RGBColors; + std::vector<cv::Point> *allTrajectories; //It is an array of vectors of Points for storing trajectories (a maximum of 8 points should be stored) + std::vector<int> counterTrajectories; //It stores the last position occupied for each trajectory in allTrajectories + + float sigma; + int k; + int min_region; + int num_components; + + //Clusters + std::vector<double> prev_clustCentX, prev_clustCentY, prev_clustCentZ; + std::vector<int> prev_positionClusterColor; + std::vector<int> clustColor; + std::vector<int> prev_activeTrajectories; + + //Trajectories + //cv::Mat trajectories=cv::Mat(DVSH, DVSW, CV_8UC3); + cv::Mat trajectories; + + //Kalman filter parameters + //cv::KalmanFilter kf; + //cv::Mat state; + //cv::Mat meas; + + std::vector<cv::KalmanFilter> vector_of_kf; + std::vector<cv::Mat> vector_of_state; + std::vector<cv::Mat> vector_of_meas; + + //bool foundBlobs; + std::vector<bool> vector_of_foundBlobs; + int notFoundBlobsCount; + std::vector<bool> foundTrajectory; + //bool foundTrajectory; + int selectedTrajectory; + //double ticks; + std::vector<double> vector_of_ticks; + + //frame of times + cv::Mat BGAFframe; +}; + +} // namespace + +#endif // MEANSHIFT_H_ diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/convolve.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/convolve.h new file mode 100755 index 0000000000000000000000000000000000000000..6c2a77339823de1835642bc9df0f8bd0754448c5 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/convolve.h @@ -0,0 +1,69 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* convolution */ + +#ifndef CONVOLVE_H +#define CONVOLVE_H + +#include <vector> +#include <algorithm> +#include <cmath> +#include "graph3d/image.h" + +/* convolve src with mask. dst is flipped! */ +static void convolve_even(image<float> *src, image<float> *dst, + std::vector<float> &mask) { + int width = src->width(); + int height = src->height(); + int len = mask.size(); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + float sum = mask[0] * imRef(src, x, y); + for (int i = 1; i < len; i++) { + sum += mask[i] * + (imRef(src, std::max(x-i,0), y) + + imRef(src, std::min(x+i, width-1), y)); + } + imRef(dst, y, x) = sum; + } + } +} + +/* convolve src with mask. dst is flipped! */ +static void convolve_odd(image<float> *src, image<float> *dst, + std::vector<float> &mask) { + int width = src->width(); + int height = src->height(); + int len = mask.size(); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + float sum = mask[0] * imRef(src, x, y); + for (int i = 1; i < len; i++) { + sum += mask[i] * + (imRef(src, std::max(x-i,0), y) - + imRef(src, std::min(x+i, width-1), y)); + } + imRef(dst, y, x) = sum; + } + } +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/disjoint-set.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/disjoint-set.h new file mode 100755 index 0000000000000000000000000000000000000000..061b68c8a4f382c96c6c0bf5b1fe08ce12c81f5f --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/disjoint-set.h @@ -0,0 +1,79 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DISJOINT_SET +#define DISJOINT_SET + +// disjoint-set forests using union-by-rank and path compression (sort of). + +typedef struct { + int rank; + int p; + int size; +} uni_elt; + +class universe { +public: + universe(int elements); + ~universe(); + int find(int x); + void join(int x, int y); + int size(int x) const { return elts[x].size; } + int num_sets() const { return num; } + +private: + uni_elt *elts; + int num; +}; + +universe::universe(int elements) { + elts = new uni_elt[elements]; + num = elements; + for (int i = 0; i < elements; i++) { + elts[i].rank = 0; + elts[i].size = 1; + elts[i].p = i; + } +} + +universe::~universe() { + delete [] elts; +} + +int universe::find(int x) { + int y = x; + while (y != elts[y].p) + y = elts[y].p; + elts[x].p = y; + return y; +} + +void universe::join(int x, int y) { + if (elts[x].rank > elts[y].rank) { + elts[y].p = x; + elts[x].size += elts[y].size; + } else { + elts[x].p = y; + elts[y].size += elts[x].size; + if (elts[x].rank == elts[y].rank) + elts[y].rank++; + } + num--; +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/filter.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/filter.h new file mode 100755 index 0000000000000000000000000000000000000000..438c5acadb0374b669769b45a282051ab1fc4c79 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/filter.h @@ -0,0 +1,100 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* simple filters */ + +#ifndef FILTER_H +#define FILTER_H + +#include <vector> +#include <cmath> +#include "graph3d/image.h" +#include "graph3d/misc.h" +#include "graph3d/convolve.h" +#include "graph3d/imconv.h" + +#define WIDTH 4.0 + +/* normalize mask so it integrates to one */ +static void normalize(std::vector<float> &mask) { + int len = mask.size(); + float sum = 0; + for (int i = 1; i < len; i++) { + sum += fabs(mask[i]); + } + sum = 2*sum + fabs(mask[0]); + for (int i = 0; i < len; i++) { + mask[i] /= sum; + } +} + +/* make filters */ +#define MAKE_FILTER(name, fun) \ +static std::vector<float> make_ ## name (float sigma) { \ + sigma = std::max(sigma, 0.01F); \ + int len = (int)ceil(sigma * WIDTH) + 1; \ + std::vector<float> mask(len); \ + for (int i = 0; i < len; i++) { \ + mask[i] = fun; \ + } \ + return mask; \ +} + +MAKE_FILTER(fgauss, exp(-0.5*square(i/sigma))); + +/* convolve image with gaussian filter */ +static image<float> *smooth(image<float> *src, float sigma) { + std::vector<float> mask = make_fgauss(sigma); + normalize(mask); + + image<float> *tmp = new image<float>(src->height(), src->width(), false); + image<float> *dst = new image<float>(src->width(), src->height(), false); + convolve_even(src, tmp, mask); + convolve_even(tmp, dst, mask); + + delete tmp; + return dst; +} + +/* convolve image with gaussian filter */ +image<float> *smooth(image<uchar> *src, float sigma) { + image<float> *tmp = imageUCHARtoFLOAT(src); + image<float> *dst = smooth(tmp, sigma); + delete tmp; + return dst; +} + +/* compute laplacian */ +static image<float> *laplacian(image<float> *src) { + int width = src->width(); + int height = src->height(); + image<float> *dst = new image<float>(width, height); + + for (int y = 1; y < height-1; y++) { + for (int x = 1; x < width-1; x++) { + float d2x = imRef(src, x-1, y) + imRef(src, x+1, y) - + 2*imRef(src, x, y); + float d2y = imRef(src, x, y-1) + imRef(src, x, y+1) - + 2*imRef(src, x, y); + imRef(dst, x, y) = d2x + d2y; + } + } + return dst; +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/image.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/image.h new file mode 100755 index 0000000000000000000000000000000000000000..c542465dc10b5029753e2758288b34338015e006 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/image.h @@ -0,0 +1,101 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* a simple image class */ + +#ifndef IMAGE_H +#define IMAGE_H + +#include <cstring> + +template <class T> +class image { + public: + /* create an image */ + image(const int width, const int height, const bool init = true); + + /* delete an image */ + ~image(); + + /* init an image */ + void init(const T &val); + + /* copy an image */ + image<T> *copy() const; + + /* get the width of an image. */ + int width() const { return w; } + + /* get the height of an image. */ + int height() const { return h; } + + /* image data. */ + T *data; + + /* row pointers. */ + T **access; + + private: + int w, h; +}; + +/* use imRef to access image data. */ +#define imRef(im, x, y) (im->access[y][x]) + +/* use imPtr to get pointer to image data. */ +#define imPtr(im, x, y) &(im->access[y][x]) + +template <class T> +image<T>::image(const int width, const int height, const bool init) { + w = width; + h = height; + data = new T[w * h]; // allocate space for image data + access = new T*[h]; // allocate space for row pointers + + // initialize row pointers + for (int i = 0; i < h; i++) + access[i] = data + (i * w); + + if (init) + memset(data, 0, w * h * sizeof(T)); +} + +template <class T> +image<T>::~image() { + delete [] data; + delete [] access; +} + +template <class T> +void image<T>::init(const T &val) { + T *ptr = imPtr(this, 0, 0); + T *end = imPtr(this, w-1, h-1); + while (ptr <= end) + *ptr++ = val; +} + + +template <class T> +image<T> *image<T>::copy() const { + image<T> *im = new image<T>(w, h, false); + memcpy(im->data, data, w * h * sizeof(T)); + return im; +} + +#endif + diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/imconv.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/imconv.h new file mode 100755 index 0000000000000000000000000000000000000000..ba78bcc622bf39c8e04dbb9fabf9a22fb71c8edd --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/imconv.h @@ -0,0 +1,177 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* image conversion */ + +#ifndef CONV_H +#define CONV_H + +#include <climits> +#include "graph3d/image.h" +#include "graph3d/imutil.h" +#include "graph3d/misc.h" + +#define RED_WEIGHT 0.299 +#define GREEN_WEIGHT 0.587 +#define BLUE_WEIGHT 0.114 + +static image<uchar> *imageRGBtoGRAY(image<rgb> *input) { + int width = input->width(); + int height = input->height(); + image<uchar> *output = new image<uchar>(width, height, false); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + imRef(output, x, y) = (uchar) + (imRef(input, x, y).r * RED_WEIGHT + + imRef(input, x, y).g * GREEN_WEIGHT + + imRef(input, x, y).b * BLUE_WEIGHT); + } + } + return output; +} + +static image<rgb> *imageGRAYtoRGB(image<uchar> *input) { + int width = input->width(); + int height = input->height(); + image<rgb> *output = new image<rgb>(width, height, false); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + imRef(output, x, y).r = imRef(input, x, y); + imRef(output, x, y).g = imRef(input, x, y); + imRef(output, x, y).b = imRef(input, x, y); + } + } + return output; +} + +static image<float> *imageUCHARtoFLOAT(image<uchar> *input) { + int width = input->width(); + int height = input->height(); + image<float> *output = new image<float>(width, height, false); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + imRef(output, x, y) = imRef(input, x, y); + } + } + return output; +} + +static image<float> *imageINTtoFLOAT(image<int> *input) { + int width = input->width(); + int height = input->height(); + image<float> *output = new image<float>(width, height, false); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + imRef(output, x, y) = imRef(input, x, y); + } + } + return output; +} + +static image<uchar> *imageFLOATtoUCHAR(image<float> *input, + float min, float max) { + int width = input->width(); + int height = input->height(); + image<uchar> *output = new image<uchar>(width, height, false); + + if (max == min) + return output; + + float scale = UCHAR_MAX / (max - min); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + uchar val = (uchar)((imRef(input, x, y) - min) * scale); + imRef(output, x, y) = bound(val, (uchar)0, (uchar)UCHAR_MAX); + } + } + return output; +} + +static image<uchar> *imageFLOATtoUCHAR(image<float> *input) { + float min, max; + min_max(input, &min, &max); + return imageFLOATtoUCHAR(input, min, max); +} + +static image<long> *imageUCHARtoLONG(image<uchar> *input) { + int width = input->width(); + int height = input->height(); + image<long> *output = new image<long>(width, height, false); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + imRef(output, x, y) = imRef(input, x, y); + } + } + return output; +} + +static image<uchar> *imageLONGtoUCHAR(image<long> *input, long min, long max) { + int width = input->width(); + int height = input->height(); + image<uchar> *output = new image<uchar>(width, height, false); + + if (max == min) + return output; + + float scale = UCHAR_MAX / (float)(max - min); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + uchar val = (uchar)((imRef(input, x, y) - min) * scale); + imRef(output, x, y) = bound(val, (uchar)0, (uchar)UCHAR_MAX); + } + } + return output; +} + +static image<uchar> *imageLONGtoUCHAR(image<long> *input) { + long min, max; + min_max(input, &min, &max); + return imageLONGtoUCHAR(input, min, max); +} + +static image<uchar> *imageSHORTtoUCHAR(image<short> *input, + short min, short max) { + int width = input->width(); + int height = input->height(); + image<uchar> *output = new image<uchar>(width, height, false); + + if (max == min) + return output; + + float scale = UCHAR_MAX / (float)(max - min); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + uchar val = (uchar)((imRef(input, x, y) - min) * scale); + imRef(output, x, y) = bound(val, (uchar)0, (uchar)UCHAR_MAX); + } + } + return output; +} + +static image<uchar> *imageSHORTtoUCHAR(image<short> *input) { + short min, max; + min_max(input, &min, &max); + return imageSHORTtoUCHAR(input, min, max); +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/imutil.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/imutil.h new file mode 100755 index 0000000000000000000000000000000000000000..f59c65d5dc5b9b7a749c44918321a0702c75a523 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/imutil.h @@ -0,0 +1,66 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* some image utilities */ + +#ifndef IMUTIL_H +#define IMUTIL_H + +#include "graph3d/image.h" +#include "graph3d/misc.h" + +/* compute minimum and maximum value in an image */ +template <class T> +void min_max(image<T> *im, T *ret_min, T *ret_max) { + int width = im->width(); + int height = im->height(); + + T min = imRef(im, 0, 0); + T max = imRef(im, 0, 0); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + T val = imRef(im, x, y); + if (min > val) + min = val; + if (max < val) + max = val; + } + } + + *ret_min = min; + *ret_max = max; +} + +/* threshold image */ +template <class T> +image<uchar> *threshold(image<T> *src, int t) { + int width = src->width(); + int height = src->height(); + image<uchar> *dst = new image<uchar>(width, height); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + imRef(dst, x, y) = (imRef(src, x, y) >= t); + } + } + + return dst; +} + +#endif + diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/misc.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/misc.h new file mode 100755 index 0000000000000000000000000000000000000000..4e4a43961ef134a232badaf3c7ca1052b2fbca0e --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/misc.h @@ -0,0 +1,65 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* random stuff */ + +#ifndef MISC_H +#define MISC_H + +#include <cmath> + +#ifndef M_PI +#define M_PI 3.141592653589793 +#endif + +typedef unsigned char uchar; + +typedef struct { uchar r, g, b; } rgb; + +inline bool operator==(const rgb &a, const rgb &b) { + return ((a.r == b.r) && (a.g == b.g) && (a.b == b.b)); +} + +template <class T> +inline T abs(const T &x) { return (x > 0 ? x : -x); }; + +template <class T> +inline int sign(const T &x) { return (x >= 0 ? 1 : -1); }; + +template <class T> +inline T square(const T &x) { return x*x; }; + +template <class T> +inline T bound(const T &x, const T &min, const T &max) { + return (x < min ? min : (x > max ? max : x)); +} + +template <class T> +inline bool check_bound(const T &x, const T&min, const T &max) { + return ((x < min) || (x > max)); +} + +inline int vlib_round(float x) { return (int)(x + 0.5F); } + +inline int vlib_round(double x) { return (int)(x + 0.5); } + +inline double gaussian(double val, double sigma) { + return exp(-square(val/sigma)/2)/(sqrt(2*M_PI)*sigma); +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/pnmfile.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/pnmfile.h new file mode 100755 index 0000000000000000000000000000000000000000..acc98bebd5f11ab19299bb102aa23fc40b3e0cfa --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/pnmfile.h @@ -0,0 +1,211 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* basic image I/O */ + +#ifndef PNM_FILE_H +#define PNM_FILE_H + +#include <cstdlib> +#include <climits> +#include <cstring> +#include <fstream> +#include "graph3d/image.h" +#include "graph3d/misc.h" + +#define BUF_SIZE 256 + +class pnm_error { }; + +static void read_packed(unsigned char *data, int size, std::ifstream &f) { + unsigned char c = 0; + + int bitshift = -1; + for (int pos = 0; pos < size; pos++) { + if (bitshift == -1) { + c = f.get(); + bitshift = 7; + } + data[pos] = (c >> bitshift) & 1; + bitshift--; + } +} + +static void write_packed(unsigned char *data, int size, std::ofstream &f) { + unsigned char c = 0; + + int bitshift = 7; + for (int pos = 0; pos < size; pos++) { + c = c | (data[pos] << bitshift); + bitshift--; + if ((bitshift == -1) || (pos == size-1)) { + f.put(c); + bitshift = 7; + c = 0; + } + } +} + +/* read PNM field, skipping comments */ +static void pnm_read(std::ifstream &file, char *buf) { + char doc[BUF_SIZE]; + char c; + + file >> c; + while (c == '#') { + file.getline(doc, BUF_SIZE); + file >> c; + } + file.putback(c); + + file.width(BUF_SIZE); + file >> buf; + file.ignore(); +} + +static image<uchar> *loadPBM(const char *name) { + char buf[BUF_SIZE]; + + /* read header */ + std::ifstream file(name, std::ios::in | std::ios::binary); + pnm_read(file, buf); + if (strncmp(buf, "P4", 2)) + throw pnm_error(); + + pnm_read(file, buf); + int width = atoi(buf); + pnm_read(file, buf); + int height = atoi(buf); + + /* read data */ + image<uchar> *im = new image<uchar>(width, height); + for (int i = 0; i < height; i++) + read_packed(imPtr(im, 0, i), width, file); + + return im; +} + +static void savePBM(image<uchar> *im, const char *name) { + int width = im->width(); + int height = im->height(); + std::ofstream file(name, std::ios::out | std::ios::binary); + + file << "P4\n" << width << " " << height << "\n"; + for (int i = 0; i < height; i++) + write_packed(imPtr(im, 0, i), width, file); +} + +static image<uchar> *loadPGM(const char *name) { + char buf[BUF_SIZE]; + + /* read header */ + std::ifstream file(name, std::ios::in | std::ios::binary); + pnm_read(file, buf); + if (strncmp(buf, "P5", 2)) + throw pnm_error(); + + pnm_read(file, buf); + int width = atoi(buf); + pnm_read(file, buf); + int height = atoi(buf); + + pnm_read(file, buf); + if (atoi(buf) > UCHAR_MAX) + throw pnm_error(); + + /* read data */ + image<uchar> *im = new image<uchar>(width, height); + file.read((char *)imPtr(im, 0, 0), width * height * sizeof(uchar)); + + return im; +} + +static void savePGM(image<uchar> *im, const char *name) { + int width = im->width(); + int height = im->height(); + std::ofstream file(name, std::ios::out | std::ios::binary); + + file << "P5\n" << width << " " << height << "\n" << UCHAR_MAX << "\n"; + file.write((char *)imPtr(im, 0, 0), width * height * sizeof(uchar)); +} + +static image<rgb> *loadPPM(const char *name) { + char buf[BUF_SIZE], doc[BUF_SIZE]; + + /* read header */ + std::ifstream file(name, std::ios::in | std::ios::binary); + pnm_read(file, buf); + if (strncmp(buf, "P6", 2)) + throw pnm_error(); + + pnm_read(file, buf); + int width = atoi(buf); + pnm_read(file, buf); + int height = atoi(buf); + + pnm_read(file, buf); + if (atoi(buf) > UCHAR_MAX) + throw pnm_error(); + + /* read data */ + image<rgb> *im = new image<rgb>(width, height); + file.read((char *)imPtr(im, 0, 0), width * height * sizeof(rgb)); + + return im; +} + +static void savePPM(image<rgb> *im, const char *name) { + int width = im->width(); + int height = im->height(); + std::ofstream file(name, std::ios::out | std::ios::binary); + + file << "P6\n" << width << " " << height << "\n" << UCHAR_MAX << "\n"; + file.write((char *)imPtr(im, 0, 0), width * height * sizeof(rgb)); +} + +template <class T> +void load_image(image<T> **im, const char *name) { + char buf[BUF_SIZE]; + + /* read header */ + std::ifstream file(name, std::ios::in | std::ios::binary); + pnm_read(file, buf); + if (strncmp(buf, "VLIB", 9)) + throw pnm_error(); + + pnm_read(file, buf); + int width = atoi(buf); + pnm_read(file, buf); + int height = atoi(buf); + + /* read data */ + *im = new image<T>(width, height); + file.read((char *)imPtr((*im), 0, 0), width * height * sizeof(T)); +} + +template <class T> +void save_image(image<T> *im, const char *name) { + int width = im->width(); + int height = im->height(); + std::ofstream file(name, std::ios::out | std::ios::binary); + + //file << "VLIB\n" << width << " " << height << "\n"; + file.write((char *)imPtr(im, 0, 0), width * height * sizeof(T)); +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment-graph.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment-graph.h new file mode 100755 index 0000000000000000000000000000000000000000..ec97b7f59d059fc4ce5750123caa6716bfacf23c --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment-graph.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SEGMENT_GRAPH +#define SEGMENT_GRAPH + +#include <algorithm> +#include <cmath> +#include "graph3d/disjoint-set.h" + +// threshold function +#define THRESHOLD(size, c) (c/size) + +typedef struct { + float w; + int a, b; +} edge; + +bool operator<(const edge &a, const edge &b) { + return a.w < b.w; +} + +/* + * Segment a graph + * + * Returns a disjoint-set forest representing the segmentation. + * + * num_vertices: number of vertices in graph. + * num_edges: number of edges in graph + * edges: array of edges. + * c: constant for treshold function. + */ +universe *segment_graph(int num_vertices, int num_edges, edge *edges, + float c) { + // sort edges by weight + std::sort(edges, edges + num_edges); + + // make a disjoint-set forest + universe *u = new universe(num_vertices); + + // init thresholds + float *threshold = new float[num_vertices]; + for (int i = 0; i < num_vertices; i++) + threshold[i] = THRESHOLD(1,c); + + // for each edge, in non-decreasing weight order... + for (int i = 0; i < num_edges; i++) { + edge *pedge = &edges[i]; + + // components conected by this edge + int a = u->find(pedge->a); + int b = u->find(pedge->b); + if (a != b) { + if ((pedge->w <= threshold[a]) && + (pedge->w <= threshold[b])) { + u->join(a, b); + a = u->find(a); + threshold[a] = pedge->w + THRESHOLD(u->size(a), c); + } + } + } + + // free up + delete threshold; + return u; +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment-image.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment-image.h new file mode 100755 index 0000000000000000000000000000000000000000..6079e799f8194dfcdb27758f8d4a14d6f9bd122f --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment-image.h @@ -0,0 +1,153 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SEGMENT_IMAGE +#define SEGMENT_IMAGE + +#include <cstdlib> +#include "graph3d/image.h" +#include "graph3d/misc.h" +#include "graph3d/filter.h" +#include "graph3d/segment-graph.h" + +// random color +rgb random_rgb(){ + rgb c; + double r; + + c.r = (uchar)random(); + c.g = (uchar)random(); + c.b = (uchar)random(); + + return c; +} + +// dissimilarity measure between pixels +static inline float diff(image<float> *r, image<float> *g, image<float> *b, + int x1, int y1, int x2, int y2) { + return sqrt(square(imRef(r, x1, y1)-imRef(r, x2, y2)) + + square(imRef(g, x1, y1)-imRef(g, x2, y2)) + + square(imRef(b, x1, y1)-imRef(b, x2, y2))); +} + +/* + * Segment an image + * + * Returns a color image representing the segmentation. + * + * im: image to segment. + * sigma: to smooth the image. + * c: constant for treshold function. + * min_size: minimum component size (enforced by post-processing stage). + * num_ccs: number of connected components in the segmentation. + */ +image<rgb> *segment_image(image<rgb> *im, float sigma, float c, int min_size, int *num_ccs) { + int width = im->width(); + int height = im->height(); + + image<float> *r = new image<float>(width, height); + image<float> *g = new image<float>(width, height); + image<float> *b = new image<float>(width, height); + + // smooth each color channel + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + imRef(r, x, y) = imRef(im, x, y).r; + imRef(g, x, y) = imRef(im, x, y).g; + imRef(b, x, y) = imRef(im, x, y).b; + } + } + image<float> *smooth_r = smooth(r, sigma); + image<float> *smooth_g = smooth(g, sigma); + image<float> *smooth_b = smooth(b, sigma); + delete r; + delete g; + delete b; + + // build graph + edge *edges = new edge[width*height*4]; + int num = 0; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + if (x < width-1) { + edges[num].a = y * width + x; + edges[num].b = y * width + (x+1); + edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x+1, y); + num++; + } + + if (y < height-1) { + edges[num].a = y * width + x; + edges[num].b = (y+1) * width + x; + edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x, y+1); + num++; + } + + if ((x < width-1) && (y < height-1)) { + edges[num].a = y * width + x; + edges[num].b = (y+1) * width + (x+1); + edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x+1, y+1); + num++; + } + + if ((x < width-1) && (y > 0)) { + edges[num].a = y * width + x; + edges[num].b = (y-1) * width + (x+1); + edges[num].w = diff(smooth_r, smooth_g, smooth_b, x, y, x+1, y-1); + num++; + } + } + } + delete smooth_r; + delete smooth_g; + delete smooth_b; + + // segment + universe *u = segment_graph(width*height, num, edges, c); + + // post process small components + for (int i = 0; i < num; i++) { + int a = u->find(edges[i].a); + int b = u->find(edges[i].b); + if ((a != b) && ((u->size(a) < min_size) || (u->size(b) < min_size))) + u->join(a, b); + } + delete [] edges; + *num_ccs = u->num_sets(); + + image<rgb> *output = new image<rgb>(width, height); + + // pick random colors for each component + rgb *colors = new rgb[width*height]; + for (int i = 0; i < width*height; i++) + colors[i] = random_rgb(); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int comp = u->find(y * width + x); + imRef(output, x, y) = colors[comp]; + } + } + + delete [] colors; + delete u; + + return output; +} + +#endif diff --git a/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment.h b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment.h new file mode 100755 index 0000000000000000000000000000000000000000..3696ec7e5f4c688630a7c65438ac2d71c5bf48fe --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/graph3d/segment.h @@ -0,0 +1,19 @@ +/* + * segment.h + * + * Created on: Nov 3, 2016 + * Author: fran + */ + +#ifndef SEGMENT_H_ +#define SEGMENT_H_ + +#include <cv_bridge/cv_bridge.h> +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> + + +void imadjust(const cv::Mat & src, cv::Mat & dst); +void im2segment(cv::Mat input, cv::Mat cv_image_output, float sigma, float k, int min_size, int *num_ccs); + +#endif /* SEGMENT_H_ */ diff --git a/RWR/src/mean-shift/dvs_meanshift/include/image_reconstruct/image_reconst.h b/RWR/src/mean-shift/dvs_meanshift/include/image_reconstruct/image_reconst.h new file mode 100755 index 0000000000000000000000000000000000000000..21877cd7ae229ba2f479c248202af9801847a469 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/include/image_reconstruct/image_reconst.h @@ -0,0 +1,41 @@ +/* + * image_reconst.h + * + * Created on: Nov 3, 2016 + * Author: fran + */ + +#ifndef IMAGE_RECONST_H_ +#define IMAGE_RECONST_H_ + +//#include <opencv2/opencv.hpp> +//#include "opencv/cxcore.h" +//#include "opencv/highgui.h" +//#include "opencv2/core/core.hpp" +//#include <opencv2/highgui/highgui.hpp> +//#include <opencv2/highgui/highgui_c.h> +//#include <opencv2/core/core.hpp> +//#include <opencv2/imgproc/imgproc.hpp> +#include "opencv2/core/core_c.h" +#include "opencv2/videoio/legacy/constants_c.h" +#include "opencv2/highgui/highgui_c.h" + + +void dst(double *btest, double *bfinal, int h, int w); +void idst(double *btest, double *bfinal, int h, int w); +void transpose(double *mat, double *mat_t, int h, int w); + +void getGradientX(cv::Mat &img, cv::Mat &gx); +void getGradientY(cv::Mat &img, cv::Mat &gy); +void lapx(cv::Mat &gx, cv::Mat &gxx); +void lapy(cv::Mat &gy, cv::Mat &gyy); + +void poisson_solver(cv::Mat &img, cv::Mat &gxx, cv::Mat &gyy, cv::Mat &result); +void poisson_solver_jacobi(cv::Mat &img, cv::Mat &gxx, cv::Mat &gyy, cv::Mat &result); + + +//IPL Image versions (legacy) +void lapx( const IplImage *img, IplImage *gxx); +void lapy( const IplImage *img, IplImage *gyy); +void poisson_solver(const IplImage *img, IplImage *gxx , IplImage *gyy, cv::Mat &result); +#endif /* IMAGE_RECONST_H_ */ diff --git a/RWR/src/mean-shift/dvs_meanshift/launch/dvs_mono.launch b/RWR/src/mean-shift/dvs_meanshift/launch/dvs_mono.launch new file mode 100755 index 0000000000000000000000000000000000000000..07ee3e77b014e886dc38e111e162bb0223923097 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/launch/dvs_mono.launch @@ -0,0 +1,39 @@ +<launch> + <!-- camera driver --> + <node name="dvs_ros_driver" pkg="dvs_ros_driver" type="dvs_ros_driver" output = "screen"> + <rosparam command="load" file="$(find dvs_ros_driver)/config/fast.yaml" /> + </node> + + <!-- visualization --> + <node name="dvs_meanshift" pkg="dvs_meanshift" type="dvs_meanshift" output = "screen"> + <!-- <param name="display_method" value="grayscale"/> --> + <param name="display_method" value="red-blue"/> + <remap from="events" to="/dvs/events" /> + <remap from="camera_info" to="/dvs/camera_info" /> + </node> + + <!-- display --> + <node name="image_view" pkg="image_view" type="image_view" output = "screen"> + <remap from="image" to="dvs_rendering"/> + </node> + + <node name="image_view2" pkg="image_view" type="image_view" output = "screen"> + <remap from="image" to="dvs_segmentation"/> + </node> + + <node name="image_view3" pkg="image_view" type="image_view" output = "screen"> + <remap from="image" to="dvs_debug1"/> + </node> + + <node name="image_view4" pkg="image_view" type="image_view" output = "screen"> + <remap from="image" to="dvs_debug2"/> + </node> + + <!-- <node name="image_view2" pkg="image_view" type="image_view" output = "screen"> --> + <!-- <remap from="image" to="dvs_undistorted"/> --> + <!-- </node> --> + + <!-- configure --> + <!-- <node name="rqt_reconfigure" pkg="rqt_reconfigure" type="rqt_reconfigure" /> --> + +</launch> diff --git a/RWR/src/mean-shift/dvs_meanshift/launch/dvs_segmentation.launch b/RWR/src/mean-shift/dvs_meanshift/launch/dvs_segmentation.launch new file mode 100755 index 0000000000000000000000000000000000000000..8e1718f5e0a0f3fd2923a98319808bc320ee6c72 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/launch/dvs_segmentation.launch @@ -0,0 +1,31 @@ +<launch> + <!-- camera driver --> + <node name="dvs_ros_driver" pkg="dvs_ros_driver" type="dvs_ros_driver" output = "screen"> + <rosparam command="load" file="$(find dvs_ros_driver)/config/fast.yaml" /> + </node> + + <!-- visualization --> + <node name="dvs_meanshift" pkg="dvs_meanshift" type="dvs_meanshift" output = "screen"> + <!-- <param name="display_method" value="grayscale"/> --> + <param name="display_method" value="red-blue"/> + <remap from="events" to="/dvs/events" /> + <remap from="camera_info" to="/dvs/camera_info" /> + </node> + + <!-- display --> + <node name="image_view" pkg="image_view" type="image_view" output = "screen"> + <remap from="image" to="dvs_rendering"/> + </node> + + <node name="image_view2" pkg="rqt_image_view" type="rqt_image_view" output = "screen"> + <remap from="image" to="dvs_segmentation"/> + </node> + + <!-- <node name="image_view3" pkg="image_view" type="image_view" output = "screen"> --> + <!-- <remap from="image" to="dvs_debug1"/> --> + <!-- </node> --> + + <!-- configure --> + <!-- <node name="rqt_reconfigure" pkg="rqt_reconfigure" type="rqt_reconfigure" /> --> + +</launch> diff --git a/RWR/src/mean-shift/dvs_meanshift/package.xml b/RWR/src/mean-shift/dvs_meanshift/package.xml new file mode 100755 index 0000000000000000000000000000000000000000..05e2835bf6f75312d4d6c7d91b5ae1dba83d411f --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/package.xml @@ -0,0 +1,66 @@ +<?xml version="1.0"?> +<package> + <name>dvs_meanshift</name> + <version>0.0.0</version> + <description>The dvs_meanshift package</description> + + <!-- One maintainer tag required, multiple allowed, one person per tag --> + <!-- Example: --> + <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> --> + <maintainer email="fran@todo.todo">fran</maintainer> + + + <!-- One license tag required, multiple allowed, one license per tag --> + <!-- Commonly used license strings: --> + <!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 --> + <license>TODO</license> + + + <!-- Url tags are optional, but mutiple are allowed, one per tag --> + <!-- Optional attribute type can be: website, bugtracker, or repository --> + <!-- Example: --> + <!-- <url type="website">http://wiki.ros.org/dvs_meanshift</url> --> + + + <!-- Author tags are optional, mutiple are allowed, one per tag --> + <!-- Authors do not have to be maintianers, but could be --> + <!-- Example: --> + <!-- <author email="jane.doe@example.com">Jane Doe</author> --> + + + <!-- The *_depend tags are used to specify dependencies --> + <!-- Dependencies can be catkin packages or system dependencies --> + <!-- Examples: --> + <!-- Use build_depend for packages you need at compile time: --> + <!-- <build_depend>message_generation</build_depend> --> + <!-- Use buildtool_depend for build tool packages: --> + <!-- <buildtool_depend>catkin</buildtool_depend> --> + <!-- Use run_depend for packages you need at runtime: --> + <!-- <run_depend>message_runtime</run_depend> --> + <!-- Use test_depend for packages you need only for testing: --> + <!-- <test_depend>gtest</test_depend> --> + <buildtool_depend>catkin</buildtool_depend> + <build_depend>cv_bridge</build_depend> + <build_depend>dvs_msgs</build_depend> + <build_depend>image_transport</build_depend> + <build_depend>pcl_ros</build_depend> + <build_depend>roscpp</build_depend> + <build_depend>rospy</build_depend> + <build_depend>sensor_msgs</build_depend> + <build_depend>std_msgs</build_depend> + <run_depend>cv_bridge</run_depend> + <run_depend>dvs_msgs</run_depend> + <run_depend>image_transport</run_depend> + <run_depend>pcl_ros</run_depend> + <run_depend>roscpp</run_depend> + <run_depend>rospy</run_depend> + <run_depend>sensor_msgs</run_depend> + <run_depend>std_msgs</run_depend> + + + <!-- The export tag contains other, unspecified, tags --> + <export> + <!-- Other tools can request additional information be placed here --> + + </export> +</package> \ No newline at end of file diff --git a/RWR/src/mean-shift/dvs_meanshift/src/COPYING b/RWR/src/mean-shift/dvs_meanshift/src/COPYING new file mode 100755 index 0000000000000000000000000000000000000000..d511905c1647a1e311e8b20d5930a37a9c2531cd --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/src/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/RWR/src/mean-shift/dvs_meanshift/src/README b/RWR/src/mean-shift/dvs_meanshift/src/README new file mode 100755 index 0000000000000000000000000000000000000000..f8e9166aaa4f44a48c9e7f907db28909edfc6890 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/src/README @@ -0,0 +1,25 @@ + +Implementation of the segmentation algorithm described in: + +Efficient Graph-Based Image Segmentation +Pedro F. Felzenszwalb and Daniel P. Huttenlocher +International Journal of Computer Vision, 59(2) September 2004. + +The program takes a color image (PPM format) and produces a segmentation +with a random color assigned to each region. + +1) Type "make" to compile "segment". + +2) Run "segment sigma k min input output". + +The parameters are: (see the paper for details) + +sigma: Used to smooth the input image before segmenting it. +k: Value for the threshold function. +min: Minimum component size enforced by post-processing. +input: Input image. +output: Output image. + +Typical parameters are sigma = 0.5, k = 500, min = 20. +Larger values for k result in larger components in the result. + diff --git a/RWR/src/mean-shift/dvs_meanshift/src/color_meanshift.cpp b/RWR/src/mean-shift/dvs_meanshift/src/color_meanshift.cpp new file mode 100755 index 0000000000000000000000000000000000000000..f1c8d2c021ec0a1f9ad62c933c3d28579b26d853 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/src/color_meanshift.cpp @@ -0,0 +1,739 @@ +#include <cstring> +#include <cmath> +#include <cstdlib> +#include "dvs_meanshift/color_meanshift.h" + +#define max(x,y) ((x)>(y)?(x):(y)) +#define min(x,y) ((x)<(y)?(x):(y)) + +#define _2D_to_linear(row, col, maxCol) ((row)*(maxCol)+(col)) +//#define _3D_to_linear(row, col, color, maxRow, maxCol) ((maxRow)*(maxCol)*(color)+(row)*(maxCol)+(col)) + +//#define _2D_to_linear(row, col, maxRow) ((col)*(maxRow)+(row)) +//#define _3D_to_linear(row, col, color, maxRow, maxCol) ((maxRow)*(maxCol)*(color)+(col)*(maxRow)+(row)) +//void colorMeanShiftFilt_helper_C(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) + +/*void colorMeanShiftFilt(double *newPixelsPtr, const double *pixelsPtr, int mPixels, int maxPixelDim, const double *imagePtr, int numRows, int numCols, float spaceDivider, char *kernelFun, int maxIterNum, float tolFun, double *newImagePtr) +{ + // Copy the original pixel values to the new pixel matrix + memcpy(newPixelsPtr, pixelsPtr, maxPixelDim*mPixels*sizeof(double)); + + // Copy the original image to a new image + memcpy(newImagePtr, imagePtr, mPixels*sizeof(double)); + + // Help variables + double x,y; + int rX, rY; + int neighX, neighY; + bool bRepeat=false; + + double *delta = (double *) calloc(maxPixelDim,sizeof(double)); + double *dX = (double *) calloc(maxPixelDim,sizeof(double)); + double *neighVec = (double *) calloc(maxPixelDim,sizeof(double)); + double deltaGrad2; + + // Create an array that indicates if we reached the end of the optimization for each pixel + double *optimizedPointArray=new double[mPixels]; + + for (int iterNum=0; iterNum<maxIterNum; iterNum++) + { + bRepeat=false; + + for (int pointNum=0; pointNum<mPixels; pointNum++) + { + if (optimizedPointArray[pointNum]==1) // The optimization for this pixel has reached the threshold + continue; + + x=newPixelsPtr[_2D_to_linear(0, pointNum, maxPixelDim)]*spaceDivider; + y=newPixelsPtr[_2D_to_linear(1, pointNum, maxPixelDim)]*spaceDivider; + + // Reset the delta variables + delta[0]=0; delta[1]=0; delta[2]=0; + dX[0]=0; dX[1]=0; dX[2]=0; + + //ROS_ERROR("y = %d, x = %d, pointNum = %d, spaceDivider = %g", (int)floor(y), (int)floor(x), pointNum, spaceDivider); + + double sumF=0; + double dist2; + + + // Find the neighbors around point (rX,rY) + //for (neighX=max(0, floor(x)-1-spaceDivider); neighX<min(numCols, ceil(x)+spaceDivider); neighX++) + for (neighX=max(0, floor(x)-spaceDivider); neighX<min(numCols, ceil(x)+spaceDivider); neighX++) + { + //for (neighY=max(0,floor(y)-1-spaceDivider); neighY<min(numRows, ceil(y)+spaceDivider); neighY++) + for (neighY=max(0,floor(y)-spaceDivider); neighY<min(numRows, ceil(y)+spaceDivider); neighY++) + { + neighVec[0]=(neighX)/spaceDivider; + neighVec[1]=(neighY)/spaceDivider; + neighVec[2]=newImagePtr[neighY*numCols+neighX]; + + + delta[0]=newPixelsPtr[_2D_to_linear(0,pointNum,maxPixelDim)]-neighVec[0]; + delta[1]=newPixelsPtr[_2D_to_linear(1,pointNum,maxPixelDim)]-neighVec[1]; + delta[2]=newPixelsPtr[_2D_to_linear(2,pointNum,maxPixelDim)]-neighVec[2]; + + dist2 = delta[0]*delta[0] + delta[1]*delta[1] + delta[2]*delta[2]; + + double kres=(exp(-dist2/2.0)); + + dX[0] += kres*neighVec[0]; + dX[1] += kres*neighVec[1]; + dX[2] += kres*neighVec[2]; + + sumF+=kres; + + //ROS_ERROR("newImagePtr[%d, %d]= %g", (int)(neighX), (int)(neighY), neighVec[2]); + } + } + + deltaGrad2=0; + + + dX[0]=(sumF==0)?0:dX[0]/sumF; //check for NaNs + dX[1]=(sumF==0)?0:dX[1]/sumF; //check for NaNs + dX[2]=(sumF==0)?0:dX[2]/sumF; //check for NaNs + + double tmp0=newPixelsPtr[_2D_to_linear(0, pointNum, maxPixelDim)]-dX[0]; + double tmp1=newPixelsPtr[_2D_to_linear(1, pointNum, maxPixelDim)]-dX[1]; + double tmp2=newPixelsPtr[_2D_to_linear(2, pointNum, maxPixelDim)]-dX[2]; + + //double tmp1=newPixelsPtr[_2D_to_linear(i, pointNum, mPixels)]-dX[i]; + deltaGrad2 = tmp0*tmp0 + tmp1*tmp1 + tmp2*tmp2; + newPixelsPtr[_2D_to_linear(0, pointNum, maxPixelDim)]=dX[0]; + newPixelsPtr[_2D_to_linear(1, pointNum, maxPixelDim)]=dX[1]; + newPixelsPtr[_2D_to_linear(2, pointNum, maxPixelDim)]=dX[2]; + + //ROS_ERROR("newImagePtr[%d, %d]= %g", (int)pointNum/numCols, (int)pointNum%numCols, dX[0]); + + // Find the corresponding row and column of the point + newImagePtr[pointNum]=dX[2]; + + //ROS_ERROR("newImagePtr[%d, %d] = %g", pointCol, pointRow, dX[0]); + + if (deltaGrad2<tolFun) + optimizedPointArray[pointNum]=1; + else + bRepeat=true; + + } // end pointNum loop + + if (bRepeat==false) + break; + + } // end for(iterNum) loop + + // CLEAN-UP + //delete[] newImagePtr; + delete[] optimizedPointArray; + delete(delta); + delete(dX); + delete(neighVec); +}*/ + +/*void colorMeanShiftFilt(double *newPixelsPtr, const double *pixelsPtr, int mPixels, int maxPixelDim, const double *imagePtr, int numRows, int numCols, float spaceDivider, char *kernelFun, int maxIterNum, float tolFun) +{ + // Copy the original pixel values to the new pixel matrix + memcpy(newPixelsPtr, pixelsPtr, maxPixelDim*mPixels*sizeof(double)); + + // Copy the original image to a new image + double *newImagePtr=new double[mPixels]; + memcpy(newImagePtr, imagePtr, mPixels*sizeof(double)); + + // Help variables + double x,y; + int neighX, neighY; + bool bRepeat=false; + + double *delta = (double *) calloc(maxPixelDim,sizeof(double)); + double *dX = (double *) calloc(maxPixelDim,sizeof(double)); + double *neighVec = (double *) calloc(maxPixelDim,sizeof(double)); + double deltaGrad2; + + // Create an array that indicates if we reached the end of the optimization for each pixel + double *optimizedPointArray=new double[mPixels]; + + for (int iterNum=0; iterNum<maxIterNum; iterNum++) + { + bRepeat=false; + for (int pointNum=0; pointNum<mPixels; pointNum++) + { + if (optimizedPointArray[pointNum]==1) // The optimization for this pixel has reached the threshold + continue; + + x=newPixelsPtr[_2D_to_linear(0, pointNum, mPixels)]*spaceDivider; + y=newPixelsPtr[_2D_to_linear(1, pointNum, mPixels)]*spaceDivider; + + delta[0]=0; delta[1]=0; delta[2]=0; + dX[0]=0; dX[1]=0; dX[2]=0; + + //ROS_ERROR("y = %d, x = %d, pointNum = %d, spaceDivider = %g", (int)floor(y), (int)floor(x), pointNum, spaceDivider); + + double sumF=0; + double dist2, kres; + + // Find the neighbors around point (rX,rY) + for (neighX=max(0, floor(x)-1-spaceDivider); neighX<min(numCols, ceil(x)+spaceDivider); neighX++) + { + for (neighY=max(0,floor(y)-1-spaceDivider); neighY<min(numRows, ceil(y)+spaceDivider); neighY++) + { + neighVec[0]=(neighX+1)/spaceDivider; + neighVec[1]=(neighY+1)/spaceDivider; + neighVec[2]=newImagePtr[neighY*numCols+neighX]; + + delta[0]=newPixelsPtr[_2D_to_linear(0,pointNum,mPixels)]-neighVec[0]; + delta[1]=newPixelsPtr[_2D_to_linear(1,pointNum,mPixels)]-neighVec[1]; + delta[2]=newPixelsPtr[_2D_to_linear(2,pointNum,mPixels)]-neighVec[2]; + + dist2 = delta[0]*delta[0]+delta[1]*delta[1]+delta[2]*delta[2]; + + kres =(exp(-dist2/2.0)); + + dX[0]+= kres*neighVec[0]; + dX[1]+= kres*neighVec[1]; + dX[2]+= kres*neighVec[2]; + sumF +=kres; + } + } + + // Find the corresponding row and column of the point + int pointRow = pointNum/numCols; + int pointCol = pointNum%numCols; + + dX[0]=(sumF==0)?0:dX[0]/sumF; //check for NaNs + dX[1]=(sumF==0)?0:dX[1]/sumF; //check for NaNs + dX[2]=(sumF==0)?0:dX[2]/sumF; //check for NaNs + //double tmp1=newPixelsPtr[_2D_to_linear(i, pointNum, maxPixelDim)]-dX[i]; + double tmp1=newPixelsPtr[_2D_to_linear(0, pointNum, mPixels)]-dX[0]; + double tmp2=newPixelsPtr[_2D_to_linear(1, pointNum, mPixels)]-dX[1]; + double tmp3=newPixelsPtr[_2D_to_linear(2, pointNum, mPixels)]-dX[2]; + + deltaGrad2=tmp1*tmp1+tmp2*tmp2+tmp3*tmp3; + newPixelsPtr[_2D_to_linear(0, pointNum, mPixels)]=dX[0]; + newPixelsPtr[_2D_to_linear(1, pointNum, mPixels)]=dX[1]; + newPixelsPtr[_2D_to_linear(2, pointNum, mPixels)]=dX[2]; + //newImagePtr[pointRow*numCols+pointCol]=dX[2]; + newImagePtr[pointNum]=dX[2]; + + if (deltaGrad2<tolFun) + optimizedPointArray[pointNum]=1; + else + bRepeat=true; + + } // end pointNum loop + + if (bRepeat==false) + break; + + } // end for(iterNum) loop + + + // CLEAN-UP + delete[] newImagePtr; + delete[] optimizedPointArray; + delete(delta); + delete(dX); + delete(neighVec); +}*/ + +/*void meanshiftCluster_Gaussian(cv::Mat dataPts, std::vector<double> *clusterCenterX, std::vector<double> *clusterCenterY, std::vector<double> *clusterCenterZ, std::vector<int> *point2Clusters, double bandwidth) +{ + //Initialization + int numPts = dataPts.cols; + int numDim = dataPts.rows; + int numClust = 0; + double bandSq = bandwidth*bandwidth; + cv::Range rng = cv::Range(1,numPts); + + cv::Mat onesAux = cv::Mat::ones(1, dataPts.cols, dataPts.type()); + + std::vector<int> initPtInds; + for (int i = rng.start; i <= rng.end; i++) initPtInds.push_back(i); + double stopThresh = 1E-3*bandwidth; //when mean has converged + int numInitPts = numPts; //track if a points been seen already + cv::Mat beenVisitedFlag = cv::Mat(1, numPts, CV_32S, cv::Scalar::all(0)); //number of points to posibaly use as initilization points + cv::Mat clusterVotes; //used to resolve conflicts on cluster membership + + double lambda = 10.; + double myMeanX, myMeanY, myMeanZ, myOldMeanX, myOldMeanY, myOldMeanZ, totalWeightX, totalWeightY, totalWeightZ; + int stInd; + + //std::vector<double> clusterCenterX, clusterCenterY, clusterCenterZ; + + int tempInd; + + while (numInitPts>0) + { + tempInd = (rand()%numInitPts); //pick a random seed point + stInd = initPtInds[tempInd]; //use this point as start of mean + myMeanX = dataPts.at<double>(cv::Point(stInd, 0)); //intilize mean to this points location + myMeanY = dataPts.at<double>(cv::Point(stInd, 1)); + myMeanZ = dataPts.at<double>(cv::Point(stInd, 2)); + cv::Mat thisClusterVotes = cv::Mat(1, numPts, CV_32S, cv::Scalar::all(0)); //used to resolve conflicts on cluster membership + //ROS_ERROR_STREAM("Before getting into while myMean = ["<<myMeanX<<", "<<myMeanY<<", "<<myMeanZ<<"]"); + cv::Mat_<double> myMean = ( cv::Mat_<double>(3, 1) << myMeanX, myMeanY, myMeanZ); + + + + while(true) + { + cv::Mat dataX, dataY, dataZ; + dataX.push_back(dataPts.row(0)); + dataY.push_back(dataPts.row(1)); + dataZ.push_back(dataPts.row(2)); + + cv::Mat diffX = dataX - myMeanX; + cv::Mat diffY = dataY - myMeanY; + cv::Mat diffZ = dataZ - myMeanZ; + + ROS_ERROR_STREAM("Original = "<<diffX); + ROS_ERROR_STREAM("onesAux.rows = "<<onesAux.rows<<" cols = "<<onesAux.cols); + ROS_ERROR_STREAM("dataPts.rows = "<<dataPts.rows<<" cols = "<<dataPts.cols); + ROS_ERROR_STREAM("myMean.rows = "<<myMean.rows<<" cols = "<<myMean.cols); + + cv::Mat diff = dataPts - myMean*onesAux; + diffX.push_back(diff.row(0)); + diffY.push_back(diff.row(1)); + diffZ.push_back(diff.row(2)); + + ROS_ERROR_STREAM("Matricial "<<diff.row(0)); + exit(0); + + cv::Mat diffXX = diffX.mul(diffX); + cv::Mat diffYY = diffY.mul(diffY); + cv::Mat diffZZ = diffZ.mul(diffZ); + + cv::Mat sqDistToAll = diffXX + diffYY + diffZZ; //dist squared from mean to all points still active + cv::Mat inInds = (sqDistToAll < bandSq); // Puts 255 wherever it is true + //ROS_ERROR_STREAM("This is the size "<<inInds.size()); + //ROS_ERROR_STREAM("This is the size "<<thisClusterVotes.size()); + //inInds.convertTo(inInds, CV_8UC1); + //cv::add(thisClusterVotes, cv::Mat::ones(1, numPts, CV_32S), thisClusterVotes, inInds); //add a vote for all the in points belonging to this cluster + cv::add(thisClusterVotes, cv::Scalar(1), thisClusterVotes, inInds); //add a vote for all the in points belonging to this cluster + //ROS_ERROR_STREAM("thisclusterVotes = "<<inInds); + //ROS_ERROR_STREAM("thisclusterVotes = "<<thisClusterVotes); + //ROS_ERROR_STREAM("thisclusterVotes = "<<sqDistToAll); + //exit(0); + + cv::Mat selectedDataX, selectedDataY, selectedDataZ; + //cv::bitwise_and(dataX, cv::Scalar(255), selectedDataX, inInds); + //cv::bitwise_and(dataY, cv::Scalar(255), selectedDataY, inInds); + //cv::bitwise_and(dataZ, cv::Scalar(255), selectedDataZ, inInds); + //ROS_ERROR_STREAM("Before: dataX ="<<dataX); + dataX.setTo(0., inInds==0); + dataY.setTo(0., inInds==0); + dataZ.setTo(0., inInds==0); + //ROS_ERROR_STREAM("inInds ="<<inInds); + //ROS_ERROR_STREAM("After: dataX ="<<dataX); + + double numOfOnes = (double) (cv::sum(inInds)[0])/255; //inInds is active if inInds[i]==255 + //ROS_ERROR_STREAM("Num of Ones ="<<numOfOnes); + //ROS_ERROR_STREAM("inInds ="<<inInds); + //exit(0); + myOldMeanX = myMeanX; myOldMeanY = myMeanY; myOldMeanZ = myMeanZ; + myMeanX = cv::sum(dataX)[0]/numOfOnes; + myMeanY = cv::sum(dataY)[0]/numOfOnes; + myMeanZ = cv::sum(dataZ)[0]/numOfOnes; + + + //ROS_ERROR_STREAM("inInds="<<inInds); + //ROS_ERROR_STREAM("After: dataX="<<dataX); + + diffX = dataX - myMeanX; + diffY = dataY - myMeanY; + diffZ = dataZ - myMeanZ; + + diffXX = diffXX.mul(diffXX); + diffYY = diffYY.mul(diffYY); + diffZZ = diffZZ.mul(diffZZ); + + cv::Mat weightX, weightY, weightZ; + cv::exp(diffXX/lambda, weightX); + cv::exp(diffYY/lambda, weightY); + cv::exp(diffZZ/lambda, weightZ); + //cv::Mat wDataX = weightX.mul(selectedDataX); + //cv::Mat wDataY = weightY.mul(selectedDataY); + //cv::Mat wDataZ = weightZ.mul(selectedDataZ); + + weightX.setTo(0., inInds==0); //Again, because the exp and the x - u make invalid values non-zero (inInds) + weightY.setTo(0., inInds==0); + weightZ.setTo(0., inInds==0); + + cv::Mat wDataX = weightX.mul(dataX); + cv::Mat wDataY = weightY.mul(dataY); + cv::Mat wDataZ = weightZ.mul(dataZ); + totalWeightX = cv::sum(weightX)[0]; + totalWeightY = cv::sum(weightY)[0]; + totalWeightZ = cv::sum(weightZ)[0]; + myMeanX = cv::sum(wDataX)[0]/totalWeightX; + myMeanY = cv::sum(wDataY)[0]/totalWeightY; + myMeanZ = cv::sum(wDataZ)[0]/totalWeightZ; + + //cv::add(beenVisitedFlag, cv::Scalar(1.f), beenVisitedFlag, inInds); + beenVisitedFlag.setTo(1, inInds); + //ROS_ERROR_STREAM("myMean = ["<<myMeanX<<", "<<myMeanY<<", "<<myMeanZ<<"]"); + //exit(0); + // if mean doesn't move much stop this cluster + if((myMeanX-myOldMeanX)*(myMeanX-myOldMeanX) + (myMeanY-myOldMeanY)*(myMeanY-myOldMeanY) + (myMeanZ-myOldMeanZ)*(myMeanZ-myOldMeanZ) < stopThresh) + { + //check for merge possibilities + int mergeWith = -1; + double distToOther; + for(int cN = 0; cN<numClust; cN++) //Careful!! cN goes from 1 to numClust!!! + { + double distToOther = (myMeanX - (*clusterCenterX)[cN])*(myMeanX - (*clusterCenterX)[cN]) + (myMeanY - (*clusterCenterY)[cN])*(myMeanY - (*clusterCenterY)[cN]) + (myMeanZ - (*clusterCenterZ)[cN])*(myMeanZ - (*clusterCenterZ)[cN]); //distance from posible new clust max to old clust max + //ROS_ERROR_STREAM("Distance to others "<<distToOther<<" and cN "<<cN); + //ROS_ERROR_STREAM("myMean = ["<<myMeanX<<", "<<myMeanY<<", "<<myMeanZ<<"]"); + //ROS_ERROR_STREAM("clusterCenter = ["<<clusterCenterX[cN]<<", "<<clusterCenterY[cN]<<", "<<clusterCenterZ[cN]<<"]"); + if(distToOther < bandwidth/2) //if its within bandwidth/2 merge new and old + { + mergeWith = cN; + break; + } + } + + if(mergeWith > -1) + { + (*clusterCenterX)[mergeWith] = 0.5*(myMeanX+(*clusterCenterX)[mergeWith]); + (*clusterCenterY)[mergeWith] = 0.5*(myMeanY+(*clusterCenterY)[mergeWith]); + (*clusterCenterZ)[mergeWith] = 0.5*(myMeanZ+(*clusterCenterZ)[mergeWith]); + + cv::Mat newClusterVotes = cv::Mat(clusterVotes.row(mergeWith)) + thisClusterVotes; + newClusterVotes.copyTo(clusterVotes.row(mergeWith)); + } + else + { + numClust = numClust+1; //increment clusters + (*clusterCenterX).push_back(myMeanX); //record the mean + (*clusterCenterY).push_back(myMeanY); + (*clusterCenterZ).push_back(myMeanZ); + + clusterVotes.push_back(thisClusterVotes); // add the new row for the new cluster + } + break; + } + } + + std::vector<int> newInitPtInds; //we can initialize with any of the points not yet visited + for(int i=0; i<numPts; i++) + if (beenVisitedFlag.at<int>(cv::Point(i, 0)) == 0) + newInitPtInds.push_back(i); + initPtInds = newInitPtInds; + numInitPts = initPtInds.size(); //number of active points in set + + //ROS_ERROR_STREAM("Num. of values still un clustered "<<numInitPts); + //ROS_ERROR_STREAM("beenVisitedFlag "<<beenVisitedFlag); + //for(int i=0; i<initPtInds.size(); ++i) + // std::cerr<<initPtInds[i] << ' '; + } + //exit(0); + //[val,data2cluster] = max(clusterVotes,[],1); //a point belongs to the cluster with the most votes + + cv::Mat TclusterVotes = clusterVotes.t(); + + double min, max; + for(int i=0; i<TclusterVotes.rows; i++) + { + cv::minMaxIdx(cv::Mat(TclusterVotes.row(i)), &min, &max); + (*point2Clusters).push_back((int)max); + } + + //ROS_ERROR_STREAM("Inside "<<(*point2Clusters).size()); + //ROS_ERROR_STREAM("Number of clusters " <<numClust<<"and "<<clusterCenterX.size()); +}*/ + + + +void meanshiftCluster_Gaussian(cv::Mat dataPts, std::vector<double> *clusterCenterX, std::vector<double> *clusterCenterY, std::vector<double> *clusterCenterZ, std::vector<int> *point2Clusters, double bandwidth) +{ + //Initialization + int numPts = dataPts.cols; + int numDim = dataPts.rows; + int numClust = 0; + double bandSq = bandwidth*bandwidth; + cv::Range rng = cv::Range(0,numPts-1); + + cv::Mat onesAux = cv::Mat::ones(1, dataPts.cols, dataPts.type()); + + std::vector<int> initPtInds; + for (int i = rng.start; i <= rng.end; i++) initPtInds.push_back(i); + double stopThresh = 1E-3*bandwidth; //when mean has converged + int numInitPts = numPts; //track if a points been seen already + cv::Mat beenVisitedFlag = cv::Mat(1, numPts, CV_32S, cv::Scalar::all(0)); //number of points to posibaly use as initilization points + cv::Mat clusterVotes; //used to resolve conflicts on cluster membership + + double lambda = 10.; + double myMeanX, myMeanY, myMeanZ, myOldMeanX, myOldMeanY, myOldMeanZ, totalWeightX, totalWeightY, totalWeightZ; + int stInd; + + //std::vector<double> clusterCenterX, clusterCenterY, clusterCenterZ; + + + int tempInd; + + while (numInitPts>0) + { + //ROS_ERROR_STREAM("iniPtInds"); + //for(int i=0; i<initPtInds.size(); i++) + // std::cerr<<initPtInds[i]<<" "; + //std::cerr<<std::endl; + + + tempInd = (rand()%numInitPts); //pick a random seed point + //ROS_ERROR_STREAM("numInitPts ="<<numInitPts); + + //std::cin.ignore(); + stInd = initPtInds[tempInd]; //use this point as start of mean + /**********REMOVE THIS******************************/ + //stInd = initPtInds[numInitPts-1]; + /**********REMOVE THIS******************************/ + myMeanX = dataPts.at<double>(cv::Point(stInd, 0)); //intilize mean to this points location + myMeanY = dataPts.at<double>(cv::Point(stInd, 1)); + myMeanZ = dataPts.at<double>(cv::Point(stInd, 2)); + cv::Mat thisClusterVotes = cv::Mat(1, numPts, CV_32S, cv::Scalar::all(0)); //used to resolve conflicts on cluster membership + //ROS_ERROR_STREAM("Before getting into while myMean = ["<<myMeanX<<", "<<myMeanY<<", "<<myMeanZ<<"]"); + cv::Mat_<double> myMean = ( cv::Mat_<double>(3, 1) << myMeanX, myMeanY, myMeanZ); + + + while(true) + { + cv::Mat myDataPts; + dataPts.copyTo(myDataPts); + + //ROS_ERROR_STREAM("Original = "<<diffX); + //ROS_ERROR_STREAM("onesAux.rows = "<<onesAux.rows<<" cols = "<<onesAux.cols); + //ROS_ERROR_STREAM("dataPts.rows = "<<dataPts.rows<<" cols = "<<dataPts.cols); + //ROS_ERROR_STREAM("myMean.rows = "<<myMean.rows<<" cols = "<<myMean.cols); + + cv::Mat diff = myDataPts - myMean*onesAux; + cv::Mat diffdiff = diff.mul(diff); + cv::Mat sqDistToAll = diffdiff.row(0) +diffdiff.row(1) + diffdiff.row(2); //dist squared from mean to all points still active + + cv::Mat inInds = (sqDistToAll < bandSq); // Puts 255 wherever it is true + cv::add(thisClusterVotes, cv::Scalar(1), thisClusterVotes, inInds); //add a vote for all the in points belonging to this cluster + cv::Mat mask3 = cv::repeat(inInds==0, 3, 1); + + //ROS_ERROR_STREAM("BEFORE myMean = "<<myMean); + //ROS_ERROR_STREAM("sqDistToAll = "<<sqDistToAll); + //ROS_ERROR_STREAM("diffX = "<<diff.row(0)); + //ROS_ERROR_STREAM("diffdiffX = "<<diffdiff.row(0)); + //ROS_ERROR_STREAM("thisClusterVotes = "<<thisClusterVotes); + //ROS_ERROR_STREAM("dataPts = "<<dataPts); + + myDataPts.setTo(0, mask3); + double numOfOnes = (double) (cv::sum(inInds)[0])/255; //inInds is active if inInds[i]==255 + + myOldMeanX = myMeanX; myOldMeanY = myMeanY; myOldMeanZ = myMeanZ; + + myMeanX = cv::sum(myDataPts.row(0))[0]/numOfOnes; + myMeanY = cv::sum(myDataPts.row(1))[0]/numOfOnes; + myMeanZ = cv::sum(myDataPts.row(2))[0]/numOfOnes; + + myMean = ( cv::Mat_<double>(3, 1) << myMeanX, myMeanY, myMeanZ); + + //ROS_ERROR_STREAM("MIDDLE myMean = "<<myMean); + + diff = myDataPts - myMean*onesAux; + diffdiff = diff.mul(diff); + + cv::Mat weight; + cv::exp(diffdiff/lambda, weight); + + weight.setTo(0., mask3); //Again, because the exp and the x - u make invalid values non-zero (inInds) + cv::Mat wData = weight.mul(myDataPts); + + totalWeightX = cv::sum(weight.row(0))[0]; + totalWeightY = cv::sum(weight.row(1))[0]; + totalWeightZ = cv::sum(weight.row(2))[0]; + myMeanX = cv::sum(wData.row(0))[0]/totalWeightX; + myMeanY = cv::sum(wData.row(1))[0]/totalWeightY; + myMeanZ = cv::sum(wData.row(2))[0]/totalWeightZ; + + myMean = ( cv::Mat_<double>(3, 1) << myMeanX, myMeanY, myMeanZ); + //ROS_ERROR_STREAM("AFTER: myMean = "<<myMeanX<<","<<myMeanY<<","<<myMeanZ); + //exit(0); + + beenVisitedFlag.setTo(1, inInds); + //ROS_ERROR_STREAM("beenVisitedFlag = "<<beenVisitedFlag); + + // if mean doesn't move much stop this cluster + //ROS_ERROR_STREAM("Norm = "<<(myMeanX-myOldMeanX)*(myMeanX-myOldMeanX) + (myMeanY-myOldMeanY)*(myMeanY-myOldMeanY) + (myMeanZ-myOldMeanZ)*(myMeanZ-myOldMeanZ)); + if((myMeanX-myOldMeanX)*(myMeanX-myOldMeanX) + (myMeanY-myOldMeanY)*(myMeanY-myOldMeanY) + (myMeanZ-myOldMeanZ)*(myMeanZ-myOldMeanZ) < stopThresh*stopThresh) + { + //check for merge posibilities + //ROS_ERROR_STREAM("Dentro!! "); + int mergeWith = -1; + double distToOther; + for(int cN = 0; cN<numClust; cN++) //Careful!! cN goes from 1 to numClust!!! + { + double distToOther = (myMeanX - (*clusterCenterX)[cN])*(myMeanX - (*clusterCenterX)[cN]) + (myMeanY - (*clusterCenterY)[cN])*(myMeanY - (*clusterCenterY)[cN]) + (myMeanZ - (*clusterCenterZ)[cN])*(myMeanZ - (*clusterCenterZ)[cN]); //distance from posible new clust max to old clust max + //ROS_ERROR_STREAM("Dentro!! "); + //ROS_ERROR_STREAM("distToOther " <<distToOther); + if(distToOther < (bandwidth/2)*(bandwidth/2)) //if its within bandwidth/2 merge new and old + { + mergeWith = cN; + break; + } + } + + if(mergeWith > -1) + { + //ROS_ERROR_STREAM("Merging cluster with #"<<mergeWith); + //ROS_ERROR_STREAM("NumClust = "<<numClust); + //exit(0); + + (*clusterCenterX)[mergeWith] = 0.5*(myMeanX+(*clusterCenterX)[mergeWith]); + (*clusterCenterY)[mergeWith] = 0.5*(myMeanY+(*clusterCenterY)[mergeWith]); + (*clusterCenterZ)[mergeWith] = 0.5*(myMeanZ+(*clusterCenterZ)[mergeWith]); + + cv::Mat newClusterVotes = cv::Mat(clusterVotes.row(mergeWith)) + thisClusterVotes; + newClusterVotes.copyTo(clusterVotes.row(mergeWith)); + + //ROS_ERROR_STREAM("clusterVotes = "<<clusterVotes); + //exit(0); + } + else + { + //ROS_ERROR_STREAM("Creating new cluster"); + (*clusterCenterX).push_back(myMeanX); //record the mean + (*clusterCenterY).push_back(myMeanY); + (*clusterCenterZ).push_back(myMeanZ); + numClust = numClust+1; //increment clusters + + clusterVotes.push_back(thisClusterVotes); // add the new row for the new cluster + + //ROS_ERROR_STREAM("clusterVotes = "<<clusterVotes); + //ROS_ERROR_STREAM("ClusterCenterX = "<<(*clusterCenterX)[numClust-1]); + //ROS_ERROR_STREAM("ClusterCenterY = "<<(*clusterCenterY)[numClust-1]); + //ROS_ERROR_STREAM("ClusterCenterZ = "<<(*clusterCenterZ)[numClust-1]); + //exit(0); + } + break; + } + } + + std::vector<int> newInitPtInds; //we can initialize with any of the points not yet visited + for(int i=0; i<numPts; i++) + if (beenVisitedFlag.at<int>(cv::Point(i, 0)) == 0) + newInitPtInds.push_back(i); + initPtInds = newInitPtInds; + numInitPts = initPtInds.size(); //number of active points in set + } + + cv::Mat TclusterVotes = clusterVotes.t(); + cv::Point minLoc; + cv::Point maxLoc; + double min, max; + for(int i=0; i<TclusterVotes.rows; i++) + { + cv::minMaxLoc(cv::Mat(TclusterVotes.row(i)), &min, &max, &minLoc, &maxLoc); + (*point2Clusters).push_back(maxLoc.x); + } + + //ROS_ERROR_STREAM("Number of clusters " <<numClust<<" and "<<(*clusterCenterX).size()); + //ROS_ERROR_STREAM("Tclusters rows " <<TclusterVotes.rows<<" cols "<<TclusterVotes.cols); +} + +void colorMeanShiftFilt(double *newPixelsPtr, const double *pixelsPtr, int mPixels, int maxPixelDim, const double *imagePtr, int numRows, int numCols, float spaceDivider, char *kernelFun, int maxIterNum, float tolFun) +{ + // Copy the original pixel values to the new pixel matrix + memcpy(newPixelsPtr, pixelsPtr, maxPixelDim*mPixels*sizeof(double)); + + // Copy the original image to a new image + double *newImagePtr=new double[mPixels]; + memcpy(newImagePtr, imagePtr, mPixels*sizeof(double)); + + // Help variables + double x,y,val; + int neighX, neighY; + bool bRepeat=false; + + double *delta = (double *) calloc(maxPixelDim,sizeof(double)); + double *dX = (double *) calloc(maxPixelDim,sizeof(double)); + double *neighVec = (double *) calloc(maxPixelDim,sizeof(double)); + double deltaGrad2; + + // Create an array that indicates if we reached the end of the optimization for each pixel + double *optimizedPointArray=new double[mPixels]; + + for (int iterNum=0; iterNum<maxIterNum; iterNum++) + { + bRepeat=false; + + cv::Mat XX=cv::Mat(numRows, numCols, CV_64F, newPixelsPtr); + cv::Mat YY=cv::Mat(numRows, numCols, CV_64F, newPixelsPtr+mPixels); + cv::Mat MM=cv::Mat(numRows, numCols, CV_64F, newPixelsPtr+2*mPixels); + + for (int pointNum=0; pointNum<mPixels; pointNum++) + { + if (optimizedPointArray[pointNum]==1) // The optimization for this pixel has reached the threshold + continue; + + x=newPixelsPtr[_2D_to_linear(0, pointNum, mPixels)]; + y=newPixelsPtr[_2D_to_linear(1, pointNum, mPixels)]; + val=newPixelsPtr[_2D_to_linear(2, pointNum, mPixels)]; + + //ROS_ERROR("y = %d, x = %d, pointNum = %d, spaceDivider = %g", (int)floor(y), (int)floor(x), pointNum, spaceDivider); + double sumF; + + int x_coord = max(0, floor(x*spaceDivider)-1-spaceDivider); + int y_coord = max(0, floor(y*spaceDivider)-1-spaceDivider); + int width = min(2*spaceDivider+1, numCols-x_coord); + int height= min(2*spaceDivider+1, numRows-y_coord); + + cv::Mat submatXX = XX(cv::Rect(x_coord, y_coord, width, height)).clone(); + cv::Mat submatYY = YY(cv::Rect(x_coord, y_coord, width, height)).clone(); + cv::Mat submatMM = MM(cv::Rect(x_coord, y_coord, width, height)).clone(); + + cv::Mat delta_XX, delta_YY, delta_MM, dist2_matrix, kres_matrix; + delta_XX = x - submatXX; + delta_YY = y - submatYY; + delta_MM = val - submatMM; + dist2_matrix = delta_XX.mul(delta_XX) + delta_YY.mul(delta_YY) + delta_MM.mul(delta_MM); + cv::exp(dist2_matrix/(-2.0), kres_matrix); //kres =(exp(-dist2/2.0)); + + dX[0] = cv::sum(kres_matrix.mul(submatXX))[0];//cv::sum() returns a cvScalar, to get the value we need .val(0) + dX[1] = cv::sum(kres_matrix.mul(submatYY))[0]; + dX[2] = cv::sum(kres_matrix.mul(submatMM))[0]; + sumF = cv::sum(kres_matrix)[0]; + + // Find the corresponding row and column of the point + + dX[0]=(sumF==0)?0:dX[0]/sumF; //check for NaNs + dX[1]=(sumF==0)?0:dX[1]/sumF; //check for NaNs + dX[2]=(sumF==0)?0:dX[2]/sumF; //check for NaNs + + double tmp1=newPixelsPtr[_2D_to_linear(0, pointNum, mPixels)]-dX[0]; + double tmp2=newPixelsPtr[_2D_to_linear(1, pointNum, mPixels)]-dX[1]; + double tmp3=newPixelsPtr[_2D_to_linear(2, pointNum, mPixels)]-dX[2]; + + deltaGrad2=tmp1*tmp1+tmp2*tmp2+tmp3*tmp3; + newPixelsPtr[_2D_to_linear(0, pointNum, mPixels)]=dX[0]; + newPixelsPtr[_2D_to_linear(1, pointNum, mPixels)]=dX[1]; + newPixelsPtr[_2D_to_linear(2, pointNum, mPixels)]=dX[2]; + + newImagePtr[pointNum]=dX[2]; + + if (deltaGrad2<tolFun) + optimizedPointArray[pointNum]=1; + else + bRepeat=true; + + } // end pointNum loop + + if (bRepeat==false) + break; + + } // end for(iterNum) loop + + + // CLEAN-UP + delete[] newImagePtr; + delete[] optimizedPointArray; + delete(delta); + delete(dX); + delete(neighVec); +} + + + diff --git a/RWR/src/mean-shift/dvs_meanshift/src/image_reconst.cpp b/RWR/src/mean-shift/dvs_meanshift/src/image_reconst.cpp new file mode 100755 index 0000000000000000000000000000000000000000..1d58720914bc49f62bbc0ce2dc8895e7d4052710 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/src/image_reconst.cpp @@ -0,0 +1,568 @@ +/* + * image_reconst.cpp + * + * Created on: Nov 3, 2016 + * Author: fran + */ + +/* +######################### Poisson Image Editing ############################ + +Copyright (C) 2012 Siddharth Kherada +Copyright (C) 2006-2012 Natural User Interface Group + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. " + +############################################################################## +*/ + +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <complex> +#include "image_reconstruct/image_reconst.h" +#include <math.h> +#include <omp.h> + +//using namespace std; +//using namespace cv; + +#define pi 3.1416 + +#define ATF at<float> +#define AT3F at<Vec3f> +#define ATB at<uchar> +#define AT3B at<Vec3b> + +/////////////////////Poisson Equation Solver by FFT///////////////////// +void dst(double *btest, double *bfinal, int h, int w) +{ + + unsigned long int idx; + + cv::Mat temp = cv::Mat(2 * h + 2, 1, CV_32F); + cv::Mat res = cv::Mat(h, 1, CV_32F); + + int p = 0; + + for (int i = 0; i<w; i++) + { + temp.ATF(0, 0) = 0.0; + + for (int j = 0, r = 1; j<h; j++, r++) + { + idx = j*w + i; + temp.ATF(r, 0) = (float)btest[idx]; + } + + temp.ATF(h + 1, 0) = 0.0; + + for (int j = h - 1, r = h + 2; j >= 0; j--, r++) + { + idx = j*w + i; + temp.ATF(r, 0) = (float)(-1 * btest[idx]); + } + + cv::Mat planes[] = { cv::Mat_<float>(temp), cv::Mat::zeros(temp.size(), CV_32F) }; + + cv::Mat complex1; + merge(planes, 2, complex1); + + dft(complex1, complex1, 0, 0); + + cv::Mat planes1[] = { cv::Mat::zeros(complex1.size(), CV_32F), cv::Mat::zeros(complex1.size(), CV_32F) }; + + split(complex1, planes1); + + std::complex<double> two_i = std::sqrt(std::complex<double>(-1)); + + double fac = -2 * imag(two_i); + + for (int c = 1, z = 0; c<h + 1; c++, z++) + { + res.ATF(z, 0) = (float)(planes1[1].ATF(c, 0) / fac); + } + + for (int q = 0, z = 0; q<h; q++, z++) + { + idx = q*w + p; + bfinal[idx] = res.ATF(z, 0); + } + p++; + } + +} + +void idst(double *btest, double *bfinal, int h, int w) +{ + int nn = h + 1; + dst(btest, bfinal, h, w); + #pragma omp parallel for + for (int i = 0; i<h; i++) + for (int j = 0; j<w; j++) + { + unsigned long int idx = i*w + j; + bfinal[idx] = (double)(2 * bfinal[idx]) / nn; + } + +} + +void transpose(double *mat, double *mat_t, int h, int w) +{ + + cv::Mat tmp = cv::Mat(h, w, CV_32FC1); + int p = 0; + + #pragma omp parallel for + for (int i = 0; i < h; i++) + { + for (int j = 0; j < w; j++) + { + + unsigned long int idx = i*(w)+j; + tmp.ATF(i, j) = (float)(mat[idx]); + } + } + cv::Mat tmp_t = tmp.t(); + + unsigned long int idx; + for (int i = 0; i < tmp_t.size().height; i++) + for (int j = 0; j<tmp_t.size().width; j++) + { + idx = i*tmp_t.size().width + j; + mat_t[idx] = tmp_t.ATF(i, j); + } + +} + + +void getGradientX(cv::Mat &img, cv::Mat &gx) +{ + int height = img.rows; + int width = img.cols; + cv::Mat cat = repeat(img, 1, 2); + /*cat.col(width) = 0;*/ + cv::Mat roimat = cat(cv::Rect(1, 0, width, height)); + gx = roimat - img; + gx.col(width - 1) = 0; +} + +// calculate vertical gradient, gy(i, j) = img(i, j+1) - img(i, j) +void getGradientY(cv::Mat &img, cv::Mat &gy) +{ + int height = img.rows; + int width = img.cols; + cv::Mat cat = repeat(img, 2, 1); + /*cat.row(height) = 0;*/ + cv::Mat roimat = cat(cv::Rect(0, 1, width, height)); + gy = roimat - img; + gy.row(height - 1) = 0; +} + +// calculate horizontal gradient, gxx(i+1, j) = gx(i+1, j) - gx(i, j) +void lapx(cv::Mat &gx, cv::Mat &gxx) +{ + int height = gx.rows; + int width = gx.cols; + cv::Mat cat = repeat(gx, 1, 2); + /*cat.col(width - 1) = 0;*/ + cv::Mat roi = cat(cv::Rect(width - 1, 0, width, height)); + gxx = gx - roi; + gxx.col(0) = 0; +} + +// calculate vertical gradient, gyy(i, j+1) = gy(i, j+1) - gy(i, j) +void lapy(cv::Mat &gy, cv::Mat &gyy) +{ + int height = gy.rows; + int width = gy.cols; + cv::Mat cat = repeat(gy, 2, 1); + /*cat.row(height - 1) = 0;*/ + cv::Mat roi = cat(cv::Rect(0, height - 1, width, height)); + gyy = gy - roi; + gyy.row(0) = 0; +} + + + +void poisson_solver(cv::Mat &img, cv::Mat &gxx, cv::Mat &gyy, cv::Mat &result){ + + int w = img.cols; + int h = img.rows; + int channel = img.channels(); + + unsigned long int idx; + + cv::Mat lap = gxx + gyy; + + cv::Mat bound(img); + bound(cv::Rect(1, 1, w - 2, h - 2)) = 0; + double *dir_boundary = new double[h*w]; + +#pragma omp parallel for + for (int i = 1; i < h - 1; i++) + for (int j = 1; j < w - 1; j++) + { + unsigned long int idx = i*w + j; + if ( i == 1 || i == h - 2 || j == 1 || j == w - 2 ) + dir_boundary[idx] = (int)bound.ATF(i, (j + 1)) + (int)bound.ATF(i, (j - 1)) + (int)bound.ATF(i - 1, j) + (int)bound.ATF(i + 1, j); + else dir_boundary[idx] = 0; + + } + + + cv::Mat diff(h, w, CV_32FC1); + +#pragma omp parallel for + for (int i = 0; i<h; i++) + { + for (int j = 0; j<w; j++) + { + unsigned long int idx = i*w + j; + diff.ATF(i, j) = (float)(lap.ATF(i, j) - dir_boundary[idx]); + } + } + + double *btemp = new double[(h - 2)*(w - 2)]; +#pragma omp parallel for + for (int i = 0; i < h - 2; i++) + { + for (int j = 0; j < w - 2; j++) + { + unsigned long int idx = i*(w - 2) + j; + btemp[idx] = diff.ATF(i + 1, j + 1); + + } + } + + double *bfinal = new double[(h - 2)*(w - 2)]; + double *bfinal_t = new double[(h - 2)*(w - 2)]; + double *denom = new double[(h - 2)*(w - 2)]; + double *fres = new double[(h - 2)*(w - 2)]; + double *fres_t = new double[(h - 2)*(w - 2)]; + + + dst(btemp, bfinal, h - 2, w - 2); + + transpose(bfinal, bfinal_t, h - 2, w - 2); + + dst(bfinal_t, bfinal, w - 2, h - 2); + + transpose(bfinal, bfinal_t, w - 2, h - 2); + + int cx = 1; + int cy = 1; + + for (int i = 0; i < w - 2; i++, cy++) + { + for (int j = 0, cx = 1; j < h - 2; j++, cx++) + { + idx = j*(w - 2) + i; + denom[idx] = (float)2 * cos(pi*cy / ((double)(w - 1))) - 2 + 2 * cos(pi*cx / ((double)(h - 1))) - 2; + + } + } + + for (idx = 0; (int)idx < (w - 2)*(h - 2); idx++) + { + bfinal_t[idx] = bfinal_t[idx] / denom[idx]; + } + + + idst(bfinal_t, fres, h - 2, w - 2); + + transpose(fres, fres_t, h - 2, w - 2); + + idst(fres_t, fres, w - 2, h - 2); + + transpose(fres, fres_t, w - 2, h - 2); + + + img.convertTo(result, CV_8UC1); + + + cv::Mat tmp = cv::Mat(h-2, w-2, CV_64F, fres_t); + double min, max; + cv::minMaxLoc(tmp, &min, &max); + + + #pragma omp parallel for + for (int i = 0; i < h - 2; i++) + { + for (int j = 0; j < w - 2; j++) + { + unsigned long int idx = i*(w - 2) + j; + //if (fres_t[idx] < 0.0) + // result.ATB(i+1, j+1) = 0; + //else if (fres_t[idx] > 255.0) + // result.ATB(i+1, j+1) = 255; + //else + // result.ATB(i+1, j+1) = (int)fres_t[idx]; + result.ATB(i+1,j+1) = (int) (255*(fres_t[idx]-min)/(max-min)); + } + } + +} + +void poisson_solver_jacobi(cv::Mat &img, cv::Mat &gxx, cv::Mat &gyy, cv::Mat &result) { + int w = img.cols; + int h = img.rows; + int channel = img.channels(); + + unsigned long int idx; + + cv::Mat lap = gxx + gyy; + + cv::Mat bound(img); + bound(cv::Rect(1, 1, w - 2, h - 2)) = 0; + double *dir_boundary = new double[h*w]; + + #pragma omp parallel for + for (int i = 1; i < h - 1; i++) + for (int j = 1; j < w - 1; j++) + { + idx = i*w + j; + if (i == 1 || i == h - 2 || j == 1 || j == w - 2) + dir_boundary[idx] = (int)bound.ATF(i, (j + 1)) + (int)bound.ATF(i, (j - 1)) + (int)bound.ATF(i - 1, j) + (int)bound.ATF(i + 1, j); + else dir_boundary[idx] = 0; + + } + + + cv::Mat diff(h, w, CV_32FC1); + #pragma omp parallel for + for (int i = 0; i < h; i++) + { + for (int j = 0; j < w; j++) + { + idx = i*w + j; + diff.ATF(i, j) = (float)(-lap.ATF(i, j) + dir_boundary[idx]); + } + } + + double *gtest = new double[(h - 2)*(w - 2)]; + #pragma omp parallel for + for (int i = 0; i < h - 2; i++) + { + for (int j = 0; j < w - 2; j++) + { + idx = i*(w - 2) + j; + gtest[idx] = diff.ATF(i + 1, j + 1); + + } + } + //Iteration begins + cv::Mat U = cv::Mat::zeros(img.size(), CV_32FC3); + int k = 0; + while (k <= 3000){ + #pragma omp parallel for + for (int i = 1; i < h - 1; i++) + { + for (int j = 1; j < w - 1; j++) + { + U.ATF(i, j) = (float)((U.ATF(i + 1, j) + U.ATF(i, j + 1) + U.ATF(i - 1, j) + U.ATF(i, j - 1) + diff.ATF(i, j)) / 4.0); + } + } + k++; + } + + img.convertTo(result, CV_8UC1); + #pragma omp parallel for + for (int i = 1; i < h - 1; i++) + { + for (int j = 1; j < w - 1; j++) + { + if (U.ATF(i,j) < 0.0) + result.ATB(i , j ) = 0; + else if (U.ATF(i, j) > 255.0) + result.ATB(i, j) = 255; + else + result.ATB(i , j ) = (int)U.ATF(i, j); + } + } +} + + +//IplImage versions + +void lapx( const IplImage *img, IplImage *gxx) +{ + int w = img->width; + int h = img->height; + int channel = img->nChannels; + + cvZero( gxx ); + for(int i=0;i<h;i++) + for(int j=0;j<w-1;j++) + for(int c=0;c<channel;++c) + { + CV_IMAGE_ELEM(gxx,float,i,(j+1)*channel+c) = + (float)CV_IMAGE_ELEM(img,float,i,(j+1)*channel+c) - (float)CV_IMAGE_ELEM(img,float,i,j*channel+c); + } +} +void lapy( const IplImage *img, IplImage *gyy) +{ + int w = img->width; + int h = img->height; + int channel = img->nChannels; + + cvZero( gyy ); + for(int i=0;i<h-1;i++) + for(int j=0;j<w;j++) + for(int c=0;c<channel;++c) + { + CV_IMAGE_ELEM(gyy,float,i+1,j*channel+c) = + (float)CV_IMAGE_ELEM(img,float,(i+1),j*channel+c) - (float)CV_IMAGE_ELEM(img,float,i,j*channel+c); + + } +} + +void poisson_solver(const IplImage *img, IplImage *gxx , IplImage *gyy, cv::Mat &result) +{ + + int w = img->width; + int h = img->height; + int channel = img->nChannels; + + unsigned long int idx,idx1; + + IplImage *lap = cvCreateImage(cvGetSize(img), 32, 1); + + for(int i =0;i<h;i++) + for(int j=0;j<w;j++) + CV_IMAGE_ELEM(lap,float,i,j)=CV_IMAGE_ELEM(gyy,float,i,j)+CV_IMAGE_ELEM(gxx,float,i,j); + + //cv::Mat bound(img); + cv::Mat bound = cv::cvarrToMat(img); + + for(int i =1;i<h-1;i++) + for(int j=1;j<w-1;j++) + { + bound.at<uchar>(i,j) = 0.0; + } + + double *f_bp = new double[h*w]; + + + for(int i =1;i<h-1;i++) + for(int j=1;j<w-1;j++) + { + idx=i*w + j; + f_bp[idx] = -4*(int)bound.at<uchar>(i,j) + (int)bound.at<uchar>(i,(j+1)) + (int)bound.at<uchar>(i,(j-1)) + + (int)bound.at<uchar>(i-1,j) + (int)bound.at<uchar>(i+1,j); + } + + + cv::Mat diff = cv::Mat(h,w,CV_32FC1); + for(int i =0;i<h;i++) + { + for(int j=0;j<w;j++) + { + idx = i*w+j; + diff.at<float>(i,j) = (CV_IMAGE_ELEM(lap,float,i,j) - f_bp[idx]); + } + } + double *gtest = new double[(h-2)*(w-2)]; + for(int i = 0 ; i < h-2;i++) + { + for(int j = 0 ; j < w-2; j++) + { + idx = i*(w-2) + j; + gtest[idx] = diff.at<float>(i+1,j+1); + + } + } + ///////////////////////////////////////////////////// Find DST ///////////////////////////////////////////////////// + + double *gfinal = new double[(h-2)*(w-2)]; + double *gfinal_t = new double[(h-2)*(w-2)]; + double *denom = new double[(h-2)*(w-2)]; + double *f3 = new double[(h-2)*(w-2)]; + double *f3_t = new double[(h-2)*(w-2)]; + double *img_d = new double[(h)*(w)]; + + dst(gtest,gfinal,h-2,w-2); + + transpose(gfinal,gfinal_t,h-2,w-2); + + dst(gfinal_t,gfinal,w-2,h-2); + + transpose(gfinal,gfinal_t,w-2,h-2); + + int cx=1; + int cy=1; + + for(int i = 0 ; i < w-2;i++,cy++) + { + for(int j = 0,cx = 1; j < h-2; j++,cx++) + { + idx = j*(w-2) + i; + denom[idx] = (float) 2*cos(pi*cy/( (double) (w-1))) - 2 + 2*cos(pi*cx/((double) (h-1))) - 2; + + } + } + + for(idx = 0 ; idx < (w-2)*(h-2) ;idx++) + { + gfinal_t[idx] = gfinal_t[idx]/denom[idx]; + } + + + idst(gfinal_t,f3,h-2,w-2); + + transpose(f3,f3_t,h-2,w-2); + + idst(f3_t,f3,w-2,h-2); + + transpose(f3,f3_t,w-2,h-2); + + for(int i = 0 ; i < h;i++) + { + for(int j = 0 ; j < w; j++) + { + idx = i*w + j; + img_d[idx] = (double)CV_IMAGE_ELEM(img,uchar,i,j); + } + } + for(int i = 1 ; i < h-1;i++) + { + for(int j = 1 ; j < w-1; j++) + { + idx = i*w + j; + img_d[idx] = 0.0; + } + } + int id1,id2; + for(int i = 1,id1=0 ; i < h-1;i++,id1++) + { + for(int j = 1,id2=0 ; j < w-1; j++,id2++) + { + idx = i*w + j; + idx1= id1*(w-2) + id2; + img_d[idx] = f3_t[idx1]; + } + } + + for(int i = 0 ; i < h;i++) + { + for(int j = 0 ; j < w; j++) + { + idx = i*w + j; + if(img_d[idx] < 0.0) + result.at<uchar>(i,j) = 0; + else if(img_d[idx] > 255.0) + result.at<uchar>(i,j) = 255.0; + else + result.at<uchar>(i,j) = img_d[idx]; + } + } + +} diff --git a/RWR/src/mean-shift/dvs_meanshift/src/meanshift.cpp b/RWR/src/mean-shift/dvs_meanshift/src/meanshift.cpp new file mode 100755 index 0000000000000000000000000000000000000000..faca3149e05e8e6941e8be34192e121b0dc4376d --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/src/meanshift.cpp @@ -0,0 +1,1606 @@ + +#include "dvs_meanshift/meanshift.h" +#include "dvs_meanshift/color_meanshift.h" +#include "image_reconstruct/image_reconst.h" +#include <time.h> + +//remove this include, just for debugging +#include "graph3d/pnmfile.h" +#include <std_msgs/Float32.h> + +#define min(x,y) ((x)<(y)?(x):(y)) + +double epsilon = 1E-10; +int counterGlobal = 0; +const int MAX_DISTANCE = 500; //actually the real distance is sqrt(MAX_DISTANCE) + +bool firstevent = true; +double firsttimestamp; + +//std::ofstream foutX("/home/fran/0_tmp/kk/shapes_rotation_totalevents.txt"); +//std::ofstream fouttotalproc("/home/fran/0_tmp/kk/shapes_rotation_totalprocessing_f.txt"); +//std::ofstream foutX("/home/fran/0_tmp/kk/shapes_rotation_2_totalevents.txt"); +//std::ofstream fouttotalproc("/home/fran/0_tmp/kk/shapes_rotation_2_totalprocessing_f.txt"); +//std::ofstream foutX("/home/fran/0_tmp/kk/shapes_translation_totalevents.txt"); +//std::ofstream fouttotalproc("/home/fran/0_tmp/kk/shapes_translation_totalprocessing_f.txt"); +//std::ofstream foutX("/home/fran/0_tmp/kk/shapes_translation_2_totalevents.txt"); +//std::ofstream fouttotalproc("/home/fran/0_tmp/kk/shapes_translation_2_totalprocessing_f.txt"); +//std::ofstream foutX("/home/fran/0_tmp/kk/shapes_6dof_totalevents.txt"); +//std::ofstream fouttotalproc("/home/fran/0_tmp/kk/shapes_6dof_totalprocessing_f.txt"); +//std::ofstream foutX("/home/fran/0_tmp/kk/shapes_6dof_2_totalevents.txt"); +//std::ofstream fouttotalproc("/home/fran/0_tmp/kk/shapes_6dof_2_totalprocessing_f.txt"); +//std::ofstream foutnumclust("/home/fran/0_tmp/kk/shapes_translation_numclusters_f.txt"); +//std::ofstream foutnumclust("/home/fran/0_tmp/kk/shapes_rotation_numclusters_f.txt"); +//std::ofstream foutnumclust("/home/fran/0_tmp/kk/shapes_6dof_numclusters_f.txt"); +//std::ofstream foutnumclust("/home/fran/0_tmp/kk/shapes_6dof_2_numclusters_f.txt"); +//std::ofstream foutnumclust("/home/fran/0_tmp/kk/shapes_rotation_2_numclusters_f.txt"); +//std::ofstream foutnumclust("/home/fran/0_tmp/kk/shapes_translation_2_numclusters_f.txt"); + +#if KALMAN_FILTERING +//std::ofstream foutX("/home/fran/0_tmp/kk/traj.txt"); +//std::ofstream foutX_estim("/home/fran/0_tmp/kk/filt_traj.txt"); +//std::ofstream foutT("/home/fran/0_tmp/kk/timetraj.txt"); +#endif + +namespace dvs_meanshift { + +void writeMatToFile(cv::Mat & m, const char* filename) +{ + std::ofstream fout(filename); + std::cout<<" IM ALIVE?? 1"<<std::endl; + + if(!fout) + { + std::cout<<"File Not Opened"<<std::endl; return; + } + + for(int i=0; i<m.rows; i++) + { + for(int j=0; j<m.cols; j++) + { + fout<<m.at<double>(i,j)<<"\t"; + } + fout<<std::endl; + } + fout.close(); +} + +class Parallel_pixel_cosine: public cv::ParallelLoopBody +{ + +public: + + Parallel_pixel_cosine(cv::Mat imgg) : img(imgg) + { + } + + void operator() (const cv::Range &r) const + { + for(int j=r.start; j<r.end; ++j) + { + double* current = const_cast<double*>(img.ptr<double>(j)); + double* last = current + img.cols; + + for (; current != last; ++current) + *current = (double) cos((double) *current); + } + } + +private: + cv::Mat img; +}; + +void meshgrid(const cv::Mat &xgv, const cv::Mat &ygv, cv::Mat1i &X, cv::Mat1i &Y) +{ + std::cout<<" IM ALIVE?? 2"<<std::endl; + cv::repeat(xgv.reshape(1,1), ygv.total(), 1, X); + cv::repeat(ygv.reshape(1,1).t(), 1, xgv.total(), Y); + +} + +// helper function (maybe that goes somehow easier) + void meshgridTest(const cv::Range &xgv, const cv::Range &ygv, cv::Mat1i &X, cv::Mat1i &Y) +{ + std::cout<<" IM ALIVE?? 3"<<std::endl; + std::vector<int> t_x, t_y; + for (int i = xgv.start; i <= xgv.end; i++) t_x.push_back(i); + for (int i = ygv.start; i <= ygv.end; i++) t_y.push_back(i); + + meshgrid(cv::Mat(t_x), cv::Mat(t_y), X, Y); +} + +void findClosestCluster(std::vector<int> * clustID, std::vector<double> clustX, std::vector<double> clustY,std::vector<double>clustX_old,std::vector<double> clustY_old) +{ + + //for (int i = 0; i<clustX.size(); i++) + // ROS_ERROR_STREAM("ClusterCenter("<<i+1<<",:)=["<<clustX.at(i)<<","<<clustY.at(i)<<"];"); + //for (int i = 0; i<clustX_old.size(); i++) + // ROS_ERROR_STREAM("prev_ClusterCenter("<<i+1<<",:)=["<<clustX_old.at(i)<<","<<clustY_old.at(i)<<"];"); + std::cout<<" IM ALIVE?? 4"<<std::endl; + std::vector<double> distvalue (clustX.size()); + double tmp; + + for(int i=0; i<clustX.size(); i++) + { + distvalue[i]=MAX_DISTANCE; + (*clustID).push_back(-1); //no match when clustID is -1 + for(int j=0; j<clustX_old.size(); j++) + { + tmp= (clustX[i]*DVSW-clustX_old[j]*DVSW)*(clustX[i]*DVSW-clustX_old[j]*DVSW) + (clustY[i]*DVSH-clustY_old[j]*DVSH)*(clustY[i]*DVSH-clustY_old[j]*DVSH); + if(tmp<distvalue[i]) + { + distvalue[i]=tmp; + (*clustID)[i]=j; + //ROS_ERROR_STREAM("Cluster "<<i+1<<" same than old cluster "<<j+1<<". Distance = "<<distvalue[i]); + } + } + } +} + +/* +void Meanshift::assignClusterColor(std::vector<int> * positionClusterColor, int numClusters, std::vector<int> matches, std::vector<int> oldPositions) +{ + + if (matches.size()==0) //no mask --> assing all new colors + { + for(int i=0; i<numClusters; i++) + { + (*positionClusterColor).push_back(lastPositionClusterColor); + lastPositionClusterColor = lastPositionClusterColor+1; + } + } + else + { + for(int i=0; i<numClusters; i++) + { + if(matches[i]==-1) //No match with previous clusters --> new cluster, new color + { + (*positionClusterColor).push_back(lastPositionClusterColor); + lastPositionClusterColor = lastPositionClusterColor+1; + } + else //Match with previous cluster --> assign color of previous cluster + { + (*positionClusterColor).push_back(oldPositions[matches[i]]); + } + } + + } +}*/ + +void Meanshift::assignClusterColor(std::vector<int> * positionClusterColor, int numClusters, std::vector<int> matches, std::vector<int> oldPositions, std::vector<int> activeTrajectories) +{ + std::cout<<" IM ALIVE?? 5"<<std::endl; + if (matches.size()==0) //no mask --> assing all new colors + { + for(int i=0; i<numClusters; i++) + { + (*positionClusterColor).push_back(lastPositionClusterColor); + lastPositionClusterColor = lastPositionClusterColor+1; + } + } + else + { + for(int i=0; i<numClusters; i++) + { + if(matches[i]==-1) //No match with previous clusters --> new cluster, new color + { + //Check if the new position is being used + while ( activeTrajectories.end() != find (activeTrajectories.begin(), activeTrajectories.end(), (lastPositionClusterColor & (MAX_NUM_CLUSTERS-1)))) + lastPositionClusterColor++; + + (*positionClusterColor).push_back(lastPositionClusterColor); + lastPositionClusterColor = lastPositionClusterColor+1; + } + else //Match with previous cluster --> assign color of previous cluster + { + (*positionClusterColor).push_back(oldPositions[matches[i]]); + } + } + + } +} + +Meanshift::Meanshift(ros::NodeHandle & nh, ros::NodeHandle nh_private) : nh_(nh) +{ + //std::cout<<" IM ALIVE?? 6"<<std::endl; + used_last_image_ = false; + + // get parameters of display method + std::string display_method_str; + nh_private.param<std::string>("display_method", display_method_str, ""); + display_method_ = (display_method_str == std::string("grayscale")) ? GRAYSCALE : RED_BLUE; + + // setup subscribers and publishers + //event_sub_ = nh_.subscribe("events", 1, &Meanshift::eventsCallback, this); + event_sub_ = nh_.subscribe("events", 1, &Meanshift::eventsCallback_simple, this); + camera_info_sub_ = nh_.subscribe("camera_info", 1, &Meanshift::cameraInfoCallback, this); + + image_transport::ImageTransport it_(nh_); + + image_pub_ = it_.advertise("dvs_rendering", 1); + std::cout<<" IM ALIVE?? 6"<<std::endl; + image_segmentation_pub_ = it_.advertise("dvs_segmentation", 1); + std::cout<<" shit cunt"<<std::endl; + + + //DEBUGGING + image_debug1_pub_ = it_.advertise("dvs_debug1", 1); + image_debug2_pub_ = it_.advertise("dvs_debug2", 1); + //NOT DEBUGGING + + //Initializing params for color meanshift + //computing image calibration + numRows=DVSH; numCols=DVSW; + mPixels=numRows*numCols; maxPixelDim=3; + + spaceDivider=7; timeDivider = 5; + maxIterNum=1; + tolFun=0.0001; + kernelFun[0] = 'g'; kernelFun[1] = 'a'; kernelFun[2] = 'u'; kernelFun[3] = 's'; + kernelFun[4] = 's'; kernelFun[5] = 'i'; kernelFun[6] = 'a'; kernelFun[7] = 'n'; + + //Initialize pointers + outputFeatures = NULL; imagePtr = NULL; pixelsPtr = NULL; + initializationPtr=new double[maxPixelDim*mPixels/4]; + + /*for (int i = 0; i < numRows; i++) + for (int j = 0; j < numCols; j++) + { + initializationPtr[i*numCols + j]=j/spaceDivider;//x + initializationPtr[mPixels+i*numCols+j]=i/spaceDivider;//y + initializationPtr[2*mPixels+i*numCols+j]=0;//img + + }*/ + + //Write xposition, yposition, and image in the same vector + for (int i = 0; i < numRows/2; i++) + for (int j = 0; j < numCols/2; j++) + { + initializationPtr[i*numCols/2 + j]=j/spaceDivider;//x + initializationPtr[mPixels/4+i*numCols/2+j]=i/spaceDivider;//y + initializationPtr[2*mPixels/4+i*numCols/2+j]=0;//img + + } + + //Initialize params for graph3d segmentation + sigma = 0.75; + k = 500; + min_region = (int)(numRows*numCols*0.01); + num_components = 0; + + //Initialization of random seed + srand(time(NULL));//Random seed initialization + //asm("rdtsc\n" + // "mov edi, eax\n" + // "call srand"); + + //Create first the RGB values and then assign it to the clusters + //(hopefully, this will keep some stability in the cluster colors along consecutive frames) + //Assume we won't have more than 50 clusters + for(int i=0; i<MAX_NUM_CLUSTERS; i++) + { + RGBColors.push_back(cv::Vec3b((uchar)random(), (uchar)random(), (uchar)random())); + //counterTrajectories.push_back(0);//initialize counter trajectories to all zeros + } + counterTrajectories=std::vector<int>(MAX_NUM_CLUSTERS,0); + + lastPositionClusterColor=0; + + //Initializing trajectories + trajectories = cv::Mat(numRows, numCols, CV_8UC3); + trajectories = cv::Scalar(128,128,128); + + //Initialize trajectory matrix + allTrajectories = new std::vector<cv::Point>[MAX_NUM_CLUSTERS]; + for(int i = 0; i < MAX_NUM_CLUSTERS; i++) + { + allTrajectories[i] = std::vector<cv::Point>(MAX_NUM_TRAJECTORY_POINTS); + } + prev_activeTrajectories=std::vector<int>(MAX_NUM_CLUSTERS,0); + + //Init Kalman filter + //createKalmanFilter(); + vector_of_kf=std::vector<cv::KalmanFilter>(MAX_NUM_CLUSTERS); + vector_of_meas=std::vector<cv::Mat>(MAX_NUM_CLUSTERS); + vector_of_state=std::vector<cv::Mat>(MAX_NUM_CLUSTERS); + for(int i=0; i<vector_of_kf.size(); i++) + createKalmanFilter(&(vector_of_kf[i]), &(vector_of_state[i]), &(vector_of_meas[i])); + + selectedTrajectory = -1; + //foundBlobs = false; + vector_of_foundBlobs=std::vector<bool>(MAX_NUM_CLUSTERS,false); + notFoundBlobsCount = 0; + //foundTrajectory=false; + foundTrajectory = std::vector<bool>(MAX_NUM_CLUSTERS, false); + //ticks = 0; + vector_of_ticks=std::vector<double> (MAX_NUM_CLUSTERS,0.0); + + //BG activity filtering + BGAFframe = cv::Mat(numRows, numCols, CV_32FC1); + BGAFframe =cv::Scalar(0.); +} + +Meanshift::~Meanshift() +{ + delete [] initializationPtr; + +#if KALMAN_FILTERING + //foutX.close(); + //foutX_estim.close(); + //foutT.close(); +#endif + image_pub_.shutdown(); + image_segmentation_pub_.shutdown(); + image_debug1_pub_.shutdown(); +} + +void Meanshift::cameraInfoCallback(const sensor_msgs::CameraInfo::ConstPtr& msg) +{ + std::cout<<" IM ALIVE?? 7"<<std::endl; + camera_matrix_ = cv::Mat(3, 3, CV_64F); + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + camera_matrix_.at<double>(cv::Point(i, j)) = msg->K[i+j*3]; + + dist_coeffs_ = cv::Mat(msg->D.size(), 1, CV_64F); + for (int i = 0; i < msg->D.size(); i++) + dist_coeffs_.at<double>(i) = msg->D[i]; +} + + +void Meanshift::createKalmanFilter(cv::KalmanFilter *kf, cv::Mat *state, cv::Mat *meas) +{ + std::cout<<" IM ALIVE?? 8"<<std::endl; + /* + * This implementation takes 6 states position, velocity, and dimensions of the bounding box + int stateSize = 6; + int measSize = 4; + int contrSize = 0; + + unsigned int type = CV_32F; + + //cv::KalmanFilter kf(stateSize, measSize, contrSize, type); + kf.init(stateSize, measSize, contrSize, type); + + cv::Mat state(stateSize, 1, type); // [x,y,v_x,v_y,w,h] + cv::Mat meas(measSize, 1, type); // [z_x,z_y,z_w,z_h] + // [E_x,E_y,E_v_x,E_v_y,E_w,E_h] + + // Transition State Matrix A + // Note: set dT at each processing step! + // [ 1 0 dT 0 0 0 ] + // [ 0 1 0 dT 0 0 ] + // [ 0 0 1 0 0 0 ] + // [ 0 0 0 1 0 0 ] + // [ 0 0 0 0 1 0 ] + // [ 0 0 0 0 0 1 ] + cv::setIdentity(kf.transitionMatrix); + + // Measure Matrix H + // [ 1 0 0 0 0 0 ] + // [ 0 1 0 0 0 0 ] + // [ 0 0 0 0 1 0 ] + // [ 0 0 0 0 0 1 ] + kf.measurementMatrix = cv::Mat::zeros(measSize, stateSize, type); + kf.measurementMatrix.at<float>(0) = 1.0f; + kf.measurementMatrix.at<float>(7) = 1.0f; + kf.measurementMatrix.at<float>(16) = 1.0f; + kf.measurementMatrix.at<float>(23) = 1.0f; + + // Process Noise Covariance Matrix Q + // [ Ex 0 0 0 0 0 ] + // [ 0 Ey 0 0 0 0 ] + // [ 0 0 Ev_x 0 0 0 ] + // [ 0 0 0 Ev_y 0 0 ] + // [ 0 0 0 0 Ew 0 ] + // [ 0 0 0 0 0 Eh ] + //cv::setIdentity(kf.processNoiseCov, cv::Scalar(1e-2)); + kf.processNoiseCov.at<float>(0) = 1e-2; + kf.processNoiseCov.at<float>(7) = 1e-2; + kf.processNoiseCov.at<float>(14) = 5.0f; + kf.processNoiseCov.at<float>(21) = 5.0f; + kf.processNoiseCov.at<float>(28) = 1e-2; + kf.processNoiseCov.at<float>(35) = 1e-2; + + // Measures Noise Covariance Matrix R + cv::setIdentity(kf.measurementNoiseCov, cv::Scalar(1e-1)); + */ + + + /* + * This implementation is only for one kalman filter + */ + int stateSize = 4; + int measSize = 2; + int contrSize = 0; + + unsigned int type = CV_32F; + + kf->init(stateSize, measSize, contrSize, type); + + //cv::Mat state(stateSize, 1, type); // [x,y,v_x,v_y] + //cv::Mat meas(measSize, 1, type); // [z_x,z_y] + state->create(stateSize,1,type); + meas->create(measSize,1,type); + // [E_x,E_y,E_v_x,E_v_y] + + + // Transition State Matrix A + // Note: set dT at each processing step! + // [ 1 0 dT 0 ] + // [ 0 1 0 dT] + // [ 0 0 1 0 ] + // [ 0 0 0 1 ] + cv::setIdentity(kf->transitionMatrix); + + // Measure Matrix H + // [ 1 0 0 0 ] + // [ 0 1 0 0 ] + kf->measurementMatrix = cv::Mat::zeros(measSize, stateSize, type); + kf->measurementMatrix.at<float>(0) = 1.0f; + kf->measurementMatrix.at<float>(5) = 1.0f; + + // Process Noise Covariance Matrix Q + // [ Ex 0 0 0 ] + // [ 0 Ey 0 0 ] + // [ 0 0 Ev_x 0 ] + // [ 0 0 0 Ev_y ] + //cv::setIdentity(kf.processNoiseCov, cv::Scalar(1e-2)); + kf->processNoiseCov.at<float>(0) = 1e-2;//original values + kf->processNoiseCov.at<float>(5) = 1e-2; + kf->processNoiseCov.at<float>(10) = 5.0f; + kf->processNoiseCov.at<float>(15) = 5.0f; + + kf->processNoiseCov.at<float>(0) = 1e-2; + kf->processNoiseCov.at<float>(5) = 1e-2; + kf->processNoiseCov.at<float>(10) = 7.0f; + kf->processNoiseCov.at<float>(15) = 7.0f; + + // Measures Noise Covariance Matrix R + cv::setIdentity(kf->measurementNoiseCov, cv::Scalar(1e-1)); +} + + + +void Meanshift::eventsCallback(const dvs_msgs::EventArray::ConstPtr& msg) +{ + std::cout<<" IM ALIVE?? 9"<<std::endl; + // only create image if at least one subscriber + if (image_pub_.getNumSubscribers() > 0) + { + cv_bridge::CvImage cv_image; + + if (display_method_ == RED_BLUE) + { + cv_image.encoding = "bgr8"; + + if (last_image_.rows == msg->height && last_image_.cols == msg->width) + { + last_image_.copyTo(cv_image.image); + used_last_image_ = true; + } + else + { + cv_image.image = cv::Mat(msg->height, msg->width, CV_8UC3); + cv_image.image = cv::Scalar(128, 128, 128); + } + + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + cv_image.image.at<cv::Vec3b>(cv::Point(x, y)) = ( + msg->events[i].polarity == true ? cv::Vec3b(255, 0, 0) : cv::Vec3b(0, 0, 255)); + } + } + else + { + cv_image.encoding = "mono8"; + cv_image.image = cv::Mat(msg->height, msg->width, CV_8U); + cv_image.image = cv::Scalar(128); + + cv::Mat on_events = cv::Mat(msg->height, msg->width, CV_8U); + on_events = cv::Scalar(0); + + cv::Mat off_events = cv::Mat(msg->height, msg->width, CV_8U); + off_events = cv::Scalar(0); + + // count events per pixels with polarity + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + if (msg->events[i].polarity == 1) + on_events.at<uint8_t>(cv::Point(x, y))++; + else + off_events.at<uint8_t>(cv::Point(x, y))++; + } + + // scale image + cv::normalize(on_events, on_events, 0, 128, cv::NORM_MINMAX, CV_8UC1); + cv::normalize(off_events, off_events, 0, 127, cv::NORM_MINMAX, CV_8UC1); + + cv_image.image += on_events; + cv_image.image -= off_events; + } + image_pub_.publish(cv_image.toImageMsg()); + } + + if (image_segmentation_pub_.getNumSubscribers() > 0) + { + cv_bridge::CvImage cv_segments; + //cv_bridge::CvImage cv_debug1; + //cv_bridge::CvImage cv_debug2; + + + //Doing color meanshift + cv::Mat timestamp_matrix = cv::Mat(numRows, numCols, CV_64F); + timestamp_matrix = cv::Scalar(0.); + cv::Mat timestamp_matrix_out; + + //Reading time of first event and saving it + //ROS_ERROR("Reading values from timestamp_matrix_out: %d", (int) msg->events.size()); + uint64_t first_timestamp = msg->events[0].ts.toNSec(); + // count events per pixels with polarity + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + double event_timestamp = (0.001*(double)(msg->events[i].ts.toNSec()-first_timestamp));//now in usecs + + if (msg->events[i].polarity == 1) + timestamp_matrix.at<double>(cv::Point(x, y))= event_timestamp*0.001; + else + timestamp_matrix.at<double>(cv::Point(x, y))=-event_timestamp*0.001; + } + + //First create the interface and + //cv_debug1.image =result_image; + //cv::Mat img_hist_equalized; + //cv::equalizeHist(result_image, img_hist_equalized); //equalize the histogram + //cv_debug1.image = img_hist_equalized; + + + + //POISSON SOLVER IMPLEMENTATION + /*----------------------------------------------------------------------------* / + cv::Mat debugIm1= cv::Mat(numRows, numCols, CV_8UC1); + + double min, max; + cv::minMaxLoc(timestamp_matrix, &min, &max); + + cv::normalize(timestamp_matrix, debugIm1, 0, 255, cv::NORM_MINMAX, CV_8UC1); + + // Here, we are assuming that our image is a gradient already (gx and gy) + cv::Mat gxx = cv::Mat(numRows, numCols, CV_64F); + cv::Mat gyy = cv::Mat(numRows, numCols, CV_64F); + + cv::Mat tmp; + debugIm1.convertTo(tmp, CV_64F); + tmp = (tmp/255)*(max-min)+min; + + + lapx(tmp, gxx); + lapy(tmp, gyy); + + cv::Mat lapfnc = cv::Mat(numRows, numCols, CV_64F); + cv::Mat fcos = cv::Mat(numRows, numCols, CV_64F); + cv::Mat denom = cv::Mat(numRows, numCols, CV_64F); + cv::Mat output = cv::Mat(numRows, numCols, CV_64F); + lapfnc = gxx+gyy; + cv::dct(lapfnc, fcos); + + cv::Mat1i XX, YY; + cv::Mat XX_bis, YY_bis; + meshgridTest(cv::Range(0,numCols-1), cv::Range(0, numRows-1), XX, YY); + + XX.convertTo(XX_bis, CV_64F); YY.convertTo(YY_bis, CV_64F); + XX_bis = CV_PI*XX_bis/numCols; YY_bis=CV_PI*YY_bis/numRows; + + parallel_for_(cv::Range(0,XX_bis.rows), Parallel_pixel_cosine(XX_bis)); + parallel_for_(cv::Range(0,YY_bis.rows), Parallel_pixel_cosine(YY_bis)); + + denom = 2*XX_bis-2 + 2*YY_bis-2; + + double first_elem =fcos.at<double>(cv::Point(0, 0)); + cv::divide(fcos, denom, fcos); + fcos.at<double>(cv::Point(0, 0))=first_elem; // remove the Inf + + cv::idct(fcos, output); + double min_bis, max_bis; + cv::minMaxLoc(output, &min_bis, &max_bis); + output = output - min_bis; + cv::Mat result_image, output_norm; + cv::normalize(output, output_norm, 0, 255, cv::NORM_MINMAX, CV_8UC1); + + cv::medianBlur(output_norm,result_image,3); + /*----------------------------------------------------------------------------*/ + //Alternatively, one can use only the time + cv::Mat result_image; + cv::normalize(timestamp_matrix, result_image, 0, 255, cv::NORM_MINMAX, CV_8UC1); + /*----------------------------------------------------------------------------*/ + + //cv::Mat kk1; + //result_image.convertTo(kk1, CV_64F); + //writeMatToFile(kk1,"/home/fran/kk1.txt"); + + //cv_debug1.encoding = "mono8"; + //cv_debug1.image = result_image; + //image_debug1_pub_.publish(cv_debug1.toImageMsg()); + + cv::Mat temporalIm, temporalImSubsampled; + result_image.convertTo(temporalIm, CV_64F); + temporalIm = temporalIm/timeDivider; + cv::pyrDown(temporalIm, temporalImSubsampled, cv::Size(numCols/2, numRows/2)); + //Initialize positions (only once) + outputFeatures=new double[maxPixelDim*mPixels/4]; + pixelsPtr=new double[maxPixelDim*mPixels/4]; + imagePtr=new double[mPixels/4]; + + memcpy(pixelsPtr, initializationPtr, maxPixelDim*mPixels/4*sizeof(double)); //copy event the 0s image + memcpy(pixelsPtr+2*mPixels/4, (void*)(temporalImSubsampled.data), mPixels/4*sizeof(double)); //copy event the 0s image + memcpy(imagePtr, (void*)(temporalImSubsampled.data), mPixels/4*sizeof(double)); //copy event the 0s image + + //extract the features + colorMeanShiftFilt(outputFeatures, pixelsPtr, mPixels/4, maxPixelDim, imagePtr, \ + numRows/2, numCols/2, spaceDivider, kernelFun, maxIterNum, tolFun); + + cv::Mat meanshiftIm; + cv::Mat meanshiftIm_small = cv::Mat(numRows/2, numCols/2, CV_64F, outputFeatures+2*mPixels/4); + meanshiftIm_small = meanshiftIm_small*timeDivider; + cv::pyrUp(meanshiftIm_small, meanshiftIm, cv::Size(numCols, numRows)); + + //cv::Mat kk = cv::Mat(numRows, numCols, CV_64F, imagePtr); + //kk = kk*timeDivider; + //writeMatToFile(kk,"/home/fran/imagePtr.txt"); + + //do the segmentation +// cv::Mat filtered_im = cv::Mat(numRows, numCols, CV_64F, outputFeatures+2*mPixels); +// filtered_im = filtered_im*timeDivider; + cv::Mat meanshiftImNormalized; + //meanshift_im.convertTo(meanshift_im_normalized,CV_8UC1); + cv::normalize(meanshiftIm, meanshiftImNormalized, 0, 255, cv::NORM_MINMAX, CV_8UC1); + + //cv_debug2.encoding = "mono8"; + //cv_debug2.image = meanshift_im_normalized; + //image_debug2_pub_.publish(cv_debug2.toImageMsg()); + + //meanshift_im_normalized= cv::imread("/home/fran/mug.pgm", CV_LOAD_IMAGE_GRAYSCALE); + + //tmp has the values that are non-zero + + cv_segments.encoding = "bgr8"; + cv_segments.image =cv::Mat(numRows, numCols, CV_8UC3); + //cv_segments.image =cv::Mat(128, 128, CV_8UC3); + im2segment(meanshiftImNormalized, cv_segments.image, sigma, k, min_region, &num_components); + image_segmentation_pub_.publish(cv_segments.toImageMsg()); + + //cv::Mat mask; + //mask = (abs(timestamp_matrix) > 1E-6); // Puts 255 wherever it is true + //mask.convertTo(mask, CV_64F); + //writeMatToFile(mask,"/home/fran/mask.txt"); + + //cv::Mat finalOutput; + //cv::bitwise_and(cv_segments.image, cv::Scalar(255,255,255), finalOutput, mask); + //cv_segments.image = finalOutput; + //image_debug2_pub_.publish(cv_segments.toImageMsg()); + //------------------------------------------------------------------------------------- + + delete[] imagePtr; + delete [] outputFeatures; + delete [] pixelsPtr; + } +} + +/*void Meanshift::eventsCallback_simple(const dvs_msgs::EventArray::ConstPtr& msg) +{ + // only create image if at least one subscriber + if (image_pub_.getNumSubscribers() > 0) + { + cv_bridge::CvImage cv_image; + + if (display_method_ == RED_BLUE) + { + cv_image.encoding = "bgr8"; + + if (last_image_.rows == msg->height && last_image_.cols == msg->width) + { + last_image_.copyTo(cv_image.image); + used_last_image_ = true; + } + else + { + cv_image.image = cv::Mat(msg->height, msg->width, CV_8UC3); + cv_image.image = cv::Scalar(128, 128, 128); + } + + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + cv_image.image.at<cv::Vec3b>(cv::Point(x, y)) = ( + msg->events[i].polarity == true ? cv::Vec3b(255, 0, 0) : cv::Vec3b(0, 0, 255)); + } + } + else + { + cv_image.encoding = "mono8"; + cv_image.image = cv::Mat(msg->height, msg->width, CV_8U); + cv_image.image = cv::Scalar(128); + + cv::Mat on_events = cv::Mat(msg->height, msg->width, CV_8U); + on_events = cv::Scalar(0); + + cv::Mat off_events = cv::Mat(msg->height, msg->width, CV_8U); + off_events = cv::Scalar(0); + + // count events per pixels with polarity + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + if (msg->events[i].polarity == 1) + on_events.at<uint8_t>(cv::Point(x, y))++; + else + off_events.at<uint8_t>(cv::Point(x, y))++; + } + + // scale image + cv::normalize(on_events, on_events, 0, 128, cv::NORM_MINMAX, CV_8UC1); + cv::normalize(off_events, off_events, 0, 127, cv::NORM_MINMAX, CV_8UC1); + + cv_image.image += on_events; + cv_image.image -= off_events; + } + image_pub_.publish(cv_image.toImageMsg()); + } + + if (image_segmentation_pub_.getNumSubscribers() > 0) + { + cv_bridge::CvImage cv_segments; + + //Doing color meanshift + cv::Mat diffTimestampMatrix = cv::Mat(numRows, numCols, CV_64F, cv::Scalar::all(0.)); + cv::Mat timestampMatrix = cv::Mat(numRows, numCols, CV_64F, cv::Scalar::all(0.)); + + uint64_t first_timestamp = msg->events[0].ts.toNSec(); + double final_timestamp = (1E-6*(double)(msg->events[(msg->events.size())-1].ts.toNSec()-first_timestamp)); + + // count events per pixels with polarity + cv::Mat data=cv::Mat(3, msg->events.size(), CV_64F, cv::Scalar::all(0.)); + int counter = 0; + + //std::ofstream foutX("/home/fran/xpos.txt"); + //std::ofstream foutY("/home/fran/ypos.txt"); + //std::ofstream foutTime("/home/fran/timestamp.txt"); + + for (int i = 0; i < msg->events.size(); i++) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + double event_timestamp = (1E-6*(double)(msg->events[i].ts.toNSec()-first_timestamp));//now in usecs + + //if (timestampMatrix.at<double>(cv::Point(x,y))> epsilon) + // diffTimestampMatrix.at<double>(cv::Point(x, y)) = event_timestamp -timestampMatrix.at<double>(cv::Point(x, y)); + //timestampMatrix.at<double>(cv::Point(x, y))= event_timestamp; + + if (event_timestamp < 15) + { + data.at<double>(cv::Point(i, 0))= (double)x/numCols; + data.at<double>(cv::Point(i, 1))= (double)y/numRows; + data.at<double>(cv::Point(i, 2))= event_timestamp/final_timestamp;//normalized + counter++; + } + else + { + //ROS_ERROR_STREAM("I'm using "<<counter<<" out of "<<msg->events.size()); + break; + } + //foutX<<x<<"\t"; foutY<<y<<"\t"; foutTime<<event_timestamp<<"\t"; + } + //foutX.close(); foutY.close(); foutTime.close(); + +/* + cv::Mat data=cv::Mat(3, 66, CV_64F, cv::Scalar::all(0.)); + int counter = 0; + std::ifstream foutX("/home/fran/xpos.txt"); + std::ifstream foutY("/home/fran/ypos.txt"); + std::ifstream foutTime("/home/fran/timestamp.txt"); + final_timestamp = 9.963; + for (int i = 0; i < 66; i++) + { + double x, y, event_timestamp; + foutX>>x; foutY>>y; foutTime>>event_timestamp; + data.at<double>(cv::Point(i, 0))= x/numCols; + data.at<double>(cv::Point(i, 1))= y/numRows; + data.at<double>(cv::Point(i, 2))= event_timestamp/final_timestamp; + } + foutX.close(); foutY.close(); foutTime.close(); +* / + + //---------------------------------------------------------------------------- + //Alternatively, one can use only the time + //cv::Mat result_image; + //cv::normalize(diffTimestampMatrix, result_image, 0, 255, cv::NORM_MINMAX, CV_8UC1); + //---------------------------------------------------------------------------- + + cv::Mat clusterCenters; + cv::Mat segmentation=cv::Mat(numRows, numCols, CV_8UC3); + segmentation = cv::Scalar(128,128,128); + + std::vector<double> clustCentX, clustCentY, clustCentZ; + std::vector<int> point2Clusters; + double bandwidth = 0.2; + std::vector<cv::Vec3b> RGBColors; + cv::RNG rng(12345); + + //ROS_ERROR_STREAM("Just before meanshift "<<msg->events.size()); + meanshiftCluster_Gaussian(data, &clustCentX, &clustCentY, &clustCentZ, &point2Clusters, bandwidth); + + //Now, draw the different segments with a color + for(int i=0; i<clustCentX.size(); i++) + RGBColors.push_back(cv::Vec3b((uchar)random(), (uchar)random(), (uchar)random())); + + counter =0; + for (int i = 0; i < msg->events.size(); i++) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + double ts = (1E-6*(double)(msg->events[i].ts.toNSec()-first_timestamp));//now in usecs + + if(ts<15) + { + segmentation.at<cv::Vec3b>(cv::Point(x,y))=RGBColors[point2Clusters[i]]; + counter++; + } + else + { + break; + } + //ROS_ERROR_STREAM("segmentation["<<x<<","<<y<<"] = "<<RGBColors[point2Clusters[i]]); + } + + cv_segments.encoding = "bgr8"; + cv_segments.image =segmentation; + image_segmentation_pub_.publish(cv_segments.toImageMsg()); + //std::cin.ignore(); + + //Saving RGB image + //if (counterGlobal>20) + //{ + // char filename[80]; + // sprintf(filename,"/home/fran/RGB_%0d.png", counterGlobal+1); + // cv::imwrite(filename , segmentation); + // exit(0); + //} + //counterGlobal++; + //------------------------------------------------------------------------------------- + + } +}*/ + +void Meanshift::eventsCallback_simple(const dvs_msgs::EventArray::ConstPtr& msg) +{ + //std::cout<<" IM ALIVE?? 10"<<std::endl; + // only create image if at least one subscriber + if (image_pub_.getNumSubscribers() > 0) + { + std::cout<<" Wanky shit demon"<<std::endl; + cv_bridge::CvImage cv_image; + + if (display_method_ == RED_BLUE) + { + cv_image.encoding = "bgr8"; + + if (last_image_.rows == msg->height && last_image_.cols == msg->width) + { + last_image_.copyTo(cv_image.image); + used_last_image_ = true; + } + else + { + cv_image.image = cv::Mat(msg->height, msg->width, CV_8UC3); + cv_image.image = cv::Scalar(128, 128, 128); + } + + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + cv_image.image.at<cv::Vec3b>(cv::Point(x, y)) = ( + msg->events[i].polarity == true ? cv::Vec3b(255, 0, 0) : cv::Vec3b(0, 0, 255)); + } + + //Write the total number of events + //foutX<<msg->events.size()<<std::endl; + } + else + { + std::cout<<" Wanky shit demon 2"<<std::endl; + cv_image.encoding = "mono8"; + cv_image.image = cv::Mat(msg->height, msg->width, CV_8U); + cv_image.image = cv::Scalar(128); + + cv::Mat on_events = cv::Mat(msg->height, msg->width, CV_8U); + on_events = cv::Scalar(0); + + cv::Mat off_events = cv::Mat(msg->height, msg->width, CV_8U); + off_events = cv::Scalar(0); + + // count events per pixels with polarity + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + + if (msg->events[i].polarity == 1) + on_events.at<uint8_t>(cv::Point(x, y))++; + else + off_events.at<uint8_t>(cv::Point(x, y))++; + } + + // scale image + cv::normalize(on_events, on_events, 0, 128, cv::NORM_MINMAX, CV_8UC1); + cv::normalize(off_events, off_events, 0, 127, cv::NORM_MINMAX, CV_8UC1); + + cv_image.image += on_events; + cv_image.image -= off_events; + } + image_pub_.publish(cv_image.toImageMsg()); + } + +/* + // only create image if at least one subscriber + if (image_debug1_pub_.getNumSubscribers() > 0) + { + cv_bridge::CvImage cv_image; + + if (display_method_ == RED_BLUE) + { + cv_image.encoding = "bgr8"; + + if (last_image_.rows == msg->height && last_image_.cols == msg->width) + { + last_image_.copyTo(cv_image.image); + used_last_image_ = true; + } + else + { + cv_image.image = cv::Mat(msg->height, msg->width, CV_8UC3); + cv_image.image = cv::Scalar(128, 128, 128); + } + + if(firstevent) + { + firsttimestamp = (1E-6*(double)(msg->events[0].ts.toNSec())); + firstevent = false; + } + + double maxTs; + int posx, posy; + double usTime = 16.0; + double ts; + for (int i = 0; i < msg->events.size(); ++i) + { + const int x = msg->events[i].x; + const int y = msg->events[i].y; + ts = (1E-6*(double)(msg->events[i].ts.toNSec())) - firsttimestamp; +#if BG_FILTERING + //BGAFframe.at<float>(cv::Point(x,y))=(float)(1E-6*(double)(msg->events[i].ts.toNSec())); + BGAFframe.at<float>(cv::Point(x,y))=0.; + maxTs = -1; + //ROS_ERROR_STREAM("NEW EVENT "<<x<<","<<y<<":"<<ts); + for(int ii=-1; ii<=1; ii++) + for(int jj=-1; jj<=1; jj++) + { + posx = x + ii; + posy = y + jj; + if(posx<0) + posx = 0; + if(posy<0) + posy=0; + if(posx>numRows-1) + posx = numRows-1; + if(posy>numCols-1) + posy = numCols-1; + + if(BGAFframe.at<float>(cv::Point(posx,posy)) > maxTs) + maxTs = BGAFframe.at<float>(cv::Point(posx,posy)); + + //ROS_ERROR_STREAM(posx<<","<<posy<<":"<<BGAFframe.at<float>(cv::Point(posx,posy))); + } + //ROS_ERROR_STREAM("maxTs: "<<maxTs); + BGAFframe.at<float>(cv::Point(x,y))=ts; + //ROS_ERROR_STREAM(BGAFframe.at<float>(cv::Point(x,y)) - maxTs); + + if(BGAFframe.at<float>(cv::Point(x,y)) >= (maxTs + usTime)) + { + continue; + //ROS_ERROR_STREAM("HERE"); + } + +#endif + cv_image.image.at<cv::Vec3b>(cv::Point(x, y)) = ( + msg->events[i].polarity == true ? cv::Vec3b(255, 0, 0) : cv::Vec3b(0, 0, 255)); + } + //ROS_ERROR_STREAM("DONE--------------------------------------------"); + + //Write the total number of events + //foutX<<msg->events.size()<<std::endl; + } + image_debug1_pub_.publish(cv_image.toImageMsg()); + } +*/ + + + if (image_segmentation_pub_.getNumSubscribers() > 0) + { + //std::cout<<" Wanky shit demon 3"<<std::endl; + cv_bridge::CvImage cv_segments; + + //Doing color meanshift + //cv::Mat diffTimestampMatrix = cv::Mat(numRows, numCols, CV_64F, cv::Scalar::all(0.)); + //cv::Mat timestampMatrix = cv::Mat(numRows, numCols, CV_64F, cv::Scalar::all(0.)); + + uint64_t first_timestamp = msg->events[0].ts.toNSec(); + double final_timestamp = (1E-6*(double)(msg->events[(msg->events.size())-1].ts.toNSec()-first_timestamp)); + std::vector<bool> activeEvents(msg->events.size()); + + int counterIn = 0; + int counterOut = 0; + + int beginEvent = 0; + int packet; + if(DVSW==240) + packet = 1800; + else + packet = 1500; + //ROS_ERROR_STREAM("Before while"); + + + while(beginEvent < msg->events.size()) + { + std::cout<<" Wanky shit demon 4"<<std::endl; + //if(msg->events.size()>15e3) + //ROS_ERROR_STREAM("BEGIN packet "<<beginEvent); + //SELECT SMALL PACKETS OF MAXIMUM 1500 events + counterIn = 0; + counterOut = 0; + //ROS_ERROR_STREAM("Computing events ["<<beginEvent<<","<<min(beginEvent+packet, msg->events.size())<<"]"); + //ROS_ERROR_STREAM("SIZE of current package is "<<msg->events.size()<<"];"); + + // count events per pixels with polarity + cv::Mat data=cv::Mat(3, min(packet, msg->events.size()-beginEvent), CV_64F, cv::Scalar::all(0.)); + + //std::ofstream foutX("/home/fran/xpos.txt"); + //std::ofstream foutY("/home/fran/ypos.txt"); + //std::ofstream foutTime("/home/fran/timestamp.txt"); + + //Filter events + //cv::Mat BGAFframe = cv::Mat(numRows, numCols, CV_32FC1); + //frame =cv::Scalar(-1); + + if(firstevent) + { + firsttimestamp = (1E-6*(double)(msg->events[10].ts.toNSec())); + firstevent = false; + } + + double maxTs; + int posx, posy; + double usTime = 10.0; + double ts; + + + int size = msg->events.size(); + for (int i = beginEvent; i < min(beginEvent+packet, msg->events.size()); i++) + { + + //SELECT SMALL PACKETS OF MAXIMUM 1000 events + const int x = msg->events[counterIn].x; + const int y = msg->events[counterIn].y; + + double event_timestamp = (1E-6*(double)(msg->events[counterIn].ts.toNSec()-first_timestamp));//now in usecs + + ts = (1E-6*(double)(msg->events[i].ts.toNSec())) - firsttimestamp; +#if BG_FILTERING + //BGAFframe.at<float>(cv::Point(x,y))=(float)(1E-6*(double)(msg->events[i].ts.toNSec())); + BGAFframe.at<float>(cv::Point(x,y))=0.; + maxTs = -1; + //calculate maximum in a 3x3 neighborhood + for(int ii=-1; ii<=1; ii++) + for(int jj=-1; jj<=1; jj++) + { + posx = x + ii; + posy = y + jj; + if(posx<0) + posx = 0; + if(posy<0) + posy=0; + if(posx>numRows-1) + posx = numRows-1; + if(posy>numCols-1) + posy = numCols-1; + + if(BGAFframe.at<float>(cv::Point(posx,posy)) > maxTs) + maxTs = BGAFframe.at<float>(cv::Point(posx,posy)); + } + + BGAFframe.at<float>(cv::Point(x,y))=ts; + //if nothing happened in usTime, remove the event + if(BGAFframe.at<float>(cv::Point(x,y)) >= (maxTs + usTime)) + { + activeEvents.at(counterIn)=false; + counterIn++; + } + else + { +#endif + std::cout<<" Wanky shit demon 6: " << i << "size of message: " << size <<std::endl; + data.at<double>(cv::Point(counterOut, 0))= (double)x/numCols; + data.at<double>(cv::Point(counterOut, 1))= (double)y/numRows; + //data.at<double>(cv::Point(counter, 2))= event_timestamp/final_timestamp;//normalized + double tau = 10000; + data.at<double>(cv::Point(counterOut, 2))= exp(-(final_timestamp-event_timestamp)/tau);//normalized + activeEvents.at(counterIn)=true; + counterIn++; + counterOut++; +#if BG_FILTERING + } +#endif + +std::cout<<" Wanky shit demon 5: " << i << "counterOut: " << counterIn <<std::endl; + + //foutX<<x<<"\t"; foutY<<y<<"\t"; foutTime<<event_timestamp<<"\t"; + } + std::cout<<"Wank on the shit"<<std::endl; + double last_timestamp = (1E-6*(double)(msg->events[counterIn-1].ts.toNSec()));//now in usecs + //foutX.close(); foutY.close(); foutTime.close(); + + cv::Mat clusterCenters; + cv::Mat segmentation=cv::Mat(numRows, numCols, CV_8UC3); + segmentation = cv::Scalar(128,128,128); + + cv::Mat traj = cv::Mat(numRows, numCols, CV_8UC3); + traj = cv::Scalar(128,128,128); + + std::vector<double> clustCentX, clustCentY, clustCentZ; + std::vector<int> point2Clusters; + std::vector<int> positionClusterColor; + std::vector<int> assign_matches; + + + //double bandwidth = 0.05; + double bandwidth = 0.15; + //double bandwidth = 0.15; + //double bandwidth = 0.20; + //double bandwidth = 0.25; + //double bandwidth = 0.50; + //cv::RNG rng(12345); + +/* if(counterGlobal==0) + { + //clock_t start, end; + //double elapsed; + //start = clock(); + //clustCentZ_old = clustCentZ; + + meanshiftCluster_Gaussian(data, &clustCentX, &clustCentY, &clustCentZ, &point2Clusters, bandwidth); + + assignClusterColor(&positionClusterColor, clustCentX.size(), assign_matches, prev_positionClusterColor); //assign new colors to clusters + + prev_clustCentX = clustCentX; + prev_clustCentY = clustCentY; + prev_positionClusterColor = positionClusterColor; + //std::vector<int> checkvector (clustCentX.size(), -1); + //ROS_ERROR_STREAM("Total number of clusters is "<<clustCentX.size()); + + + //end = clock(); + //elapsed = ((double) (end - start)) / CLOCKS_PER_SEC; + //ROS_ERROR_STREAM("Num. packets = "<<data.cols<<" elapsed time = "<<elapsed<<". Time/packet = "<<elapsed/data.cols); + + //Moved to initialization + //Now, draw the different segments with a color + //for(int i=0; i<clustCentX.size(); i++) + // RGBColors.push_back(cv::Vec3b((uchar)random(), (uchar)random(), (uchar)random())); + + counter =0; + for (int i = beginEvent; i < min(beginEvent+packet, msg->events.size()); i++) + { + const int x = msg->events[counter].x; + const int y = msg->events[counter].y; + double ts = (1E-6*(double)(msg->events[counter].ts.toNSec()-first_timestamp));//now in usecs + + //if(ts<15) + //{ + //segmentation.at<cv::Vec3b>(cv::Point(x,y))=RGBColors[point2Clusters[counter]]; + //segmentation.at<cv::Vec3b>(cv::Point(x,y))=RGBColors[(positionClusterColor[point2Clusters[counter]])%MAX_NUM_CLUSTERS]; + segmentation.at<cv::Vec3b>(cv::Point(x,y))=RGBColors[(positionClusterColor[point2Clusters[counter]])&MAX_NUM_CLUSTERS]; //cheaper than % (mod operation) + //} + //else + // break; + counter++; + } + } + else + { + +*/ + + //fouttotalproc<<min(packet, msg->events.size()-beginEvent)<<std::endl; +std::cout<<"Wank on the shit 2"<<std::endl; + meanshiftCluster_Gaussian(data, &clustCentX, &clustCentY, &clustCentZ, &point2Clusters, bandwidth); +std::cout<<"Wank on the shit 3"<<std::endl; + //Assign new color or use color from previous clusters? + //if(counterGlobal>0)//not the first time + findClosestCluster(&assign_matches, clustCentX, clustCentY, prev_clustCentX, prev_clustCentY); //no match when clustID is -1 +std::cout<<"Wank on the shit 4"<<std::endl; + //assignClusterColor(&positionClusterColor, clustCentX.size(), assign_matches, prev_positionClusterColor); //assign new colors to clusters + assignClusterColor(&positionClusterColor, clustCentX.size(), assign_matches, prev_positionClusterColor, prev_activeTrajectories); //assign new colors to clusters +std::cout<<"Wank on the shit 5"<<std::endl; + //foutnumclust<<clustCentX.size()<<std::endl; + + int tmpColorPos; + float estimClustCenterX=-1., estimClustCenterY=-1.; + //std::vector<int> activeTrajectories(MAX_NUM_CLUSTERS,0); + std::vector<int> activeTrajectories; + + if(point2Clusters.size()>400) //update positions only when there is enough change (>25%) + { + std::cout<<" Wanky shit demon 6"<<std::endl; + for(int i=0; i<clustCentX.size(); i++) + { + estimClustCenterX=-1., estimClustCenterY=-1.; + + tmpColorPos = (positionClusterColor[i])&(MAX_NUM_CLUSTERS-1); + + //Check if the new position is being used + /*int idx = 0; + for (int idx=0; idx<prev_activeTrajectories.size(); idx++) + if(tmpColorPos == prev_activeTrajectories[idx]) + break;*/ + std::vector<int>::iterator it; + it = find (prev_activeTrajectories.begin(), prev_activeTrajectories.end(), tmpColorPos); + + if(it==prev_activeTrajectories.end())//if the element tmpcolorpos is not found in the vector + { + //Initialize the trajectory (just the counter) + //allTrajectories[tmpColorPos] = std::vector<cv::Point>(MAX_NUM_TRAJECTORY_POINTS); + counterTrajectories[tmpColorPos]=0; + +#if KALMAN_FILTERING + foundTrajectory[tmpColorPos] = false; + createKalmanFilter(&(vector_of_kf[tmpColorPos]), &(vector_of_state[tmpColorPos]), &(vector_of_meas[tmpColorPos])); + vector_of_foundBlobs[tmpColorPos]=false; + vector_of_ticks[tmpColorPos]=0.0; +#endif + } + + /* + if(prev_activeTrajectories[tmpColorPos]==0) //TODO: when the cluster is tracked all the time, it is active when I go back with &MAX_NUM_CLUSTERS + { + //Initialize the trajectory (just the counter) + //allTrajectories[tmpColorPos] = std::vector<cv::Point>(MAX_NUM_TRAJECTORY_POINTS); + counterTrajectories[tmpColorPos]=0; + }*/ + +#if KALMAN_FILTERING + if(counterTrajectories[tmpColorPos]>25 & !foundTrajectory[tmpColorPos]) + { + //selectedTrajectory = tmpColorPos; + foundTrajectory[tmpColorPos] = true; + } + //if(foundTrajectory[tmpColorPos] & selectedTrajectory == tmpColorPos) //More than 25 points in the trajectory, start w/ KF + if(foundTrajectory[tmpColorPos]) //More than 25 points in the trajectory, start w/ KF + { + //double precTick = ticks; + //ticks = (double) cv::getTickCount(); + //double dT = (ticks - precTick) / cv::getTickFrequency(); //seconds + + /* In case we use only 1 kalman filter + if((last_timestamp - ticks) > 1) + { + double precTick = ticks; + ticks = last_timestamp; + double dT = (ticks - precTick)/1000; //seconds + + if (foundBlobs) + { + // >>>> Matrix A + kf.transitionMatrix.at<float>(2) = dT; + kf.transitionMatrix.at<float>(7) = dT; + // <<<< Matrix A + state = kf.predict(); + estimClustCenterX = state.at<float>(0); + estimClustCenterY = state.at<float>(1); + } + + meas.at<float>(0) = clustCentX[i]*DVSW; + meas.at<float>(1) = clustCentY[i]*DVSH; //[z_x, z_y] + + if (!foundBlobs) // First detection! + { + // >>>> Initialization + kf.errorCovPre.at<float>(0) = 1; // px + kf.errorCovPre.at<float>(5) = 1; // px + kf.errorCovPre.at<float>(10) = 2; + kf.errorCovPre.at<float>(15) = 2; + + state.at<float>(0) = meas.at<float>(0); + state.at<float>(1) = meas.at<float>(1); + state.at<float>(2) = 0; + state.at<float>(3) = 0; //[z_x, z_y, v_x, v_y] + // <<<< Initialization + + kf.statePost = state; + + foundBlobs = true; + } + else + kf.correct(meas); // Kalman Correction + + if(estimClustCenterX>=0.) //initialized to -1 + { + //ROS_ERROR_STREAM("Estimated point = ["<<estimClustCenterX<<", "<<estimClustCenterY<<"];"); + //ROS_ERROR_STREAM("Measured point = ["<<clustCentX[i]<<", "<<clustCentY[i]<<"];"); + cv::circle(trajectories, cv::Point(clustCentX[i]*DVSW, clustCentY[i]*DVSH), 2, cv::Scalar( 0, 0, 255 ),-1,8); + cv::circle(trajectories, cv::Point(estimClustCenterX, estimClustCenterY), 2, cv::Scalar( 255, 0, 0),-1,8); + foutX<<clustCentX[i]*DVSW<<" "<<clustCentY[i]*DVSH<<std::endl; + foutX_estim<<estimClustCenterX<<" "<<estimClustCenterY<<std::endl; + foutT<<dT<<std::endl; + } + } + */ + + if((last_timestamp - vector_of_ticks[tmpColorPos]) > 1) + { + double precTick = vector_of_ticks[tmpColorPos]; + vector_of_ticks[tmpColorPos] = last_timestamp; + double dT = (vector_of_ticks[tmpColorPos] - precTick)/1000; //seconds + //if (foundBlobs) + if(vector_of_foundBlobs[tmpColorPos]) + { + // >>>> Matrix A + vector_of_kf[tmpColorPos].transitionMatrix.at<float>(2) = dT; + vector_of_kf[tmpColorPos].transitionMatrix.at<float>(7) = dT; + // <<<< Matrix A + vector_of_state[tmpColorPos] = vector_of_kf[tmpColorPos].predict(); + estimClustCenterX = vector_of_state[tmpColorPos].at<float>(0); + estimClustCenterY = vector_of_state[tmpColorPos].at<float>(1); + } + vector_of_meas[tmpColorPos].at<float>(0) = clustCentX[i]*DVSW; + vector_of_meas[tmpColorPos].at<float>(1) = clustCentY[i]*DVSH; //[z_x, z_y] + + + //if (!foundBlobs) // First detection! + if(!vector_of_foundBlobs[tmpColorPos]) + { + // >>>> Initialization + vector_of_kf[tmpColorPos].errorCovPre.at<float>(0) = 1; // px + vector_of_kf[tmpColorPos].errorCovPre.at<float>(5) = 1; // px + vector_of_kf[tmpColorPos].errorCovPre.at<float>(10) = 2; + vector_of_kf[tmpColorPos].errorCovPre.at<float>(15) = 2; + + vector_of_state[tmpColorPos].at<float>(0) = vector_of_meas[tmpColorPos].at<float>(0); + vector_of_state[tmpColorPos].at<float>(1) = vector_of_meas[tmpColorPos].at<float>(1); + vector_of_state[tmpColorPos].at<float>(2) = 0; + vector_of_state[tmpColorPos].at<float>(3) = 0; //[z_x, z_y, v_x, v_y] + // <<<< Initialization + + vector_of_kf[tmpColorPos].statePost = vector_of_state[tmpColorPos]; + + //foundBlobs = true; + vector_of_foundBlobs[tmpColorPos]=true; + } + else + vector_of_kf[tmpColorPos].correct(vector_of_meas[tmpColorPos]); // Kalman Correction + + if(estimClustCenterX>=0.) //initialized to -1 + { + //ROS_ERROR_STREAM("Estimated difference = ["<<abs(estimClustCenterX/DVSW -clustCentX[i]) <<", "<<abs(estimClustCenterY/DVSH-clustCentY[i])<<"];"); + //ROS_ERROR_STREAM("Estimated point = ["<<estimClustCenterX<<", "<<estimClustCenterY<<"];"); + //ROS_ERROR_STREAM("Measured point = ["<<clustCentX[i]<<", "<<clustCentY[i]<<"];"); + //cv::circle(trajectories, cv::Point(clustCentX[i]*DVSW, clustCentY[i]*DVSH), 2, cv::Scalar( 0, 0, 255 ),-1,8); + //cv::circle(trajectories, cv::Point(estimClustCenterX, estimClustCenterY), 2, cv::Scalar( 255, 0, 0),-1,8); + + //foutX<<tmpColorPos<<" "<<clustCentX[i]*DVSW<<" "<<clustCentY[i]*DVSH<<" "<<estimClustCenterX<<" "<<estimClustCenterY<<std::endl; + + //foutX_estim<<estimClustCenterX<<" "<<estimClustCenterY<<std::endl; + //foutT<<dT<<std::endl; + //foutX<<"Estimated difference = ["<<abs(estimClustCenterX/DVSW -clustCentX[i]) <<", "<<abs(estimClustCenterY/DVSH-clustCentY[i])<<"];"<<std::endl; + + // !!!!!!CAREFUL **************************************************************************************** + //ACTIVATE THIS !!!!! + //clustCentX[i] = estimClustCenterX/DVSW; + //clustCentY[i] = estimClustCenterY/DVSH; + // CAREFUL **************************************************************************************** + } + } + } +#endif + + cv::Point end(clustCentX[i]*DVSW, clustCentY[i]*DVSH); +/* +#if KALMAN_FILTERING + //frame, event, colorCluster, X,Y, filtX, filtY + foutX<<counterGlobal+1<<" "<<(double)(1E-6*(msg->events[beginEvent].ts.toNSec()-msg->events[0].ts.toNSec()))<<" " <<tmpColorPos<<" "<<clustCentX[i]*DVSW<<" "<<clustCentY[i]*DVSH<<" "<<estimClustCenterX<<" "<<estimClustCenterY<<std::endl; +#endif +*/ + + allTrajectories[tmpColorPos][(counterTrajectories[tmpColorPos]) & (MAX_NUM_TRAJECTORY_POINTS-1)]=end; + counterTrajectories[tmpColorPos]++; + //activeTrajectories[tmpColorPos]=1; + activeTrajectories.push_back(tmpColorPos); + } + + prev_clustCentX = clustCentX; + prev_clustCentY = clustCentY; + prev_positionClusterColor = positionClusterColor; + prev_activeTrajectories = activeTrajectories; + + trajectories = cv::Scalar(128,128,128); + int first=1; + for(int i=0; i<activeTrajectories.size(); i++) + { + int tmpval = activeTrajectories[i]; + if (counterTrajectories[tmpval]>1) + { + if(counterTrajectories[tmpval]<=MAX_NUM_TRAJECTORY_POINTS) + { + for(int j=1; j<counterTrajectories[tmpval]; j++) //instead of % I use &(power of 2 -1): it is more efficient + cv::line( trajectories, allTrajectories[tmpval][j-1], allTrajectories[tmpval][j], cv::Scalar( RGBColors[tmpval].val[0], RGBColors[tmpval].val[1], RGBColors[tmpval].val[2]), 2, 1); + } + else + { + int j=1; + int pos = counterTrajectories[tmpval]; + while(j<MAX_NUM_TRAJECTORY_POINTS) + { + cv::line( trajectories, allTrajectories[tmpval][pos & (MAX_NUM_TRAJECTORY_POINTS-1)], allTrajectories[tmpval][(pos+1)&(MAX_NUM_TRAJECTORY_POINTS-1)], cv::Scalar( RGBColors[tmpval].val[0], RGBColors[tmpval].val[1], RGBColors[tmpval].val[2]), 2, 1); + pos = pos+1; + j++; + } + } + } + + } + } + + trajectories.copyTo(segmentation); //Always keep trajectories + +/* +#if TEST + char filename[80]; + sprintf(filename,"/home/fran/0_tmp/kk/RGB_%0d.png", counterGlobal+1); + cv::imwrite(filename , segmentation); + + sprintf(filename,"/home/fran/0_tmp/kk/RGB_%0d.txt", counterGlobal+1); + std::ofstream foutallT(filename); + + for(int k=0; k<activeTrajectories.size(); k++) + if(counterTrajectories[activeTrajectories[k]]>0) + { + foutallT<<"ClusterID "<<activeTrajectories[k]<<" with "<<counterTrajectories[activeTrajectories[k]]<<" elems: = ["; + for(int j=0; j<counterTrajectories[activeTrajectories[k]]; j++) //instead of % I use &(power of 2 -1): it is more efficient + { + foutallT<<"("<<allTrajectories[activeTrajectories[k]][j].x<<", "<<allTrajectories[activeTrajectories[k]][j].y<<"), "; + } + foutallT<<"];\n"; + } + + foutallT.close(); +#endif +*/ + +#if TEST + char filename1[80]; + sprintf(filename1,"/home/chris/0_tmp/kk/rgb_%0d.txt", counterGlobal+1); + std::ofstream foutX(filename1); +#endif + counterIn =0; + counterOut=0; + for (int i = beginEvent; i < min(beginEvent+packet, msg->events.size()); i++) + { + if(activeEvents.at(counterIn)) //Label it only if it is not noise + { + const int x = msg->events[counterIn].x; + const int y = msg->events[counterIn].y; + double ts = (1E-6*(double)(msg->events[counterIn].ts.toNSec()-first_timestamp));//now in usecs + + //if(ts<15) //This is just for painting, we are processing all events + //{ + //segmentation.at<cv::Vec3b>(cv::Point(x,y))=RGBColors[(positionClusterColor[point2Clusters[counter]])%MAX_NUM_CLUSTERS]; + segmentation.at<cv::Vec3b>(cv::Point(x,y))=RGBColors[(positionClusterColor[point2Clusters[counterOut]])&(MAX_NUM_CLUSTERS-1)]; //cheaper than % (mod operation) + #if TEST + //foutX<<x<<" "<<y<<" "<<ts<<" "<<msg->events[counter].polarity<<'\n'; + foutX<<x<<'\t'<<'\t'<<y<<'\t'<<ts<<'\t'<<(int)(msg->events[counter].polarity)<<'\t'<<(int)((positionClusterColor[point2Clusters[counter]])&(MAX_NUM_CLUSTERS-1))<<'\n'; + #endif + counterOut++; + } + //} + //else + //{ + // break; + //} + counterIn++; + } + + + //char filename2[80]; + //sprintf(filename2,"/home/chris/0_tmp/kk/rgb_%0d.png", counterGlobal+1); + //cv::imwrite(filename2, segmentation); + + +// } + + + cv_segments.encoding = "bgr8"; + cv_segments.image = segmentation; + std::cout<<" Wanky shit demon 7"<<std::endl; + image_segmentation_pub_.publish(cv_segments.toImageMsg()); + std::cout<<" Wanky shit demon 8"<<std::endl; + //std::cin.ignore(); + + beginEvent +=packet; + +//#if TEST + //char filename[80]; + //sprintf(filename,"/home/fran/0_tmp/kk/rgb_%0d.jpg", counterGlobal+1); + //cv::imwrite(filename , segmentation); + //sprintf(filename,"/home/fran/0_tmp/kk/cc_%0d.txt", counterGlobal+1); + //std::ofstream foutcc(filename); + //for (int i = 0; i<clustCentX.size(); i++) + // foutcc<<"ClusterCenter("<<i+1<<",:)=["<<clustCentX.at(i)*DVSW<<","<<clustCentY.at(i)*DVSH<<"];"<<std::endl; + //foutcc.close(); +//#endif + //Saving RGB image +/* + if (counterGlobal>0) + { + //std::cin.ignore(); + //for (int i = 0; i<clustCentX.size(); i++) + // ROS_ERROR_STREAM("ClusterCenter("<<i+1<<",:)=["<<clustCentX.at(i)<<","<<clustCentY.at(i)<<","<<clustCentZ.at(i)<<"];"); + + //std::cout<<"clustperevent=["<<point2Clusters[0]; + //for (int i = 1; i<point2Clusters.size(); i++) + // std::cout<<","<<point2Clusters[i]; + //std::cout<<"];"<<std::endl; + + char filename[80]; + sprintf(filename,"/home/fran/0_tmp/kk/RGB_%0d.png", counterGlobal+1); + cv::imwrite(filename , segmentation); + //exit(0); + + //char filename[80]; + //sprintf(filename,"/home/fran/0_tmp/kk/RGB_%0d.txt", counterGlobal+1); + //std::ofstream foutX(filename); + //foutX<<counter<<"\n"; + //foutX.close(); + } +*/ + + + /*if(msg->events.size()>15e3) + { + char filename[80]; + sprintf(filename,"/home/fran/0_tmp/kk/RGB_%0d.png", counterGlobal+1); + cv::imwrite(filename , segmentation); + exit(0); + }*/ + counterGlobal++; + } + } +} + + + + +} // namespace diff --git a/RWR/src/mean-shift/dvs_meanshift/src/meanshift_node.cpp b/RWR/src/mean-shift/dvs_meanshift/src/meanshift_node.cpp new file mode 100755 index 0000000000000000000000000000000000000000..879b219b3532f680d1f1d3c5af0841e88bca02c1 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/src/meanshift_node.cpp @@ -0,0 +1,17 @@ + + +#include "dvs_meanshift/meanshift.h" + +int main(int argc, char* argv[]) +{ + ros::init(argc, argv, "dvs_meanshift"); + + ros::NodeHandle nh; + ros::NodeHandle nh_private("~"); + + dvs_meanshift::Meanshift meanshift(nh, nh_private); + + ros::spin(); + + return 0; +} diff --git a/RWR/src/mean-shift/dvs_meanshift/src/segment.cpp b/RWR/src/mean-shift/dvs_meanshift/src/segment.cpp new file mode 100755 index 0000000000000000000000000000000000000000..8d1d30b230d18c5235e77ecb73f6d3076dc30af7 --- /dev/null +++ b/RWR/src/mean-shift/dvs_meanshift/src/segment.cpp @@ -0,0 +1,171 @@ +/* +Copyright (C) 2006 Pedro Felzenszwalb + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <cstdio> +#include <cstdlib> +#include "graph3d/segment.h" +#include "graph3d/image.h" +#include "graph3d/misc.h" +#include "graph3d/pnmfile.h" +#include "graph3d/segment-image.h" + + +#include <cstdio> +#include <cstdlib> +#include <cv_bridge/cv_bridge.h> +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include "graph3d/image.h" +#include "graph3d/misc.h" +#include "graph3d/pnmfile.h" +#include "graph3d/segment-image.h" + +/* +int main(int argc, char **argv) { + if (argc != 6) { + fprintf(stderr, "usage: %s sigma k min input(ppm) output(ppm)\n", argv[0]); + return 1; + } + + float sigma = atof(argv[1]); + float k = atof(argv[2]); + int min_size = atoi(argv[3]); + + printf("loading input image.\n"); + image<rgb> *input = loadPPM(argv[4]); + + printf("processing\n"); + int num_ccs; + image<rgb> *seg = segment_image(input, sigma, k, min_size, &num_ccs); + savePPM(seg, argv[5]); + + + printf("got %d components\n", num_ccs); + printf("done! uff...thats hard work.\n"); + + return 0; +}*/ + + + +//void imadjust(const cv::Mat & src, cv::Mat & dst, int tol = 1, cv::Vec2i in = cv::Vec2i(0, 255), cv::Vec2i out = cv::Vec2i(0, 255)) +void imadjust(const cv::Mat & src, cv::Mat & dst) +{ + // src : input CV_8UC1 image + // dst : output CV_8UC1 imge + // tol : tolerance, from 0 to 100. + // in : src image bounds + // out : dst image buonds + + int in[2]; in[0]=0; in[1]=255; + int out[2]; out[0]=0; out[1]=255; + int tol =1; + + + + dst = src.clone(); + + tol = std::max(0, std::min(100, tol)); + + if (tol > 0) + { + // Compute in and out limits + + // Histogram + std::vector<int> hist(256, 0); + for (int r = 0; r < src.rows; ++r) { + for (int c = 0; c < src.cols; ++c) { + hist[src.at<uint8_t>(cv::Point(r,c))]++; + } + } + + // Cumulative histogram + std::vector<int> cum = hist; + for (int i = 1; i < hist.size(); ++i) { + cum[i] = cum[i - 1] + hist[i]; + } + + // Compute bounds + int total = src.rows * src.cols; + int low_bound = total * tol / 100; + int upp_bound = total * (100-tol) / 100; + in[0] = distance(cum.begin(), lower_bound(cum.begin(), cum.end(), low_bound)); + in[1] = distance(cum.begin(), lower_bound(cum.begin(), cum.end(), upp_bound)); + + } + + // Stretching + float scale = float(out[1] - out[0]) / float(in[1] - in[0]); + for (int r = 0; r < dst.rows; ++r) + { + for (int c = 0; c < dst.cols; ++c) + { + int vs = std::max(src.at<uint8_t>(cv::Point(r, c)) - in[0], 0); + + + int vd = std::min(int(vs * scale + 0.5f) + out[0], out[1]); + dst.at<uint8_t>(cv::Point(r, c)) = cv::saturate_cast<uchar>(vd); + } + } +} + +//This function is just an interface to call the segment_image function +void im2segment(cv::Mat input, cv::Mat cv_image_output, float sigma, float k, int min_size, int *num_ccs) +{ + + image<rgb> *inputIm=new image<rgb>(input.cols, input.rows); + + + for (int y = 0; y < input.rows; y++) { + for (int x = 0; x < input.cols; x++) { + imRef(inputIm, x, y).r = input.at<uint8_t>(cv::Point(x, y)); + imRef(inputIm, x, y).g = input.at<uint8_t>(cv::Point(x, y)); + imRef(inputIm, x, y).b = input.at<uint8_t>(cv::Point(x, y)); + } + } + + std::cout<<"I'm here!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<std::endl; + savePPM(inputIm, "/home/chris/input_image.ppm"); + + image<rgb> *seg = segment_image(inputIm, sigma, k, min_size, num_ccs); + + //cv_image_output.encoding = "bgr8"; + //cv_image_output.image =cv::Mat(input.rows, input.cols, CV_8UC3); + + for (int y = 0; y < input.rows; y++) { + for (int x = 0; x < input.cols; x++) { + //output.at<uint8_t>(cv::Point(x, y))=imRef(seg, x, y); + cv_image_output.at<cv::Vec3b>(cv::Point(x, y)) = ( \ + cv::Vec3b(imRef(seg,x,y).b, imRef(seg,x,y).g, imRef(seg,x,y).r)); + } + } + + + /*image<uchar> *inputTmp=new image<uchar>(input.cols, input.rows);; + for (int y = 0; y < input.rows; y++) { + for (int x = 0; x < input.cols; x++) { + imRef(inputTmp, x, y) = input.at<uint8_t>(cv::Point(x, y)); + } + } + savePGM(inputTmp, "/home/fran/input_image.ppm"); + */ + + //printf("got %d components\n", num_ccs); + //printf("done! uff...thats hard work.\n"); +} + diff --git a/RWR/src/mean-shift/rpg_dvs_ros b/RWR/src/mean-shift/rpg_dvs_ros new file mode 160000 index 0000000000000000000000000000000000000000..95f08d565c3115b181a4763e1e350f4df0375c4b --- /dev/null +++ b/RWR/src/mean-shift/rpg_dvs_ros @@ -0,0 +1 @@ +Subproject commit 95f08d565c3115b181a4763e1e350f4df0375c4b