00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #ifndef JSK_RECOGNITION_UTILS_COLOR_HISTOGRAM_H__
00041 #define JSK_RECOGNITION_UTILS_COLOR_HISTOGRAM_H__
00042
00043 #include <algorithm>
00044 #include <iterator>
00045 #include <vector>
00046 #include <pcl/point_cloud.h>
00047 #include <pcl/point_types.h>
00048
00049 namespace jsk_recognition_utils {
00050 enum HistogramPolicy {
00051 HUE = 0,
00052 HUE_AND_SATURATION
00053 };
00054
00055 enum ComparePolicy {
00056 CORRELATION = 0,
00057 BHATTACHARYYA,
00058 INTERSECTION,
00059 CHISQUARE,
00060 KL_DIVERGENCE
00061 };
00062
00063 struct PointXYZHLS {
00064 double x, y, z;
00065 double h, l, s;
00066 };
00067
00068 inline void
00069 HSV2HLS(const pcl::PointXYZHSV& hsv, PointXYZHLS& hls) {
00070 hls.x = hsv.x; hls.y = hsv.y; hls.z = hsv.z;
00071 hls.h = hsv.h;
00072 hls.l = (2.0 - hsv.s) * hsv.v;
00073 hls.s = hsv.s * hsv.v;
00074 hls.s /= (hls.l <= 1.0) ? hls.l : 2.0 - hls.l;
00075 hls.l /= 2.0;
00076 }
00077
00078 inline int
00079 getHistogramBin(const double& val, const int& step,
00080 const double& min, const double& max)
00081 {
00082 int idx = std::floor((val - min) / (max - min) * step);
00083 if (idx >= step) return step - 1;
00084 else if (idx <= 0) return 0;
00085 else return idx;
00086 }
00087
00088 inline void
00089 normalizeHistogram(std::vector<float>& histogram)
00090 {
00091 float sum = 0.0f;
00092 for (size_t i = 0; i < histogram.size(); ++i)
00093 sum += histogram[i];
00094 if (sum != 0.0) {
00095 for (size_t i = 0; i < histogram.size(); ++i)
00096 histogram[i] /= sum;
00097 }
00098 }
00099
00100 inline void
00101 computeColorHistogram1d(const pcl::PointCloud<pcl::PointXYZHSV>& cloud,
00102 std::vector<float>& histogram,
00103 const int bin_size,
00104 const double white_threshold=0.1,
00105 const double black_threshold=0.1)
00106 {
00107 histogram.resize(bin_size + 2, 0.0f);
00108 int white_index = bin_size;
00109 int black_index = bin_size + 1;
00110
00111 for (size_t i = 0; i < cloud.points.size(); ++i) {
00112 PointXYZHLS p;
00113 HSV2HLS(cloud.points[i], p);
00114 if (p.l > 1.0 - white_threshold)
00115 histogram[white_index] += 1.0f;
00116 else if (p.l < black_threshold)
00117 histogram[black_index] += 1.0f;
00118 else {
00119 int h_bin = getHistogramBin(p.h, bin_size, 0.0, 360.0);
00120 histogram[h_bin] += 1.0f;
00121 }
00122 }
00123
00124 normalizeHistogram(histogram);
00125 }
00126
00127 inline void
00128 computeColorHistogram2d(const pcl::PointCloud<pcl::PointXYZHSV>& cloud,
00129 std::vector<float>& histogram,
00130 const int bin_size_per_channel,
00131 const double white_threshold=0.1,
00132 const double black_threshold=0.1)
00133 {
00134 histogram.resize(bin_size_per_channel * bin_size_per_channel + 2, 0.0f);
00135 int white_index = bin_size_per_channel * bin_size_per_channel;
00136 int black_index = bin_size_per_channel * bin_size_per_channel + 1;
00137
00138
00139 for (size_t i = 0; i < cloud.points.size(); ++i) {
00140 PointXYZHLS p;
00141 HSV2HLS(cloud.points[i], p);
00142 if (p.l < white_threshold)
00143 histogram[white_index] += 1.0f;
00144 else if (p.l > 1.0 - black_threshold)
00145 histogram[black_index] += 1.0f;
00146 else {
00147 int h_bin = getHistogramBin(p.h, bin_size_per_channel, 0.0, 360.0);
00148 int s_bin = getHistogramBin(p.s, bin_size_per_channel, 0.0, 1.0);
00149 histogram[s_bin * bin_size_per_channel + h_bin] += 1.0f;
00150 }
00151 }
00152
00153 normalizeHistogram(histogram);
00154 }
00155
00156 inline void
00157 rotateHistogram1d(const std::vector<float>& input,
00158 std::vector<float>& output,
00159 const double degree)
00160 {
00161 size_t bin_size = input.size() - 2;
00162 int offset = std::floor(degree / 360.0 * bin_size);
00163 output.resize(input.size());
00164 for (size_t h = 0; h < bin_size; ++h) {
00165 int hout = h + offset % bin_size;
00166 output[hout] = input[h];
00167 }
00168
00169
00170 int index = bin_size;
00171 output[index] = input[index];
00172 output[index+1] = input[index+1];
00173 }
00174
00175 inline void
00176 rotateHistogram2d(const std::vector<float>& input,
00177 std::vector<float>& output,
00178 const double degree)
00179 {
00180 size_t bin_size = (size_t)(std::sqrt(input.size() - 2));
00181 int offset = std::floor(degree / 360.0 * bin_size);
00182 output.resize(input.size());
00183 for (size_t s = 0; s < bin_size; ++s) {
00184 for (size_t h = 0; h < bin_size; ++h) {
00185 int hout = h + offset % bin_size;
00186 output[s * bin_size + hout] = input[s * bin_size + h];
00187 }
00188 }
00189
00190
00191 int index = bin_size * bin_size;
00192 output[index] = input[index];
00193 output[index+1] = input[index+1];
00194 }
00195
00196 inline bool
00197 compareHistogram(const std::vector<float>& input,
00198 const std::vector<float>& reference,
00199 const ComparePolicy policy,
00200 double& distance)
00201 {
00202 if (input.size() != reference.size()) {
00203 ROS_ERROR("Mismatch histogram bin size");
00204 return false;
00205 }
00206
00207 distance = 0.0;
00208 size_t len = input.size();
00209 if (policy == CHISQUARE) {
00210 for (size_t i = 0; i < len; ++i) {
00211 double a = input[i] - reference[i], b = input[i];
00212 if (std::fabs(b) > DBL_EPSILON) distance += a * a / b;
00213 }
00214 } else if (policy == CORRELATION) {
00215 double s1 = 0.0, s2 = 0.0, s11 = 0.0, s12 = 0.0, s22 = 0.0;
00216 for (size_t i = 0; i < len; ++i) {
00217 double a = input[i], b = reference[i];
00218 s11 += a*a; s12 += a*b; s22 += b*b;
00219 s1 += a; s2 += b;
00220 }
00221 double num = s12 - s1*s2/len;
00222 double denom2 = (s11 - s1 * s1 / len) * (s22 - s2 * s2 / len);
00223 distance = std::fabs(denom2) > DBL_EPSILON ? num / std::sqrt(denom2) : 1.0;
00224 } else if (policy == INTERSECTION) {
00225 for (size_t i = 0; i < len; ++i) {
00226 distance += std::min(input[i], reference[i]);
00227 }
00228 } else if (policy == BHATTACHARYYA) {
00229 double s1 = 0.0, s2 = 0.0;
00230 for (size_t i = 0; i < len; ++i) {
00231 distance += std::sqrt(input[i] * reference[i]);
00232 s1 += input[i]; s2 += reference[i];
00233 }
00234 s1 *= s2;
00235 s1 = std::fabs(s1) > DBL_EPSILON ? 1.0 / std::sqrt(s1) : 1.0;
00236 distance = std::sqrt(std::max(1.0 - distance * s1, 0.0));
00237 } else if (policy == KL_DIVERGENCE) {
00238 for (size_t i = 0; i < len; ++i) {
00239 double p = input[i], q = reference[i];
00240 if (std::fabs(p) <= DBL_EPSILON) continue;
00241 if (std::fabs(q) <= DBL_EPSILON) q = 1e-10;
00242 distance += p * std::log(p / q);
00243 }
00244 } else {
00245 ROS_ERROR("Invalid compare policy");
00246 return false;
00247 }
00248
00249 return true;
00250 }
00251 }
00252
00253 #endif // JSK_RECOGNITION_UTILS_COLOR_HISTOGRAM_H__