00001 00002 #include <jsk_perception/histogram_of_oriented_gradients.h> 00003 00004 HOGFeatureDescriptor::HOGFeatureDescriptor() { 00005 00006 } 00007 00008 void HOGFeatureDescriptor::bilinearBinVoting( 00009 const float &angle, int &lower_index, int &higher_index) { 00010 float nearest_lower = FLT_MAX; 00011 float nearest_higher = FLT_MAX; 00012 lower_index = 0; 00013 higher_index = 0; 00014 for (int i = BINS_ANGLE/2; i < ANGLE; i += BINS_ANGLE) { 00015 float distance = abs(angle - i); 00016 if (i < angle) { 00017 if (distance < nearest_lower) { 00018 nearest_lower = distance; 00019 lower_index = i; 00020 } 00021 } else { 00022 if (distance < nearest_higher) { 00023 nearest_higher = distance; 00024 higher_index = i; 00025 } 00026 } 00027 } 00028 } 00029 00030 void HOGFeatureDescriptor::imageGradient( 00031 const cv::Mat &image, cv::Mat &hog_bins) { 00032 cv::Mat xsobel; 00033 cv::Mat ysobel; 00034 cv::Sobel(image, xsobel, CV_32F, 1, 0, 3); 00035 cv::Sobel(image, ysobel, CV_32F, 0, 1, 3); 00036 cv::Mat Imag; 00037 cv::Mat Iang; 00038 cv::cartToPolar(xsobel, ysobel, Imag, Iang, true); 00039 cv::add(Iang, cv::Scalar(180), Iang, Iang < 0); 00040 cv::add(Iang, cv::Scalar(-180), Iang, Iang >= 180); 00041 cv::Mat orientation_histogram; 00042 for (int j = 0; j < image.rows; j += CELL) { 00043 for (int i = 0; i < image.cols; i += CELL) { 00044 cv::Rect rect = cv::Rect(i, j, CELL, CELL); 00045 if ((rect.x + rect.width <= image.cols) && 00046 (rect.y + rect.height <= image.rows)) { 00047 cv::Mat bin = cv::Mat::zeros(1, N_BINS, CV_32F); 00048 for (int y = rect.y; y < (rect.y + rect.height); y++) { 00049 for (int x = rect.x; x < (rect.x + rect.width); x++) { 00050 float angle = static_cast<float>(Iang.at<float>(y, x)); 00051 int l_bin; 00052 int h_bin; 00053 this->bilinearBinVoting(angle, l_bin, h_bin); 00054 float l_ratio = 1 - (angle - l_bin)/BINS_ANGLE; 00055 float h_ratio = 1 + (angle - h_bin)/BINS_ANGLE; 00056 int l_index = (l_bin-(BINS_ANGLE/2))/BINS_ANGLE; 00057 int h_index = (h_bin-(BINS_ANGLE/2))/BINS_ANGLE; 00058 bin.at<float>(0, l_index) += 00059 (Imag.at<float>(y, x) * l_ratio); 00060 bin.at<float>(0, h_index) += 00061 (Imag.at<float>(y, x) * h_ratio); 00062 } 00063 } 00064 orientation_histogram.push_back(bin); 00065 } 00066 } 00067 } 00068 hog_bins = orientation_histogram.clone(); 00069 } 00070 00071 cv::Mat HOGFeatureDescriptor::blockGradient( 00072 const int col, const int row, cv::Mat &bins) { 00073 cv::Mat block_hogMD = cv::Mat(cv::Size(N_BINS * BLOCK * BLOCK, 1), CV_32F); 00074 int icounter = 0; 00075 for (int j = row; j < (row + BLOCK); j++) { 00076 for (int i = col; i < (col + BLOCK); i++) { 00077 int index = (j * CELL) + i; 00078 for (int k = 0; k < N_BINS; k++) { 00079 block_hogMD.at<float>(0, icounter++) = bins.at<float>(index); 00080 } 00081 } 00082 } 00083 return block_hogMD; 00084 } 00085 00086 void HOGFeatureDescriptor::getHOG( 00087 const cv::Mat &image, cv::Mat &bins, cv::Mat &featureMD) { 00088 for (int j = 0; j < image.rows; j += CELL) { 00089 for (int i = 0; i < image.cols; i += CELL) { 00090 cv::Rect rect = cv::Rect(i, j, CELL*BLOCK, CELL*BLOCK); 00091 if ((rect.x + rect.width <= image.cols) && 00092 (rect.y + rect.height <= image.rows)) { 00093 cv::Mat hogMD = this->blockGradient(rect.x, rect.y, bins); 00094 normalize(hogMD, hogMD, 1, 0, CV_L2); 00095 featureMD.push_back(hogMD); 00096 } 00097 } 00098 } 00099 } 00100 00101 cv::Mat HOGFeatureDescriptor::computeHOG( 00102 const cv::Mat &img) { 00103 cv::Mat image = img.clone(); 00104 if (image.type() != CV_8U) { 00105 cv::cvtColor(image, image, CV_BGR2GRAY); 00106 } 00107 cv::Mat bins; 00108 this->imageGradient(image, bins); 00109 cv::Mat featureMD; 00110 getHOG(image, bins, featureMD); 00111 featureMD = featureMD.reshape(1, 1); 00112 return featureMD; 00113 } 00114 00115 cv::Mat HOGFeatureDescriptor::orientationistogram( 00116 const cv::Mat &src, const int &min_val, const int &max_val, bool normed) { 00117 cv::Mat result; 00118 int histSize = max_val - min_val; 00119 float range[] = { static_cast<float>(min_val), 00120 static_cast<float>(max_val+1)}; 00121 const float* histRange = {range}; 00122 cv::calcHist( 00123 &src, 1, 0, cv::Mat(), result, 1, &histSize, &histRange, true, false); 00124 if (normed) { 00125 cv::normalize(result, result, 0, 1, cv::NORM_MINMAX, -1, cv::Mat()); 00126 } 00127 return result; 00128 } 00129 00130 00131 template<typename T> 00132 T HOGFeatureDescriptor::computeHOGHistogramDistances( 00133 const cv::Mat &patch, std::vector<cv::Mat> &imageHOG, 00134 const int distance_type) { 00135 T sum = 0.0; 00136 T argMinDistance = FLT_MAX; 00137 for (int i = 0; i < imageHOG.size(); i++) { 00138 cv::Mat img_hog = imageHOG[i]; 00139 T d = compareHist(patch, img_hog, distance_type); 00140 if (d < argMinDistance) { 00141 argMinDistance = static_cast<double>(d); 00142 } 00143 } 00144 sum = static_cast<T>(argMinDistance); 00145 return static_cast<T>(sum); 00146 }