File indexing completed on 2025-01-19 03:57:41

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam
0004  *
0005  * Date        : 2012-01-03
0006  * Description : Calculates the TanTriggs Preprocessing as described in:
0007  *               Tan, X., and Triggs, B. "Enhanced local texture feature sets for face
0008  *               recognition under difficult lighting conditions.". IEEE Transactions
0009  *               on Image Processing 19 (2010), 1635–650.
0010  *               Default parameters are taken from the paper.
0011  *
0012  * SPDX-FileCopyrightText: 2012-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0013  * SPDX-FileCopyrightText:      2012 Philipp Wagner <bytefish at gmx dot de>
0014  *
0015  * SPDX-License-Identifier: GPL-2.0-or-later
0016  *
0017  * ============================================================ */
0018 
0019 #include "tantriggspreprocessor.h"
0020 
0021 namespace Digikam
0022 {
0023 
0024 TanTriggsPreprocessor::TanTriggsPreprocessor()
0025     : alpha (0.1f),
0026       tau   (10.0f),
0027       gamma (0.2f),
0028       sigma0(1),
0029       sigma1(2)
0030 {
0031 }
0032 
0033 cv::Mat TanTriggsPreprocessor::preprocess(const cv::Mat& inputImage)
0034 {
0035     return normalize(preprocessRaw(inputImage));
0036 }
0037 
0038 cv::Mat TanTriggsPreprocessor::preprocessRaw(const cv::Mat& inputImage)
0039 {
0040     cv::Mat X = inputImage;
0041 
0042     // Ensure it's grayscale
0043 
0044     if (X.channels() > 1)
0045     {
0046         cvtColor(X, X, CV_RGB2GRAY);
0047     }
0048 
0049     // Convert to floating point:
0050 
0051     X.convertTo(X, CV_32FC1);
0052 
0053     // Start preprocessing:
0054 
0055     cv::Mat I;
0056 
0057     // Gamma correction
0058 
0059     cv::pow(X, gamma, I);
0060 
0061     // Calculate the DOG (Difference of Gaussian) Image.
0062 
0063     {
0064         cv::Mat gaussian0, gaussian1;
0065 
0066         // Kernel Size:
0067 
0068         int kernel_sz0 = (int)(3*sigma0);
0069         int kernel_sz1 = (int)(3*sigma1);
0070 
0071         // Make them odd for OpenCV:
0072 
0073         kernel_sz0    += ((kernel_sz0 % 2) == 0) ? 1 : 0;
0074         kernel_sz1    += ((kernel_sz1 % 2) == 0) ? 1 : 0;
0075         cv::GaussianBlur(I, gaussian0, cv::Size(kernel_sz0,kernel_sz0), sigma0, sigma0, cv::BORDER_CONSTANT);
0076         cv::GaussianBlur(I, gaussian1, cv::Size(kernel_sz1,kernel_sz1), sigma1, sigma1, cv::BORDER_CONSTANT);
0077         cv::subtract(gaussian0, gaussian1, I);
0078     }
0079 
0080     {
0081         double meanI = 0.0;
0082 
0083         {
0084             cv::Mat tmp;
0085             cv::pow(cv::abs(I), alpha, tmp);
0086             meanI = cv::mean(tmp).val[0];
0087         }
0088 
0089         I = I / cv::pow(meanI, 1.0/alpha);
0090     }
0091 
0092     {
0093         double meanI = 0.0;
0094 
0095         {
0096             cv::Mat tmp;
0097             cv::pow(cv::min(cv::abs(I), tau), alpha, tmp);
0098             meanI = cv::mean(tmp).val[0];
0099         }
0100 
0101         I = I / cv::pow(meanI, 1.0/alpha);
0102     }
0103 
0104     // Squash into the tanh:
0105 
0106     {
0107         for (int r = 0 ; r < I.rows ; ++r)
0108         {
0109             for (int c = 0 ; c < I.cols ; ++c)
0110             {
0111                 I.at<float>(r, c) = tanh(I.at<float>(r, c) / tau);
0112             }
0113         }
0114 
0115         I = tau * I;
0116     }
0117 
0118     return I;
0119 }
0120 
0121 /**
0122  * Normalizes a given image into a value range between 0 and 255.
0123  */
0124 cv::Mat TanTriggsPreprocessor::normalize(const cv::Mat& src)
0125 {
0126     // Create and return normalized image.
0127 
0128     cv::Mat dst;
0129 
0130     switch (src.channels())
0131     {
0132         case 1:
0133             cv::normalize(src, dst, 0, 255, cv::NORM_MINMAX, CV_8UC1);
0134             break;
0135         case 3:
0136             cv::normalize(src, dst, 0, 255, cv::NORM_MINMAX, CV_8UC3);
0137             break;
0138         default:
0139             src.copyTo(dst);
0140             break;
0141     }
0142 
0143     return dst;
0144 }
0145 
0146 } // namespace Digikam