Renesas GR-PEACH OpenCV Development / gr-peach-opencv-project-sd-card_update

Fork of gr-peach-opencv-project-sd-card by the do

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers bif.cpp Source File

bif.cpp

00001 /*
00002 By downloading, copying, installing or using the software you agree to this license.
00003 If you do not agree to this license, do not download, install,
00004 copy or use the software.
00005 
00006 
00007                           License Agreement
00008                For Open Source Computer Vision Library
00009                        (3-clause BSD License)
00010 
00011 Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
00012 Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
00013 Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
00014 Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
00015 Copyright (C) 2015, OpenCV Foundation, all rights reserved.
00016 Copyright (C) 2015, Itseez Inc., all rights reserved.
00017 Third party copyrights are property of their respective owners.
00018 
00019 Redistribution and use in source and binary forms, with or without modification,
00020 are permitted provided that the following conditions are met:
00021 
00022   * Redistributions of source code must retain the above copyright notice,
00023     this list of conditions and the following disclaimer.
00024 
00025   * Redistributions in binary form must reproduce the above copyright notice,
00026     this list of conditions and the following disclaimer in the documentation
00027     and/or other materials provided with the distribution.
00028 
00029   * Neither the names of the copyright holders nor the names of the contributors
00030     may be used to endorse or promote products derived from this software
00031     without specific prior written permission.
00032 
00033 This software is provided by the copyright holders and contributors "as is" and
00034 any express or implied warranties, including, but not limited to, the implied
00035 warranties of merchantability and fitness for a particular purpose are disclaimed.
00036 In no event shall copyright holders or contributors be liable for any direct,
00037 indirect, incidental, special, exemplary, or consequential damages
00038 (including, but not limited to, procurement of substitute goods or services;
00039 loss of use, data, or profits; or business interruption) however caused
00040 and on any theory of liability, whether in contract, strict liability,
00041 or tort (including negligence or otherwise) arising in any way out of
00042 the use of this software, even if advised of the possibility of such damage.
00043 */
00044 
00045 
00046 /*
00047 This file contains implementation of the bio-inspired features (BIF) approach
00048 for computing image descriptors, applicable for human age estimation. For more
00049 details we refer to [1,2].
00050 
00051 REFERENCES
00052   [1] Guo, Guodong, et al. "Human age estimation using bio-inspired features."
00053       Computer Vision and Pattern Recognition, 2009. CVPR 2009.
00054   [2] Spizhevoi, A. S., and A. V. Bovyrin. "Estimating human age using
00055       bio-inspired features and the ranking method." Pattern Recognition and
00056       Image Analysis 25.3 (2015): 547-552.
00057 */
00058 
00059 #include "precomp.hpp"
00060 #include "opencv2/face/bif.hpp"
00061 #include <iostream>
00062 #include <vector>
00063 
00064 namespace {
00065 
00066 // The constants below are taken from paper [1].
00067 
00068 const int kNumBandsMax = 8;
00069 
00070 const cv::Size kCellSizes[kNumBandsMax] = {
00071     cv::Size(6,6), cv::Size(8,8), cv::Size(10,10), cv::Size(12,12),
00072     cv::Size(14,14), cv::Size(16,16), cv::Size(18,18), cv::Size(20,20)
00073 };
00074 
00075 const cv::Size kGaborSize[kNumBandsMax][2] = {
00076     {cv::Size(5,5), cv::Size(7,7)}, {cv::Size(9,9), cv::Size(11,11)},
00077     {cv::Size(13,13), cv::Size(15,15)}, {cv::Size(17,17), cv::Size(19,19)},
00078     {cv::Size(21,21), cv::Size(23,23)}, {cv::Size(25,25), cv::Size(27,27)},
00079     {cv::Size(29,29), cv::Size(31,31)}, {cv::Size(33,33), cv::Size(35,35)}
00080 };
00081 
00082 const double kGaborGamma = 0.3;
00083 
00084 const double kGaborSigmas[kNumBandsMax][2] = {
00085     {2.0, 2.8}, {3.6, 4.5}, {5.4, 6.3}, {7.3, 8.2},
00086     {9.2, 10.2}, {11.3, 12.3}, {13.4, 14.6}, {15.8, 17.0}
00087 };
00088 
00089 const double kGaborWavelens[kNumBandsMax][2] = {
00090     {2.5, 3.5}, {4.6, 5.6}, {6.8, 7.9}, {9.1, 10.3},
00091     {11.5, 12.7}, {14.1, 15.4}, {16.8, 18.2}, {19.7, 21.2}
00092 };
00093 
00094 class BIFImpl : public cv::face::BIF {
00095 public:
00096     BIFImpl(int num_bands, int num_rotations) {
00097         initUnits(num_bands, num_rotations);
00098     }
00099 
00100     virtual int getNumBands() const { return num_bands_; }
00101 
00102     virtual int getNumRotations() const { return num_rotations_; }
00103 
00104     virtual void compute(cv::InputArray image,
00105                          cv::OutputArray features) const;
00106 
00107 private:
00108     struct UnitParams {
00109         cv::Size cell_size;
00110         cv::Mat filter1, filter2;
00111     };
00112 
00113     void initUnits(int num_bands, int num_rotations);
00114     void computeUnit(int unit_idx, const cv::Mat &img, cv::Mat &dst) const;
00115 
00116     int num_bands_;
00117     int num_rotations_;
00118     std::vector<UnitParams> units_;
00119 };
00120 
00121 void BIFImpl::compute(cv::InputArray _image,
00122                       cv::OutputArray _features) const {
00123     cv::Mat image = _image.getMat();
00124     CV_Assert(image.type() == CV_32F);
00125 
00126     std::vector<cv::Mat> fea_units(units_.size());
00127     int fea_dim = 0;
00128 
00129     for (size_t i = 0; i < units_.size(); ++i) {
00130         computeUnit(static_cast<int>(i), image, fea_units[i]);
00131         fea_dim += fea_units[i].rows;
00132     }
00133 
00134     _features.create(fea_dim, 1, CV_32F);
00135     cv::Mat fea = _features.getMat();
00136 
00137     int offset = 0;
00138     for (size_t i = 0; i < fea_units.size(); ++i) {
00139         cv::Mat roi = fea.rowRange(offset, offset + fea_units[i].rows);
00140         fea_units[i].copyTo(roi);
00141         offset += fea_units[i].rows;
00142     }
00143     CV_Assert(offset == fea_dim);
00144 }
00145 
00146 void BIFImpl::initUnits(int num_bands, int num_rotations) {
00147     CV_Assert(num_bands > 0 && num_bands <= kNumBandsMax);
00148     CV_Assert(num_rotations > 0);
00149 
00150     num_bands_ = num_bands;
00151     num_rotations_ = num_rotations;
00152 
00153     for (int ri = 0; ri < num_rotations; ++ri) {
00154         double angle = CV_PI / num_rotations * ri;
00155 
00156         for (int bi = 0; bi < num_bands; ++bi) {
00157             cv::Mat kernel[2];
00158             for (int i = 0; i < 2; ++i) {
00159                 kernel[i] = cv::getGaborKernel(
00160                     kGaborSize[bi][i], kGaborSigmas[bi][i], angle,
00161                     kGaborWavelens[bi][i], kGaborGamma, 0, CV_32F);
00162 
00163                 // Make variance for the Gaussian part of the Gabor filter
00164                 // the same across all filters.
00165                 kernel[i] /= 2 * kGaborSigmas[bi][i] * kGaborSigmas[bi][i]
00166                              / kGaborGamma;
00167             }
00168 
00169             UnitParams unit;
00170             unit.cell_size = kCellSizes[bi];
00171             unit.filter1 = kernel[0];
00172             unit.filter2 = kernel[1];
00173             units_.push_back(unit);
00174         }
00175     }
00176 }
00177 
00178 void BIFImpl::computeUnit(int unit_idx, const cv::Mat &img,
00179                           cv::Mat &dst) const {
00180     cv::Mat resp1, resp2;
00181     cv::filter2D(img, resp1, CV_32F, units_[unit_idx].filter1);
00182     cv::filter2D(img, resp2, CV_32F, units_[unit_idx].filter2);
00183 
00184     cv::Mat resp, sum, sumsq;
00185     cv::max(resp1, resp2, resp);
00186     cv::integral (resp, sum, sumsq);
00187 
00188     int Hhalf = units_[unit_idx].cell_size.height / 2;
00189     int Whalf = units_[unit_idx].cell_size.width / 2;
00190 
00191     int nrows = (resp.rows + Hhalf - 1) / Hhalf;
00192     int ncols = (resp.cols + Whalf - 1) / Whalf;
00193     dst.create(nrows*ncols, 1, CV_32F);
00194 
00195     for (int pos = 0, yc = 0; yc < resp.rows; yc += Hhalf) {
00196         int y0 = std::max(0, yc - Hhalf);
00197         int y1 = std::min(resp.rows, yc + Hhalf);
00198 
00199         for (int xc = 0; xc < resp.cols; xc += Whalf, ++pos) {
00200             int x0 = std::max(0, xc - Whalf);
00201             int x1 = std::min(resp.cols, xc + Whalf);
00202             int area = (y1-y0) * (x1-x0);
00203 
00204             double mean = sum.at<double>(y1,x1) - sum.at<double>(y1,x0)
00205                          - sum.at<double>(y0,x1) + sum.at<double>(y0,x0);
00206             mean /= area;
00207 
00208             double sd = sumsq.at<double>(y1,x1) - sumsq.at<double>(y1,x0)
00209                         - sumsq.at<double>(y0,x1) + sumsq.at<double>(y0,x0);
00210             sd = sqrt(std::max(0.0, sd / area - mean * mean));
00211 
00212             dst.at<float>(pos) = static_cast<float>(sd);
00213         }
00214     }
00215 }
00216 
00217 }  // namespace
00218 
00219 cv::Ptr<cv::face::BIF> cv::face::createBIF(int num_bands, int num_rotations) {
00220     return cv::Ptr<cv::face::BIF>(new BIFImpl(num_bands, num_rotations));
00221 }
00222