diff --git a/.ci/linux-steps.yaml b/.ci/linux-steps.yaml index 3b660741..a53b2efa 100644 --- a/.ci/linux-steps.yaml +++ b/.ci/linux-steps.yaml @@ -20,7 +20,7 @@ steps: unset BOOST_ROOT echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT - sudo apt-get install -y --allow-unauthenticated liblapack-dev g++ libboost1.70-dev libarmadillo-dev xz-utils + sudo apt-get install -y --allow-unauthenticated liblapack-dev g++ libboost1.70-dev libcereal-dev libarmadillo-dev xz-utils curl https://data.kurg.org/armadillo-8.400.0.tar.xz | tar -xvJ && cd armadillo* cmake . && make && sudo make install && cd .. diff --git a/augmentation/augmentation.hpp b/augmentation/augmentation.hpp index de85c7b7..b5f6cc65 100644 --- a/augmentation/augmentation.hpp +++ b/augmentation/augmentation.hpp @@ -1,6 +1,6 @@ /** * @file augmentation.hpp - * @author Kartik Dutt + * @author Kartik Dutt, Sirish * * Definition of Augmentation class for augmenting data. * @@ -105,6 +105,29 @@ class Augmentation const size_t datapointDepth, const std::string& augmentation); + + /** + * Applies gaussian blurring to the entire dataset. + * + * @tparam DatasetType Datatype on which augmentation will be done. + * + * @param dataset Dataset on which augmentation will be applied. + * @param datapointWidth Width of a single data point i.e. + * Since each column represents a seperate data + * point. + * @param datapointHeight Height of a single data point. + * @param datapointDepth Depth of a single data point. For one 2-dimensional + * data point, set it to 1. Defaults to 1. + * @param augmentation String containing the transform. + */ + + template + void GaussianBlurTransform(DatasetType& dataset, + const size_t datapointWidth, + const size_t datapointHeight, + const size_t datapointDepth, + const std::string& augmentation); + private: /** * Function to determine if augmentation has Resize function. @@ -119,10 +142,31 @@ class Augmentation // Search in augmentation vector. - return augmentations.size() <= 0 ? false : - augmentations[0].find("resize") != std::string::npos; + for(size_t i = 0; i < argumentation.size(); i++) + { + if (argumentation[i].find("resize") != std::string::npos) + return true + } + return false + } + /* + * Function to determine whether blurring is needed or not + Will check if the string has blurring. + */ + bool HasBlurring(const std::string& augmentation = "") + { + if (augmentation.length()) + return augmentation.find("gaussian-blur") != std::string::npos; + + for(size_t i = 0; i < argumentation.size(); i++) + { + if(argumentation[i].find("gaussian-blur") != std::string::npos) + return true + } + return false } + /** * Sets size of output width and output height of the new data. * @@ -169,6 +213,38 @@ class Augmentation outHeight = std::stoi(*matches); } } + /** + * Sets size of radius/ sigma of the gaussian kernel. + * + * @param sigma is the radius of the gaussian kernel specified by user. + */ + void GetBlurParam(size_t& sigma, const std::string& augmentation) + { + if (!HasBlurring(augmentation)) + return; + + sigma = 0; + + // Use regex to find one number. + // Input should be of form sigma. + boost::regex regex{"[0-9]+"}; + + // Create an iterator to find matches. + boost::sregex_token_iterator matches(augmentation.begin(), + augmentation.end(), regex, 0), end; + + size_t matchesCount = std::distance(matches, end); + + if (matchesCount != 1) + { + mlpack::Log::Fatal << "Invalid sigma/ radius for gaussian blurring" << + augmentation << std::endl; + } + else + { + sigma = std::stoi(*matches); + } + } //! Locally held augmentations and transforms that need to be applied. std::vector augmentations; diff --git a/augmentation/augmentation_impl.hpp b/augmentation/augmentation_impl.hpp index c4494a35..2cf29cd7 100644 --- a/augmentation/augmentation_impl.hpp +++ b/augmentation/augmentation_impl.hpp @@ -1,6 +1,6 @@ -/** +/**Adding support for more data types to mlpack, it would be preferable to add the support upstream to Armadillo instead, so that may be a better direction to go first. Then very little code modification for mlpack will be necessary./** * @file augmentation_impl.hpp - * @author Kartik Dutt + * @author Kartik Dutt, Sirish * * Implementation of Augmentation class for augmenting data. * @@ -38,7 +38,12 @@ void Augmentation::Transform(DatasetType& dataset, this->ResizeTransform(dataset, datapointWidth, datapointHeight, datapointDepth, augmentations[i]); } - else + else if(this->HasBlurring(augmentations[i])) + { + this->GaussianBlurTransform(dataset, datapointWidth, datapointHeight, + datapointDepth, augmentations[i]); + } + else { mlpack::Log::Warn << "Unknown augmentation : \'" << augmentations[i] << "\' not found!" << std::endl; @@ -70,4 +75,66 @@ void Augmentation::ResizeTransform( dataset = std::move(output); } +template +void Augmentation::GaussianBlurTransform( + DatasetType& dataset, + const size_t datapointWidth, + const size_t datapointHeight, + const size_t datapointDepth, + const std::string& augmentation) +{ + //Implementing using http://blog.ivank.net/fastest-gaussian-blur.html + size_t sigma = 0; + GetBlurParam(sigma,augmentation); + + size_t rows, cols, depth; + // Storing initial matrix dimensions + rows = dataset.n_rows; + cols = dataset.n_cols; + depth = dataset.depth; + + // Creating empty object bImage + DatasetType bImage(datapointHeight, datapointWidth, datapointDepth); + + // Reshaping the matrix for ease of calculation + dataset = arma::resize(dataset,datapointHeight,datapointWidth,datapointDepth); + + //Significant radius + size_t rs = arma::ceil(sigma * 2.57); + + for (size_t k = 0; k < datapointDepth; k++) + { + for (size_t i = 0; i < datapointHeight; i++) + { + for (size_t j = 0; j < datapointWidth; j++) + { + size_t val = 0; + size_t wsum = 0; + + for (size_t iy = i - rs; iy <= i + rs; iy++) + { + for (size_t ix = j - rs; ix <= j + rs; ix++) + { + size_t x,y; + x = arma::min(datapointWidth - 1, arma::max(0, ix)) + y = arma::min(datapointHeight - 1, arma::max(0, iy)) + // Calculating sqaured distance + dsq = (ix - j) * (ix - j) + (iy - i) * (iy - i) + // Weight of gaussian kernel + weight = arma::exp(-dsq / (2 * sigma * sigma)) / (datum::pi * 2 * sigma * sigma) + // Summing all weighted contributions + val += dataset(y,x,k)* weight + wsum += weight + } + } + // Blurred image + bImage(i,j,k) = arma::round(val / wsum) + } + } + } + + //Restoring the blurred image to original dimensions as that of input + bImage = arma::resize(bImage,rows,cols,depth); + dataset = std::move(bImage); +} #endif