color_histogram.h
Go to the documentation of this file.
00001 // -*- mode: C++ -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2017, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the JSK Lab nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *********************************************************************/
00035 /*
00036  * color_histogram.h
00037  * Author: Yuki Furuta <furushchev@jsk.imi.i.u-tokyo.ac.jp>
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); // h + w + b
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); // h * s + w + b
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     // vote
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     // copy white + black
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     // copy white + black
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 } // namespace
00252 
00253 #endif // JSK_RECOGNITION_UTILS_COLOR_HISTOGRAM_H__


jsk_recognition_utils
Author(s):
autogenerated on Sun Oct 8 2017 02:42:48