tensor2D eigenVectors(const tensor2D& t) { vector2D evals(eigenValues(t)); tensor2D evs ( eigenVector(t, evals.x()), eigenVector(t, evals.y()) ); return evs; }
tensor eigenVectors(const symmTensor& t) { vector evals(eigenValues(t)); tensor evs ( eigenVector(t, evals.x()), eigenVector(t, evals.y()), eigenVector(t, evals.z()) ); return evs; }
TqrEigenDecomposition::TqrEigenDecomposition(const Array& diag, const Array& sub, EigenVectorCalculation calc, ShiftStrategy strategy) : iter_(0), d_(diag), ev_((calc == WithEigenVector)? d_.size() : (calc == WithoutEigenVector)? 0 : 1, d_.size(), 0) { Size n = diag.size(); QL_REQUIRE(n == sub.size()+1, "Wrong dimensions"); Array e(n, 0.0); std::copy(sub.begin(),sub.end(),e.begin()+1); Size i; for (i=0; i < ev_.rows(); ++i) { ev_[i][i] = 1.0; } for (Size k=n-1; k >=1; --k) { while (!offDiagIsZero(k, e)) { Size l = k; while (--l > 0 && !offDiagIsZero(l,e)); iter_++; Real q = d_[l]; if (strategy != NoShift) { // calculated eigenvalue of 2x2 sub matrix of // [ d_[k-1] e_[k] ] // [ e_[k] d_[k] ] // which is closer to d_[k+1]. // FLOATING_POINT_EXCEPTION const Real t1 = std::sqrt( 0.25*(d_[k]*d_[k] + d_[k-1]*d_[k-1]) - 0.5*d_[k-1]*d_[k] + e[k]*e[k]); const Real t2 = 0.5*(d_[k]+d_[k-1]); const Real lambda = (std::fabs(t2+t1 - d_[k]) < std::fabs(t2-t1 - d_[k]))? t2+t1 : t2-t1; if (strategy == CloseEigenValue) { q-=lambda; } else { q-=((k==n-1)? 1.25 : 1.0)*lambda; } } // the QR transformation Real sine = 1.0; Real cosine = 1.0; Real u = 0.0; bool recoverUnderflow = false; for (Size i=l+1; i <= k && !recoverUnderflow; ++i) { const Real h = cosine*e[i]; const Real p = sine*e[i]; e[i-1] = std::sqrt(p*p+q*q); if (e[i-1] != 0.0) { sine = p/e[i-1]; cosine = q/e[i-1]; const Real g = d_[i-1]-u; const Real t = (d_[i]-g)*sine+2*cosine*h; u = sine*t; d_[i-1] = g + u; q = cosine*t - h; for (Size j=0; j < ev_.rows(); ++j) { const Real tmp = ev_[j][i-1]; ev_[j][i-1] = sine*ev_[j][i] + cosine*tmp; ev_[j][i] = cosine*ev_[j][i] - sine*tmp; } } else { // recover from underflow d_[i-1] -= u; e[l] = 0.0; recoverUnderflow = true; } } if (!recoverUnderflow) { d_[k] -= u; e[k] = q; e[l] = 0.0; } } } // sort (eigenvalues, eigenvectors), // code taken from symmetricSchureDecomposition.cpp std::vector<std::pair<Real, std::vector<Real> > > temp(n); std::vector<Real> eigenVector(ev_.rows()); for (i=0; i<n; i++) { if (ev_.rows() > 0) std::copy(ev_.column_begin(i), ev_.column_end(i), eigenVector.begin()); temp[i] = std::make_pair(d_[i], eigenVector); } std::sort(temp.begin(), temp.end(), std::greater<std::pair<Real, std::vector<Real> > >()); // first element is positive for (i=0; i<n; i++) { d_[i] = temp[i].first; Real sign = 1.0; if (ev_.rows() > 0 && temp[i].second[0]<0.0) sign = -1.0; for (Size j=0; j<ev_.rows(); ++j) { ev_[j][i] = sign * temp[i].second[j]; } } }
void CVDataFilter::Paint(CVPipeline * pipe) { if (returnType == CVReturnType::QUADS) { // Draw quads. if (!pipe->quads.Size()) return; // Copy original input pipe->initialInput.copyTo(pipe->output); // Convert to color if needed. int channelsBefore = pipe->output.channels(); if (channelsBefore == 1) { // pipe->output.convertTo(pipe->output, CV_8UC3); cv::cvtColor(pipe->output, pipe->output, CV_GRAY2RGB); } int channelsAfter = pipe->output.channels(); // o.o Paste! for (int i = 0; i < pipe->quads.Size(); ++i) { Quad quad = pipe->quads[i]; #define RGB(r,g,b) cv::Scalar(b,g,r) rng = cv::RNG(1344); cv::Scalar color = RGB(rng.uniform(0, 255),rng.uniform(0, 255),rng.uniform(0, 255)); // cv::Mat rectImage = cv::Mat::zeros(pipe->output.size(), CV_8UC3); cv::rectangle(pipe->output, cv::Point(quad.point1.x, quad.point1.y), cv::Point(quad.point3.x, quad.point3.y), color, CV_FILLED); float alpha = 0.2f; float beta = 1 - alpha; // cv::addWeighted(rectImage, alpha, pipe->output, beta, 0.0, pipe->output); // rectImage.copyTo(pipe->output); } } else if (returnType == CVReturnType::APPROXIMATED_POLYGONS) { // Copy original input.. pipe->initialInput.copyTo(pipe->output); RenderPolygons(pipe); } else if (returnType == CVReturnType::CV_IMAGE) { // Do nothing as the image should already be in the ouput matrix of the pipeline. } else if (returnType == CVReturnType::LINES || returnType == CVReturnType::CV_LINES) { // Convert the color to colors again for visualization... pipe->initialInput.copyTo(pipe->output); for( size_t i = 0; i < pipe->lines.Size(); i++ ) { Line & line = pipe->lines[i]; // Multiply the line coordinates with the last used inverted scale. line.start *= pipe->currentScaleInv; line.stop *= pipe->currentScaleInv; cv::line( pipe->output, cv::Point(line.start.x, line.start.y), cv::Point(line.stop.x, line.stop.y), cv::Scalar(0,0,255), 3, 8 ); } } else if (returnType == CVReturnType::CV_CONTOURS) { pipe->initialInput.copyTo(pipe->output); RenderContours(pipe); } switch(returnType) { case CVReturnType::CV_CONTOUR_SEGMENTS: { // Render shit! pipe->initialInput.copyTo(pipe->output); RenderContourSegments(pipe); break; } } if (returnType == CVReturnType::CV_CONTOUR_ELLIPSES) { pipe->initialInput.copyTo(pipe->output); RenderContours(pipe); RenderContourBounds(pipe); } else if (returnType == CVReturnType::CV_CONVEX_HULLS) { pipe->initialInput.copyTo(pipe->output); RenderContours(pipe); RenderConvexHulls(pipe); } else if (returnType == CVReturnType::CV_CONVEXITY_DEFECTS) { pipe->initialInput.copyTo(pipe->output); RenderContours(pipe); RenderConvexHulls(pipe); RenderConvexityDefects(pipe); } else if (returnType == CVReturnType::HANDS) { // Convert image to RGB for easier display int channelsBefore = pipe->initialInput.channels(); // cv::cvtColor(*pipe->initialInput, pipe->output, CV_GRAY2RGB); pipe->initialInput.copyTo(pipe->output); int channelsAfter = pipe->output.channels(); // Check if we got contour-segments, if so prioritize them. RenderHands(pipe); } else if (returnType == CVReturnType::FINGER_STATES) { // Render the last known one. pipe->initialInput.copyTo(pipe->output); FingerState & state = pipe->fingerStates.Last(); cv::Scalar color(255,0,0,255); for (int i = 0; i < state.positions.Size(); ++i) { Vector3f pos = state.positions[i]; cv::circle(pipe->output, cv::Point(pos.x, pos.y), 5, color, 3); } } else if (returnType == CVReturnType::POINT_CLOUDS) { pipe->initialInput.copyTo(pipe->output); for (int i = 0; i < pipe->pointClouds.Size(); ++i) { int r,g,b,a; r = g = b = a = 255; if (i % 2 == 0) g = 0; if (i % 4 == 0) b = 0; cv::Scalar color(r,g,b,a); CVPointCloud & pc = pipe->pointClouds[i]; for (int j = 0; j < pc.points.Size(); ++j) { Vector2f & pos = pc.points[j]; cv::circle(pipe->output, cv::Point(pos.x, pos.y), 2, color, 3); } /// Render PCA data if applicable. for (int j = 0; j < pc.eigenVectors.Size(); ++j) { cv::Scalar color = j == 0? CV_RGB(255, 255, 0) : CV_RGB(0, 255, 255); cv::Point2f eigenVector(pc.eigenVectors[j].x, pc.eigenVectors[j].y); float eigenValue = pc.eigenValues[j]; cv::Point2f scaledEigenVector = eigenVector * eigenValue * 0.02; cv::Point2f pcaCenter(pc.pcaCenter.x, pc.pcaCenter.y); circle(pipe->output, pcaCenter, 3, CV_RGB(255, 0, 255), 2); line(pipe->output, pcaCenter, pcaCenter + scaledEigenVector, color); } } } else if (returnType == CVReturnType::CV_OPTICAL_FLOW) { // http://stackoverflow.com/questions/7693561/opencv-displaying-a-2-channel-image-optical-flow // Split the coordinates. /* cv::Mat xy[2]; cv::split(pipe->opticalFlow, xy); cv::Mat magnitude, angle; // Fetch matrix from pipeline. cv::cartToPolar(xy[0], xy[1], magnitude, angle, true); double magMax; cv::minMaxLoc(magnitude, 0, &magMax); magnitude.convertTo(magnitude, -1, 1.0 / magMax); // Build HSV image? cv::Mat hsvChannels[3], hsv; hsvChannels[0] = angle; hsvChannels[1] = cv::Mat::ones(angle.size(), CV_32F); hsvChannels[2] = magnitude; cv::merge(hsvChannels, 3, hsv); // Convert to rgb and send to output. cv::cvtColor(hsv, pipe->output, cv::COLOR_HSV2RGB); */ } else if (returnType == CVReturnType::NOTHING) { // Nothing to render... } else if (returnType == -1) { // Nothing to render if error. std::cout<<"\nreturnType variable in filter "<<name<<" not set!"; } else if (returnType == CVReturnType::RENDER) // Nothing to render if render. ; else ; // std::cout<<"\nCVDataFilter::Paint called. Forgot to subclass the paint-method?"; }
PCA& PCA::fit( const std::vector< std::vector< double > >& data ) { const size_t nSamples = data.size(); const size_t nFeatures = data.front().size(); // Calculate the means vector arma::mat meansVector( nFeatures, 1 ); for ( size_t iFeature = 0; iFeature < nFeatures; ++iFeature ) { double sx = 0; for ( size_t iSample = 0; iSample < nSamples; ++iSample ) { const double value = data[iSample][iFeature]; if ( std::isnan(value) ) throw std::runtime_error( "PCA::fit : nan value encountered at input!" ); sx += value; } meansVector(iFeature, 0) = sx / nSamples; } // Construct the covariance matrix from the scatter matrix arma::mat covMatrix( nFeatures, nFeatures, arma::fill::zeros ); for ( size_t iSample = 0; iSample < nSamples; ++iSample ) { arma::mat sampleData( data[iSample ] ); arma::mat d = sampleData - meansVector; covMatrix += d * d.t(); } covMatrix /= nSamples; // Now find the eigenvalues and eigenvectors arma::cx_vec eigval; arma::cx_mat eigvec; bool result = arma::eig_gen(eigval, eigvec, covMatrix ); if (! result ) { throw std::runtime_error("PCA::fit : eigenvalue decomposition failed!"); } // Normalise the eigenvalues m_eigPairs.clear(); m_eigPairs.reserve( nFeatures ); double eigSum = 0; for ( size_t iFeature = 0; iFeature < nFeatures; ++iFeature ) { const double eigMagnitude = std::abs( eigval(iFeature) ); arma::cx_vec eigenVectorFromCalculation = eigvec.row( iFeature ); std::vector<double> eigenVector( nFeatures, 0.0 ); for (size_t j = 0; j < nFeatures; ++j ) eigenVector[j] = eigenVectorFromCalculation(j).real(); m_eigPairs.push_back( std::make_pair( eigMagnitude, eigenVector ) ); eigSum += eigMagnitude; } for ( size_t iFeature = 0; iFeature < nFeatures; ++iFeature ) { m_eigPairs[iFeature].first /= eigSum; } // Sort the eigenValues std::sort( m_eigPairs.begin(), m_eigPairs.end(), [] (const std::pair<double, std::vector<double> >&a, const std::pair<double, std::vector<double> >&b ) { return a.first > b.first; } ); return *this; }
SymmetricSchurDecomposition::SymmetricSchurDecomposition(const Matrix & s) : diagonal_(s.rows()), eigenVectors_(s.rows(), s.columns(), 0.0) { QL_REQUIRE(s.rows() > 0 && s.columns() > 0, "null matrix given"); QL_REQUIRE(s.rows()==s.columns(), "input matrix must be square"); Size size = s.rows(); for (Size q=0; q<size; q++) { diagonal_[q] = s[q][q]; eigenVectors_[q][q] = 1.0; } Matrix ss = s; std::vector<Real> tmpDiag(diagonal_.begin(), diagonal_.end()); std::vector<Real> tmpAccumulate(size, 0.0); Real threshold, epsPrec = 1e-15; bool keeplooping = true; Size maxIterations = 100, ite = 1; do { //main loop Real sum = 0; for (Size a=0; a<size-1; a++) { for (Size b=a+1; b<size; b++) { sum += std::fabs(ss[a][b]); } } if (sum==0) { keeplooping = false; } else { /* To speed up computation a threshold is introduced to make sure it is worthy to perform the Jacobi rotation */ if (ite<5) threshold = 0.2*sum/(size*size); else threshold = 0.0; Size j, k, l; for (j=0; j<size-1; j++) { for (k=j+1; k<size; k++) { Real sine, rho, cosin, heig, tang, beta; Real smll = std::fabs(ss[j][k]); if(ite> 5 && smll<epsPrec*std::fabs(diagonal_[j]) && smll<epsPrec*std::fabs(diagonal_[k])) { ss[j][k] = 0; } else if (std::fabs(ss[j][k])>threshold) { heig = diagonal_[k]-diagonal_[j]; if (smll<epsPrec*std::fabs(heig)) { tang = ss[j][k]/heig; } else { beta = 0.5*heig/ss[j][k]; tang = 1.0/(std::fabs(beta)+ std::sqrt(1+beta*beta)); if (beta<0) tang = -tang; } cosin = 1/std::sqrt(1+tang*tang); sine = tang*cosin; rho = sine/(1+cosin); heig = tang*ss[j][k]; tmpAccumulate[j] -= heig; tmpAccumulate[k] += heig; diagonal_[j] -= heig; diagonal_[k] += heig; ss[j][k] = 0.0; for (l=0; l+1<=j; l++) jacobiRotate_(ss, rho, sine, l, j, l, k); for (l=j+1; l<=k-1; l++) jacobiRotate_(ss, rho, sine, j, l, l, k); for (l=k+1; l<size; l++) jacobiRotate_(ss, rho, sine, j, l, k, l); for (l=0; l<size; l++) jacobiRotate_(eigenVectors_, rho, sine, l, j, l, k); } } } for (k=0; k<size; k++) { tmpDiag[k] += tmpAccumulate[k]; diagonal_[k] = tmpDiag[k]; tmpAccumulate[k] = 0.0; } } } while (++ite<=maxIterations && keeplooping); QL_ENSURE(ite<=maxIterations, "Too many iterations (" << maxIterations << ") reached"); // sort (eigenvalues, eigenvectors) std::vector<std::pair<Real, std::vector<Real> > > temp(size); std::vector<Real> eigenVector(size); Size row, col; for (col=0; col<size; col++) { std::copy(eigenVectors_.column_begin(col), eigenVectors_.column_end(col), eigenVector.begin()); temp[col] = std::make_pair(diagonal_[col], eigenVector); } std::sort(temp.begin(), temp.end(), std::greater<std::pair<Real, std::vector<Real> > >()); Real maxEv = temp[0].first; for (col=0; col<size; col++) { // check for round-off errors diagonal_[col] = (std::fabs(temp[col].first/maxEv)<1e-16 ? 0.0 : temp[col].first); Real sign = 1.0; if (temp[col].second[0]<0.0) sign = -1.0; for (row=0; row<size; row++) { eigenVectors_[row][col] = sign * temp[col].second[row]; } } }