dimanche 22 août 2021

Application crashes with global object declaration of class containing static variables

I have a class Texture containing few static variables which would act as look-up tables. These would be used to compute GLCM (Gray-Level Concurrence Matrix) properties. These are kept static because once generated, they could be shared between different objects of the same class irrespective of the number of objects created. Here is my class header.

texture.h

#pragma once
#ifndef TEXTURE_H
#define TEXTURE_H

#include <iostream>
#include <iomanip>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <algorithm>
#include <string>

class Texture
{
public:
    Texture();
    ~Texture();

private:

    const static int MAXIMUM_GLCM = 4; //!< Maximum number of GLCM matrices that would be computed (same as num of directions)

    const static int MAX_LEVELS = 256; //!< Maximum number of levels is assumed to be 256. A valid assumption for 8-bit gray-scale images.

    static cv::Mat lutWeights; //! @brief LUT to generate Contrast, Dissimilarity, Similarity and Homogeneity weights.
    static cv::Mat contrastWeights; //! @brief Container for Contrast and Homogeneity weights.
    static cv::Mat dissimilarWeights; //! @brief Container for Dissimilarity and Similarity weights.

    /*!
     * Generates a 256-element single channel LUT of of type CV_32F. The elements start from 0 and
     * increase linearly.
     * @param[in] None
     * @param[in] None
     * @param[out] None
     */
    static void generateLUT();

    /*!
     * Populates required weight matrices based on the LUT generates as part of generateLUT().
     * The generated weight matrices are single channel and of type CV_32F
     * @param[in] None
     * @param[in] None
     * @param[out] None
     */
    static void prepareWeightMatrices();
};
#endif // !TEXTURE_H

Following is my texture.cpp file.

#include "texture.h"
using namespace std;
using namespace cv; //!< /namespace for OpenCV

cv::Mat Texture::lutWeights = cv::Mat::zeros(cv::Size2i(Texture::MAX_LEVELS,1), CV_32FC1); //! @brief Intialise static LUT with zeros.
cv::Mat Texture::contrastWeights = cv::Mat::zeros(cv::Size2i(Texture::MAX_LEVELS, Texture::MAX_LEVELS), CV_32FC1); //! @brief Intialise static Contrast weights with zeros.
cv::Mat Texture::dissimilarWeights = cv::Mat::zeros(cv::Size2i(Texture::MAX_LEVELS, Texture::MAX_LEVELS), CV_32FC1); //! @brief Intialise static Dissimilarity weights with zeros.

void Texture::generateLUT()
{
    cout << "\ngenerateLUT()";
    for (int i = 0; i < lutWeights.cols; i++)
    {
        lutWeights.at<float>(i) = (float)i; //! Every index is an entry for the LUT.
    }
}

void Texture::prepareWeightMatrices()
{
    cout << "\nprepareWeightMatrices()";
    generateLUT(); //! Generate LUT

    int rowSpan = dissimilarWeights.rows - 1;
    cout << "\n rowSpan: " << rowSpan;
    for (int i = 0; i < rowSpan; i++)
    {
        lutWeights.colRange(1, (rowSpan +1) - i).copyTo(dissimilarWeights.row(i).colRange(i+1, rowSpan +1));
    }

    cv::completeSymm(dissimilarWeights, false); //! Mirror the upper triangle.
    cv::accumulateSquare(dissimilarWeights, contrastWeights); //! Elementwise square to generate contrast weights.
}

Now, the problem is if I declare a global object of the class, my application crashes. See below my main.cpp.

#include "texture.h"
using namespace std;

Texture texture;
int main()
{
    return(0);
}

However, a declaration of the object within main() works without any issues.

#include "texture.h"
using namespace std;

int main()
{
    Texture texture;
    return(0);
}

Debugging of the crash revealed that in the global declaration case, the weight matrices 'lutWeights', 'contrastWeights', and 'dissimilarWeights' are not getting initialised and crash occurs at cv::completeSymm(dissimilarWeights, false) in prepareWeightMatrices() function due to rowSpan coming to be -1. However, with local declaration the initialisation seems to be happening and rowSpan has the correct value of 255.

So, the questions are,

  1. Why the initialisation does not happen when the object is declared globally?
  2. How do I replicate the behaviour of local object declaration with global object declaration?
  3. From design perspective, even if this issue is fixed, should I be going ahead with this class definition or reevaluate my decision?

I am still exploring static member functions and variables of a class. Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire