- added multiple format support for input data (now supports csv, tabs, ; and spaces)
[mldemos:baraks-mldemos.git] / _AlgorithmsPlugins / Projections / projectorPCA.cpp
1 #include "projectorPCA.h"
2 #include "widget.h"
3 #include <QPainter>
4
5 ProjectorPCA::ProjectorPCA()
6 {}
7
8 PCA ProjectorPCA::compressPCA(const Mat& pcaset, int maxComponents, const Mat& testset, Mat& compressed)
9 {
10     PCA pca(pcaset, // pass the data
11             Mat(), // we do not have a pre-computed mean vector,
12                    // so let the PCA engine to compute it
13             CV_PCA_DATA_AS_ROW, // indicate that the vectors
14                                 // are stored as matrix rows
15                                 // (use CV_PCA_DATA_AS_COL if the vectors are
16                                 // the matrix columns)
17             maxComponents // specify, how many principal components to retain
18             );
19     // if there is no test data, just return the computed basis, ready-to-use
20     if( !testset.data )
21         return pca;
22     CV_Assert( testset.cols == pcaset.cols );
23
24     compressed.create(testset.rows, maxComponents, testset.type());
25
26     Mat reconstructed;
27     for( int i = 0; i < testset.rows; i++ )
28     {
29         Mat vec = testset.row(i), coeffs = compressed.row(i);
30         // compress the vector, the result will be stored
31         // in the i-th row of the output matrix
32         pca.project(vec, coeffs);
33         // and then reconstruct it
34         pca.backProject(coeffs, reconstructed);
35         // and measure the error
36         //printf("");
37     }
38     return pca;
39 }
40
41 void ProjectorPCA::DrawEigenvals(QPainter &painter)
42 {
43     int w=painter.window().width();
44     int h=painter.window().height();
45     int pad = 5;
46
47     Mat& eigVal = pca.eigenvalues;
48     int dim = eigVal.rows;
49     float maxEigVal = 0;
50     FOR(i, dim) if(eigVal.at<float>(i) == eigVal.at<float>(i)) maxEigVal += eigVal.at<float>(i);
51     float accumulator = 0;
52     maxEigVal = max(1.f,maxEigVal);
53
54     painter.setPen(Qt::black);
55     painter.drawLine(QPointF(pad, h-2*pad), QPointF(w-2*pad, h-2*pad));
56     painter.drawLine(QPointF(pad, pad), QPointF(pad, h-2*pad));
57     painter.setRenderHint(QPainter::Antialiasing);
58     QPointF point(pad,pad);
59     painter.setPen(Qt::red);
60     FOR(i, dim)
61     {
62         float eigval = eigVal.at<float>(i);
63         if(eigval == eigval)
64         {
65             QPointF point2 = QPointF(i * (w-2*pad) / dim + pad+(!i?1:0), (h-2*pad) - (int)(eigval / maxEigVal * (h-2*pad)));
66             painter.drawLine(point, point2);
67             accumulator += eigval / maxEigVal;
68             point = point2;
69         }
70     }
71     painter.drawLine(point, QPoint(w-2*pad, h-2*pad));
72     QFont font = painter.font();
73     font.setPointSize(8);
74     painter.setFont(font);
75     painter.setPen(Qt::black);
76     painter.drawText(0,0,w,2*pad,Qt::AlignCenter, "reconstruction error");
77     FOR(i, dim)
78     {
79         int x = dim==1? w/2 : i*(w-2*pad)/(dim-1);
80         painter.drawText(pad + x - 3, h-1, QString("e%1").arg(i+1));
81     }
82 }
83
84 void ProjectorPCA::TrainPCA(std::vector<fvec> samples, int pcaCount)
85 {
86     if(!samples.size() || !samples[0].size()) return;
87
88     int count = samples.size();
89     int dim = samples[0].size();
90     pcaCount = min(dim, pcaCount);
91     Mat pcaData = Mat::zeros(count, dim, CV_32F);
92     FOR(i, count)
93     {
94         FOR(d,dim)
95         {
96             pcaData.at<float>(i,d) = samples[i][d];
97         }
98     }
99     Mat output;
100     pca = compressPCA(pcaData, pcaCount, pcaData, output);
101     projected = vector<fvec>(count);
102         vector<bool> bNan(pcaCount,false);
103         int nanCnt = 0;
104         FOR(d, pcaCount)
105         {
106                 if(bNan[d] = pca.eigenvalues.at<float>(d) != pca.eigenvalues.at<float>(d)) nanCnt++;
107         }
108     FOR(i, count)
109     {
110         projected[i].resize(pcaCount-nanCnt);
111                 int D = 0;
112         FOR(d, pcaCount)
113         {
114                         if(bNan[d]) continue;
115             projected[i][D] = output.at<float>(i,d);
116                         D++;
117         }
118     }
119 }
120
121 void ProjectorPCA::Train(std::vector< fvec > samples, int startIndex, int stopIndex)
122 {
123     if(!samples.size()) return;
124     dim = samples[0].size();
125     if(!dim) return;
126     if(stopIndex >= (int)dim) stopIndex = -1;
127     if(startIndex && startIndex >= (int)dim) startIndex = dim-1;
128     if(stopIndex != -1 && startIndex > stopIndex) stopIndex = startIndex;
129     int pcaCount = (stopIndex != -1) ? stopIndex+1 : min((int)dim, (int)samples.size()-1);
130     TrainPCA(samples, pcaCount);
131     if(startIndex)
132     {
133         vector<fvec> newProjected(projected.size());
134         if(!projected.size()) return;
135         int pDim = projected[0].size();
136         FOR(i, projected.size())
137         {
138             newProjected[i].resize(pDim - startIndex);
139             FOR(d, pDim - startIndex) newProjected[i][d] = projected[i][d + startIndex];
140         }
141     }
142 }
143
144 fvec ProjectorPCA::Project(const fvec &sample)
145 {
146 }
147
148 fvec ProjectorPCA::GetEigenValues()
149 {
150     fvec values(dim);
151     FOR(i, dim)
152     {
153         float eigval = pca.eigenvalues.at<float>(i);
154         values[i] = eigval;
155     }
156     return values;
157 }