openCV PCA C++ simple implementation

Hi,

I am new here. I am teaching myself openCV because I decided to relearn image processing. I am trying to use the PCA compression, but I am getting a blank image.

The references I have are:
https://docs.opencv.org/4.x/d3/d8d/classcv_1_1PCA.html
https://docs.opencv.org/4.x/d3/db0/samples_2cpp_2pca_8cpp-example.html#_a16

I have tried to make it very simple so, I only apply PCA to a single image.

static  Mat formatImagesForPCA(const Mat& data)
{
    Mat dst(1, data.rows * data.cols, CV_32F);

    Mat image_row = data.clone().reshape(1, 1);
    Mat row_i = dst;
    image_row.convertTo(row_i, CV_32F);
    return image_row;
}


Mat TestPCA(const Mat& img)
{
    Mat clone = convertograyScale(img);
    int rows = clone.rows;
    int channels = clone.channels();

    Mat pcaset = formatImagesForPCA(clone);

    PCA pca(pcaset,             // pass the data
        Mat(),              // we do not have a pre-computed mean vector,
        // so let the PCA engine to compute it
        PCA::DATA_AS_ROW,   // indicate that the vectors
        // are stored as matrix rows
        // (use PCA::DATA_AS_COL if the vectors are
        // the matrix columns)
        100000
    );

    Mat compressed = pca.project(pcaset);
    Mat reconstruction = pca.backProject(compressed); // re-create the image from the "point"
    reconstruction = reconstruction.reshape(1, rows);
    return reconstruction;
}

I have also tried to use

Mat pcaset = clone.reshape(1,1);

instead of

static Mat formatImagesForPCA(const Mat& data)

which I had to adapt to work with only one image and also think that the original code was wrong because it did this:

        Mat image_row = data[i].clone().reshape(1,1);
        Mat row_i = dst.row(i);
        image_row.convertTo(row_i,CV_32F);

Inside a loop and in the end, it just returned dst. Unless

Mat row_i = dst.row(i);

Creates an implicit reference I am not seeing.

I am using OpenCV 4.8
Visual Studio 2022
Windows 11

Thanks in advance.
Daniel

I have tried to make it very simple so, I only apply PCA to a single image.

unfortunately, this is your main problem.
PCA does not work with a single ‘data point’, and you won’t get any proper insight from the results

Inside a loop and in the end, it just returned dst. Unless
Mat row_i = dst.row(i);
Creates an implicit reference I am not seeing.

it does !
consider a simple:

float data[] = {1,2,3,4,5,6,7,8,9};
Mat m(3,3,CV_32F,data);
m.row(1) = 0; // overwrite 4,5,6
cout << m; // [1,2,3; 0,0,0; 7,8,9]

but I am getting a blank image.

it’s in [0,1} space, needs a scale or [0,255] normalization (see sample, again)

1 Like

what is the goal? clustering the colors in a picture? turning the colors into a palette?

Hi, thanks a lot for your explanations. I will go back to basics.

Something like

But I see this guy is using another library ( his example is in python but he is not using openCV to apply PCA. I misunderstood openCV approach. When I worked with image processing it was pre-filtering, and segmentation so I am now trying to advance beyond that.
thanks
Daniel