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