// // createBoW // // @param[in] feature_vectors...extracted features. // 複数の特徴ベクトルであることに注意 // @param[in] codebook...calculated codebook. // @param[out] bow...output bag-of-words. // void createBoW ( const cv::Mat &feature_vectors, const codebook &codebook, std::vector<float> &bow) { // 各特徴ベクトルに関して最近傍のvisual-wordを見つけて投票 int num_feature_vectors = feature_vectors.rows; int codebook_size = codebook.rows; assert (codebook_size != 0); // 最も近いvisual-wordのインデックス cv::Mat indices = cv::Mat::zeros (num_feature_vectors, codebook_size, CV_32SC1); // その距離 cv::Mat dists = cv::Mat::zeros (num_feature_vectors, codebook_size, CV_64FC1); // kD-tree cv::flann::Index flannIndex (codebook, cv::flann::KDTreeIndexParams ()); cv::flann::SearchParams searchParams = cv::flann::SearchParams (); // Nearest Neighbor flannIndex.knnSearch (feature_vectors, indices, dists, codebook_size, searchParams); // Create histogram std::vector<int> hist (codebook.rows); std::fill (hist.begin (), hist.end (), 0); for (int j = 0; j < indices.rows; j++) { // 現在は最近傍法なのでindicesの最初の要素だけを見ればよい int idx = indices.at<int> (j, 0); // FIXME: 画素アクセス hist[idx]++; } // Normalization // 局所特徴の総数でヒストグラムの各binを割る assert (bow.empty ()); for (int i = 0; i < hist.size (); ++i) { float val_normalized = (float) hist[i] / (float) num_feature_vectors; bow.push_back (val_normalized); } // (0, 1]の間で正規化する SG::normalizeVector (bow); }
WeightedGraph kNearestGraph(const Mat_<Vec3f> &image, const Mat_<float> mask, int k, double (*simFunc)(const Mat&, const Mat&), bool bidirectional) { vector<int> indexToVertex; Mat features = pixelFeatures(image, mask, indexToVertex, positionHueFeature, 3); flann::Index flannIndex(features, flann::KMeansIndexParams(16, 3)); WeightedGraph nnGraph(image.rows * image.cols); set<pair<int,int> > edges; // for each feature, determine the k nearest neighbors and add them // as edges to the graph. for (int i = 0; i < features.rows; i++) { vector<int> indices(k + 1); vector<float> distances(k + 1); flannIndex.knnSearch(features.row(i), indices, distances, k + 1); int source = indexToVertex[i]; for (int j = 0; j < k + 1; j++) { if (indices[j] != i) { int destination = indexToVertex[indices[j]]; int first = min(source, destination); int second = max(source, destination); if (edges.find(pair<int,int>(first, second)) == edges.end()) { float weight = (float)simFunc(features.row(i), features.row(indices[j])); edges.insert(pair<int,int>(first, second)); nnGraph.addEdge(source, destination, weight); if (bidirectional) { nnGraph.addEdge(destination, source, weight); } } } } } return nnGraph; }
bool ofxFeatureFinder::detectObject(ofxFeatureFinderObject object, cv::Mat &homography) { //////////////////////////// // NEAREST NEIGHBOR MATCHING USING FLANN LIBRARY (included in OpenCV) ////////////////////////// cv::Mat results; cv::Mat dists; int k=2; // find the 2 nearest neighbors // assume it is CV_32F // Create Flann KDTree index cv::flann::Index flannIndex(imageDescriptors, cv::flann::KDTreeIndexParams(), cvflann::FLANN_DIST_EUCLIDEAN); results = cv::Mat(object.descriptors.rows, k, CV_32SC1); // Results index dists = cv::Mat(object.descriptors.rows, k, CV_32FC1); // Distance results are CV_32FC1 // search (nearest neighbor) flannIndex.knnSearch(object.descriptors, results, dists, k, cv::flann::SearchParams() ); // Find correspondences by NNDR (Nearest Neighbor Distance Ratio) float nndrRatio = 0.6; std::vector<cv::Point2f> mpts_1, mpts_2; // Used for homography std::vector<int> indexes_1, indexes_2; // Used for homography std::vector<uchar> outlier_mask; // Used for homography for(unsigned int i=0; i<object.descriptors.rows; ++i) { // Check if this descriptor matches with those of the objects // Apply NNDR if(dists.at<float>(i,0) <= nndrRatio * dists.at<float>(i,1)) { mpts_1.push_back(object.keypoints.at(i).pt); indexes_1.push_back(i); mpts_2.push_back(imageKeypoints.at(results.at<int>(i,0)).pt); indexes_2.push_back(results.at<int>(i,0)); } } // FIND HOMOGRAPHY if(mpts_1.size() >= minMatchCount) { homography = findHomography(mpts_1, mpts_2, cv::RANSAC, 1.0, outlier_mask); uint inliers=0, outliers=0; for(unsigned int k=0; k<mpts_1.size(); ++k) { if(outlier_mask.at(k)) { ++inliers; } else { ++outliers; } } cout << inliers << " in / " << outliers << " out" << endl; return true; } return false; }
void locallyLinearEmbeddings(const Mat_<float> &samples, int outDim, Mat_<float> &embeddings, int k) { assert(outDim < samples.cols); assert(k >= 1); Mat_<int> nearestNeighbors(samples.rows, k); // determining k nearest neighbors for each sample flann::Index flannIndex(samples, flann::LinearIndexParams()); for (int i = 0; i < samples.rows; i++) { Mat_<int> nearest; Mat dists; flannIndex.knnSearch(samples.row(i), nearest, dists, k + 1); nearest.colRange(1, nearest.cols).copyTo(nearestNeighbors.row(i)); } // determining weights for each sample vector<Triplet<double> > tripletList; tripletList.reserve(samples.rows * k); for (int i = 0; i < samples.rows; i++) { Mat_<double> C(k,k); for (int u = 0; u < k; u++) { for (int v = u; v < k; v++) { C(u,v) = (samples.row(i) - samples.row(nearestNeighbors(i,u))).dot(samples.row(i) - samples.row(nearestNeighbors(i,v))); C(v,u) = C(u,v); } } // regularize when the number of neighbors is greater than the input // dimension if (k > samples.cols) { C = C + Mat_<double>::eye(k,k) * 10E-3 * trace(C)[0]; } Map<MatrixXd,RowMajor> eigC((double*)C.data, C.rows, C.cols); LDLT<MatrixXd> solver(eigC); Mat_<double> weights(k,1); Map<MatrixXd,RowMajor> eigWeights((double*)weights.data, weights.rows, weights.cols); eigWeights = solver.solve(MatrixXd::Ones(k,1)); Mat_<double> normWeights; double weightsSum = sum(weights)[0]; if (weightsSum == 0) { cout<<"error: cannot reconstruct point "<<i<<" from its neighbors"<<endl; exit(EXIT_FAILURE); } normWeights = weights / weightsSum; for (int j = 0; j < k; j++) { tripletList.push_back(Triplet<double>(nearestNeighbors(i,j), i, normWeights(j))); } } SparseMatrix<double> W(samples.rows, samples.rows); W.setFromTriplets(tripletList.begin(), tripletList.end()); // constructing vectors in lower dimensional space from the weights VectorXd eigenvalues; MatrixXd eigenvectors; LLEMult mult(&W); symmetricSparseEigenSolver(samples.rows, "SM", outDim + 1, samples.rows, eigenvalues, eigenvectors, mult); embeddings = Mat_<double>(samples.rows, outDim); if (DEBUG_LLE) { cout<<"actual eigenvalues : "<<eigenvalues<<endl; cout<<"actual : "<<endl<<eigenvectors<<endl; MatrixXd denseW(W); MatrixXd tmp = MatrixXd::Identity(W.rows(), W.cols()) - denseW; MatrixXd M = tmp.transpose() * tmp; SelfAdjointEigenSolver<MatrixXd> eigenSolver(M); MatrixXd expectedEigenvectors = eigenSolver.eigenvectors(); cout<<"expected eigenvalues : "<<eigenSolver.eigenvalues()<<endl; cout<<"expected : "<<endl<<expectedEigenvectors<<endl; } for (int i = 0; i < samples.rows; i++) { for (int j = 0; j < outDim; j++) { embeddings(i,j) = eigenvectors(i, j + 1); } } }
// Main function, defines the entry point for the program. int main( int argc, char** argv ) { // Structure for getting video from camera or avi CvCapture* capture = 0; // Images to capture the frame from video or camera or from file IplImage *frame, *frame_copy = 0; // Input file name for avi or image file. const char* vectorList; const char* testImage; // Check for the correct usage of the command line if( argc == 2 ) { //vectorList = argv[1]; testImage = argv[1]; } else { fprintf( stderr, "Usage: eigenDecomp testImage\n" ); return -1; } // Allocate the memory storage storage = cvCreateMemStorage(0); // Create a new named window with title: result cvNamedWindow( "result", 1 ); std::vector<IplImage*> images; std::vector<char*> labels; //Load Labels printf("Loading Labels... "); FILE* f = fopen( "labels.txt", "rt" ); if( f ) { char buf[100+1]; // Get the line from the file while( fgets( buf, 100, f ) ) { // Remove the spaces if any, and clean up the name int len = (int)strlen(buf); while( len > 0 && isspace(buf[len-1]) ) len--; buf[len] = '\0'; char* str = (char*)malloc(sizeof(char)*100); memcpy(str, buf, 100); labels.push_back(str); } // Close the file fclose(f); printf("%d Labels loaded.\n", labels.size()); } else printf("Failed.\n"); //Load Eigenvectors: printf("Loading Eigenvectors... "); CvFileStorage* fs2 = cvOpenFileStorage("eigenvectors.yml", NULL, CV_STORAGE_READ); char vectorname[50]; CvFileNode* vectorloc = cvGetFileNodeByName(fs2, NULL, "vector0"); for(int i = 1; vectorloc != NULL; i++) { images.push_back((IplImage*)cvRead(fs2, vectorloc, &cvAttrList(0,0))); //printf("pushed %s\n", vectorname); sprintf(vectorname, "vector%d", i); vectorloc = cvGetFileNodeByName(fs2, NULL, vectorname); } //cvReleaseFileStorage(&fs2); This may delete the images printf("%d Eigenvectors (and 1 average) loaded.\n", images.size()-1); //TODO: unfix this number! - Done! //printf("FLANN DIMS: %d, %d\n", 165, images.size()); //cv::Mat mat( 165, images.size(), CV_32F ); //flann::Matrix<float> flannmat; //flann::load_from_file(flannmat, "flann.dat", "flann.dat"); //flann::Index::Index flannIndex(flannmat, flann::LinearIndexParams()); printf("Loading Nearest Neighbor Matrix... "); CvMat* flannmat; CvFileStorage* fs = cvOpenFileStorage("nn.yml", NULL, CV_STORAGE_READ); flannmat = (CvMat*)cvRead(fs, cvGetFileNodeByName(fs, NULL, "data"), &cvAttrList(0,0)); //cvReleaseFileStorage(&fs); This will delete the matrix printf("Done. DIMS: %d, %d\n", flannmat->rows, flannmat->cols); cv::flann::Index::Index flannIndex(flannmat, cv::flann::LinearIndexParams()); int nn_dims = flannmat->cols; //number of nearest neighbor dimensions available int projection_dims = images.size()-1; //number of dimensions to project into eigenspace. IplImage* eigenArray[projection_dims]; IplImage* avgImage = images[0]; for(int i = 0; i < projection_dims; i++) { eigenArray[i] = images[i+1]; } //load test image printf("Loading Test Image...\n"); IplImage* testImg = cvLoadImage(testImage, CV_LOAD_IMAGE_GRAYSCALE); float projection[projection_dims]; // Project the test image onto the PCA subspace printf("Conducting Eigen Decomposite...\n"); cvEigenDecomposite( testImg, //test object projection_dims, //number of eigen vectors (void*)eigenArray, //eigenVectors 0, 0, //ioflags, user callback data avgImage, //root eigen vector projection); //print projection //printf("Eigenvector Coefficents:\n"); //for(int i = 0; i < projection_dims; i++) //printf("%5f ", projection[i]); //printf("\n"); int neighbors = 10; //to test against std::vector<float> proj(nn_dims); std::vector<float> dists(neighbors); std::vector<int> indicies(neighbors); for(int i = 0; i < nn_dims; i++) proj[i] = projection[i]; flannIndex.knnSearch(proj, indicies, dists, neighbors, NULL); for(int i = 0; i < neighbors; i++) printf("Index Match0: %4d, dist: %13.3f, Label: %s\n", indicies[i], dists[i], labels[indicies[i]]); // Destroy the window previously created with filename: "result" cvDestroyWindow("result"); printf("Done.\n"); // return 0 to indicate successfull execution of the program return 0; }
int main(int argc, char * argv[]) { bool quiet = false; int method = mTotal; //total matches if(argc<3) { printf("Two images required!\n"); showUsage(); } else if(argc>3) { for(int i=1; i<argc-2; ++i) { if(std::string(argv[i]).compare("-inliers") == 0) { method = mInliers; } else if(std::string(argv[i]).compare("-quiet") == 0) { quiet = true; } else { printf("Option %s not recognized!", argv[1]); showUsage(); } } } //Load as grayscale cv::Mat objectImg = cv::imread(argv[argc-2], cv::IMREAD_GRAYSCALE); cv::Mat sceneImg = cv::imread(argv[argc-1], cv::IMREAD_GRAYSCALE); int value = 0; if(!objectImg.empty() && !sceneImg.empty()) { std::vector<cv::KeyPoint> objectKeypoints; std::vector<cv::KeyPoint> sceneKeypoints; cv::Mat objectDescriptors; cv::Mat sceneDescriptors; //////////////////////////// // EXTRACT KEYPOINTS //////////////////////////// cv::SIFT sift; sift.detect(objectImg, objectKeypoints); sift.detect(sceneImg, sceneKeypoints); //////////////////////////// // EXTRACT DESCRIPTORS //////////////////////////// sift.compute(objectImg, objectKeypoints, objectDescriptors); sift.compute(sceneImg, sceneKeypoints, sceneDescriptors); //////////////////////////// // NEAREST NEIGHBOR MATCHING USING FLANN LIBRARY (included in OpenCV) //////////////////////////// cv::Mat results; cv::Mat dists; std::vector<std::vector<cv::DMatch> > matches; int k=2; // find the 2 nearest neighbors // Create Flann KDTree index cv::flann::Index flannIndex(sceneDescriptors, cv::flann::KDTreeIndexParams(), cvflann::FLANN_DIST_EUCLIDEAN); results = cv::Mat(objectDescriptors.rows, k, CV_32SC1); // Results index dists = cv::Mat(objectDescriptors.rows, k, CV_32FC1); // Distance results are CV_32FC1 // search (nearest neighbor) flannIndex.knnSearch(objectDescriptors, results, dists, k, cv::flann::SearchParams() ); //////////////////////////// // PROCESS NEAREST NEIGHBOR RESULTS //////////////////////////// // Find correspondences by NNDR (Nearest Neighbor Distance Ratio) float nndrRatio = 0.6; std::vector<cv::Point2f> mpts_1, mpts_2; // Used for homography std::vector<int> indexes_1, indexes_2; // Used for homography std::vector<uchar> outlier_mask; // Used for homography // Check if this descriptor matches with those of the objects for(int i=0; i<objectDescriptors.rows; ++i) { // Apply NNDR if(dists.at<float>(i,0) <= nndrRatio * dists.at<float>(i,1)) { mpts_1.push_back(objectKeypoints.at(i).pt); indexes_1.push_back(i); mpts_2.push_back(sceneKeypoints.at(results.at<int>(i,0)).pt); indexes_2.push_back(results.at<int>(i,0)); } } if(method == mInliers) { // FIND HOMOGRAPHY unsigned int minInliers = 8; if(mpts_1.size() >= minInliers) { cv::Mat H = findHomography(mpts_1, mpts_2, cv::RANSAC, 1.0, outlier_mask); int inliers=0, outliers=0; for(unsigned int k=0; k<mpts_1.size();++k) { if(outlier_mask.at(k)) { ++inliers; } else { ++outliers; } } if(!quiet) printf("Total=%d Inliers=%d Outliers=%d\n", (int)mpts_1.size(), inliers, outliers); value = (inliers*100) / (inliers+outliers); } } else { value = mpts_1.size(); } } else { printf("Images are not valid!\n"); showUsage(); } if(!quiet) printf("Similarity = %d\n", value); return value; }