// Computes an Lidfaces model with images in src and corresponding labels // in labels. void Lidfaces::train(cv::InputArrayOfArrays src, cv::InputArray labels) { std::vector<std::vector<cv::KeyPoint> > allKeyPoints; cv::Mat descriptors; // Get SIFT keypoints and LID descriptors detectKeypointsAndDescriptors(src, allKeyPoints, descriptors); // kmeans function requires points to be CV_32F descriptors.convertTo(descriptors, CV_32FC1); // Do k-means clustering const int CLUSTER_COUNT = params::lidFace::clustersAsPercentageOfKeypoints*descriptors.rows; cv::Mat histogramLabels; // This function populates histogram bin labels // The nth element of histogramLabels is an integer which represents the cluster that the // nth element of allKeyPoints is a member of. kmeans( descriptors, // The points we are clustering are the descriptors CLUSTER_COUNT, // The number of clusters (K) histogramLabels, // The label of the corresponding keypoint params::kmeans::termCriteria, params::kmeans::attempts, params::kmeans::flags, mCenters); // Convert to single channel 32 bit float as the matrix needs to be in a form supported // by calcHist histogramLabels.convertTo(histogramLabels, CV_32FC1); // We end up with a histogram for each image const size_t NUM_IMAGES = getSize(src); std::vector<cv::Mat> hists(NUM_IMAGES); // mCodebook.resize(NUM_IMAGES); // The histogramLabels vector contains ALL the points from EVERY image. We need to split // it up into groups of points for each image. // Because there are the same number of points in each image, and the points were put // into the labels vector in order, we can simply divide the labels vector evenly to get // the individual image's points. std::vector<cv::Mat> separatedLabels; for (unsigned int i = 0, startRow = 0; i < NUM_IMAGES; ++i) { separatedLabels.push_back( histogramLabels.rowRange( startRow, startRow + allKeyPoints[i].size())); startRow += allKeyPoints[i].size(); } // Populate the hists vector generateHistograms(hists, separatedLabels, CLUSTER_COUNT); // Make the magnitude of each histogram equal to 1 normalizeHistograms(hists); mCodebook = hists; mLabels = labels.getMat(); }
//________________________________________________________ void GFOverlay::Overlay(const TObjArray &dirs, const TObjArray &legends) { // 'directories' must contain TDirectory and inheriting, being parallel with legends TDirectory *dir1 = 0; for (Int_t iDir = 0; !dir1 && iDir < dirs.GetEntriesFast(); ++iDir) { dir1 = static_cast<TDirectory*>(dirs[iDir]); } if (!dir1) return; const Int_t currentLayer = fLayer; fLayer += (fSummaries ? 2 : 1); std::vector<TH1*> meanHists, rmsHists; UInt_t counter = 0; TIter nextKey(dir1->GetListOfKeys()); // // while(TKey* key = static_cast <TKey*> (nextKey())) { // // OK, make CINT happy, i.e. make .L GFOverlay.C work without extending '+': TKey* key = NULL; while ((key = static_cast <TKey*> (nextKey()))) { if (!fNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fNames)) continue; if (this->KeyContainsListMember(key->GetName(), fSkipNames)) continue; TObjArray hists(this->GetTypeWithNameFromDirs(TH1::Class(), key->GetName(), dirs)); if (this->AddHistsAt(hists, legends, currentLayer, counter) > 0) { if (fSummaries) { this->CreateFillMeanRms(hists, currentLayer, dir1->GetName(), meanHists, rmsHists); } ++counter; } TObjArray subDirs(this->GetTypeWithNameFromDirs(TDirectory::Class(), key->GetName(), dirs)); if (subDirs.GetEntries()) { // NOT GetEntriesFast()! ::Info("GFOverlay::Overlay", "Key '%s' has directories to do recursion.", key->GetName()); this->Overlay(subDirs, legends); } } // If mean/rms hists created, add them to manager: for (unsigned int iMean = 0; iMean < meanHists.size(); ++iMean) { fHistMan->AddHistSame(meanHists[iMean], currentLayer + 1, 0, legends[iMean]->GetName()); fHistMan->AddHistSame(rmsHists[iMean], currentLayer + 1, 1, legends[iMean]->GetName()); } }
Hists getHists(std::string inFileName,std::string title,bool istOnly = false,bool istPxl2Only = false) { TFile file(inFileName.c_str()); tpcResNtuple nt((TTree*)file.Get("nt")); Hists hists(title); for(int ii=0;ii<nt.GetEntries();++ii) { nt.GetEntry(ii); hists.h1McPt->Fill(nt.pt); if(nt.geantId!=8 || fabs(nt.eta)>0.5) continue; if(nt.gPt>1 && nt.gPt<5. && nt.nFit>20 && nt.nFit/nt.nMax>0.52) { hists.h1TpcMcPt->Fill(nt.pt); int hftTopo = static_cast<int>(nt.hftTopo); if(istOnly) { if(nt.isTrueHft && (hftTopo>>3 & 0x3)) { hists.h1HftMatchedMcPt->Fill(nt.pt); } } else if(istPxl2Only) { if(nt.isTrueHft && (hftTopo>>1 & 0x3) && (hftTopo>>3 & 0x3)) { hists.h1HftMatchedMcPt->Fill(nt.pt); } } else { if(nt.isTrueHft && ((hftTopo>>0 & 0x1) && (hftTopo>>1 & 0x3) && (hftTopo>>3 & 0x3)))
//________________________________________________________ void GFHistManager::DrawReally(Int_t layer) { if(layer < 0 || layer > fDepth-1) { this->Warning("DrawReally","Layer %d does not exist, possible are 0 to %d.", layer, fDepth-1); return; } this->MakeCanvases(layer); TIter canIter(static_cast<TObjArray*>(fCanArrays->At(layer))); TIter histIter(static_cast<TObjArray*>(fHistArrays->At(layer))); Int_t histNo = 0; // becomes number of histograms in layer while(TCanvas* can = static_cast<TCanvas*>(canIter.Next())){ Int_t nPads = this->NumberOfSubPadsOf(can); if (fNoX[layer] * fNoY[layer] != nPads && !(nPads == 0 && fNoX[layer] * fNoY[layer] == 1)) { this->Warning("Update", "inconsistent number of pads %d, expect %d*%d", nPads, fNoX[layer], fNoY[layer]); } for(Int_t i = 0; i <= nPads; ++i){ if (i == 0 && nPads != 0) i = 1; can->cd(i); if(GFHistArray* histsOfPad = static_cast<GFHistArray*>(histIter.Next())){ TIter hists(histsOfPad); TH1* firstHist = static_cast<TH1*>(hists.Next()); firstHist->Draw(); this->DrawFuncs(firstHist); while(TH1* h = static_cast<TH1*>(hists.Next())){ h->Draw(Form("SAME%s%s", (fSameWithStats ? "S" : ""), h->GetOption())); this->DrawFuncs(h); } if(histsOfPad->GetEntriesFast() > 1){ const Double_t max = this->MaxOfHists(histsOfPad); if(//firstHist->GetMaximumStored() != -1111. && ???? max > firstHist->GetMaximumStored()){ firstHist->SetMaximum((fLogY[layer] ? 1.1 : 1.05) * max); } const Double_t min = this->MinOfHists(histsOfPad); if(!(gStyle->GetHistMinimumZero() && min > 0.)) { firstHist->SetMinimum(min * 1.05); } } if(fLogY[layer] && (firstHist->GetMinimum() > 0. || (firstHist->GetMinimum() == 0. && firstHist->GetMinimumStored() == -1111.)))gPad->SetLogy(); // draw other objects: this->DrawObjects(layer, histNo); // make hist style differ if(fDrawDiffStyle) GFHistManager::MakeDifferentStyle(histsOfPad); // draw legends on top of all if(fLegendArrays && layer <= fLegendArrays->GetLast() && fLegendArrays->At(layer)){ this->DrawLegend(layer, histNo); } gPad->Modified(); this->ColourFuncs(histsOfPad); if (fSameWithStats) { gPad->Update(); // not nice to need this here, makes use over network impossible... this->ColourStatsBoxes(histsOfPad); } histNo++; } } // loop over pads } // loop over canvases }
// Predicts the label and confidence for a given sample. void Lidfaces::predict(cv::InputArray src, int& label, double& dist) const { label = -1; dist = DBL_MAX; std::vector<std::vector<cv::KeyPoint> > keyPoints; cv::Mat descriptors; std::vector<cv::Mat> imageVector; // A vector containing just one image (this is so we can use the same detectKeypointsAndDescriptors function imageVector.push_back(src.getMat()); // Get SIFT keypoints and LID descriptors detectKeypointsAndDescriptors(imageVector, keyPoints, descriptors); // Cluster the image using the training centres int closestCentroidIndex = 0; mCenters.convertTo(mCenters, CV_32FC1); descriptors.convertTo(descriptors, CV_32FC1); cv::Mat histogramLabels(descriptors.rows, 1, CV_32F); // For each descriptor for (int descriptorIndex = 0; descriptorIndex < descriptors.rows; ++descriptorIndex) { // (Give it a classification) double smallestDist = DBL_MAX; // For each centroid for (int centroidIndex = 0; centroidIndex < mCenters.rows; ++centroidIndex) { // Calculate the distance from the descriptor to the centroid double currentDist = cv::norm( descriptors.row(descriptorIndex) - mCenters.row(centroidIndex)); // If it is the smallest distance, remember it and the centroid if (currentDist < smallestDist) { smallestDist = currentDist; closestCentroidIndex = centroidIndex; } } histogramLabels.at<float>(descriptorIndex) = closestCentroidIndex; } assert(histogramLabels.rows == descriptors.rows); std::vector<cv::Mat> separatedLabels; std::vector<cv::Mat> hists(1); separatedLabels.push_back(histogramLabels); generateHistograms(hists, separatedLabels, mCenters.rows); normalizeHistograms(hists); dist = DBL_MAX; std::multimap<int, double> distances; // Maps label to distance // Compare this histogram against all the other histograms for (size_t codebookIndex = 0; codebookIndex < mCodebook.size(); ++codebookIndex) { // Get dist hist double currentDist = cv::compareHist(hists[0], mCodebook[codebookIndex], CV_COMP_CHISQR); distances.insert(std::pair<int, double>(mLabels.at<int>(codebookIndex), currentDist)); } // Calculate the smallest average distance double smallestAverageDist = DBL_MAX; int closestLabel = -1; double curDist = 0; for (int curLabel = 0; curLabel < mCenters.rows; ++curLabel) // For each curLabel { if (distances.count(curLabel) == 0) // If this histogram has none of this label continue; // Don't bother calculating it double totalDist = 0; std::pair<std::multimap<int, double>::const_iterator, std::multimap<int, double>::const_iterator> itRange = distances.equal_range(curLabel); for (std::multimap<int, double>::const_iterator it = itRange.first; it != itRange.second; ++it) { totalDist += it->second; } curDist = totalDist/distances.count(curLabel); if (curDist < smallestAverageDist) { smallestAverageDist = curDist; closestLabel = curLabel; } } label = closestLabel; dist = smallestAverageDist; }
//________________________________________________________ void GFOverlay::Overlay(const TObjArray &dirs, const TObjArray &legends) { // 'directories' must contain TDirectory and inheriting, being parallel with legends, // method is called recursively TDirectory *dir1 = 0; for (Int_t iDir = 0; !dir1 && iDir < dirs.GetEntriesFast(); ++iDir) { dir1 = static_cast<TDirectory*>(dirs[iDir]); } if (!dir1) return; const Int_t currentLayer = fLayer; fLayer += (fSummaries ? 2 : 1); std::vector<TH1*> meanHists, rmsHists; // Now loop on keys of first directory (i.e. first file). If not deselected, foresee hists // for plotting and directories for recursion. Other objects are ignored. UInt_t counter = 0; TIter nextKey(dir1->GetListOfKeys()); // // while(TKey* key = static_cast <TKey*> (nextKey())) { // // OK, make CINT happy, i.e. make .L GFOverlay.C work without extending '+': TKey* key = NULL; while ((key = static_cast <TKey*> (nextKey()))) { // If key's name is deselected for both cases (hist and dir), avoid reading object: if (!fHistNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fHistNames) && !fDirNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fDirNames )) { continue; // type (dir/hist) independent skip: not actively selected! } if (this->KeyContainsListMember(key->GetName(), fSkipHistNames) && this->KeyContainsListMember(key->GetName(), fSkipDirNames)) { continue; // type (dir/hist) independent skip: actively deselected! } // Now read object (only of first directory/file!) to be able to check type specific // skipping (hist or dir): TObject *obj = key->ReadObj(); if (!obj) continue; // What ? How that? if (obj->InheritsFrom(TH1::Class())) { if (!fHistNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fHistNames)) { continue; } if (this->KeyContainsListMember(key->GetName(), fSkipHistNames)) continue; } else if (obj->InheritsFrom(TDirectory::Class())) { if (!fDirNames.IsEmpty() && !this->KeyContainsListMember(key->GetName(), fDirNames)) { continue; } if (this->KeyContainsListMember(key->GetName(), fSkipDirNames)) continue; } // Now key survived! First treat for hist case: TObjArray hists(this->GetTypeWithNameFromDirs(TH1::Class(), key->GetName(), dirs)); if (this->AddHistsAt(hists, legends, currentLayer, counter) > 0) { if (fSummaries) { this->CreateFillMeanRms(hists, currentLayer, dir1->GetName(), meanHists, rmsHists); } ++counter; } // Now treat directory case: TObjArray subDirs(this->GetTypeWithNameFromDirs(TDirectory::Class(), key->GetName(), dirs)); if (subDirs.GetEntries()) { // NOT GetEntriesFast()! ::Info("GFOverlay::Overlay", "Key '%s' is directory to do recursion.", key->GetName()); this->Overlay(subDirs, legends); } } // end of loop on keys // If mean/rms hists created, add them to manager: for (unsigned int iMean = 0; iMean < meanHists.size(); ++iMean) { fHistMan->AddHistSame(meanHists[iMean], currentLayer + 1, 0, legends[iMean]->GetName()); fHistMan->AddHistSame(rmsHists[iMean], currentLayer + 1, 1, legends[iMean]->GetName()); } }