Program Listing for File DBScanLArMatchHits.cxx¶
↰ Return to documentation for file (larflow/Reco/DBScanLArMatchHits.cxx
)
#include "DBScanLArMatchHits.h"
#include "cluster_functions.h"
#include "nlohmann/json.hpp"
#include "ublarcvapp/ContourTools/ContourClusterAlgo.h"
#include "ublarcvapp/dbscan/DBScan.h"
#include "larcv/core/DataFormat/EventImage2D.h"
#include "DataFormat/larflow3dhit.h"
#include "DataFormat/larflowcluster.h"
#include "TRandom3.h"
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <ctime>
namespace larflow {
namespace reco {
void DBScanLArMatchHits::process( larcv::IOManager& iolcv, larlite::storage_manager& ioll ) {
larlite::event_larflow3dhit* ev_lfhits
= (larlite::event_larflow3dhit*)ioll.get_data( larlite::data::kLArFlow3DHit, _input_larflowhit_tree_name );
// cluster track hits
std::vector<int> used_hits_v;
std::vector<cluster_t> cluster_v;
makeCluster( *ev_lfhits, cluster_v, used_hits_v );
// form clusters of larflow hits for saving
larlite::event_larflowcluster* evout_lfcluster
= (larlite::event_larflowcluster*)ioll.get_data( larlite::data::kLArFlowCluster, _out_cluster_tree_name );
larlite::event_pcaxis* evout_pcaxis
= (larlite::event_pcaxis*) ioll.get_data( larlite::data::kPCAxis, _out_cluster_tree_name );
int cidx = 0;
for ( auto& c : cluster_v ) {
// cluster of hits
larlite::larflowcluster lfcluster = makeLArFlowCluster( c, *ev_lfhits );
evout_lfcluster->emplace_back( std::move(lfcluster) );
// pca-axis
larlite::pcaxis llpca = cluster_make_pcaxis( c, cidx );
evout_pcaxis->push_back( llpca );
cidx++;
}
// make noise cluster
larlite::event_larflowcluster* evout_noise_lfcluster
= (larlite::event_larflowcluster*)ioll.get_data( larlite::data::kLArFlowCluster, _out_cluster_tree_name+"noise" );
larlite::larflowcluster lfnoise;
cluster_t noise_cluster;
for ( size_t i=0; i<ev_lfhits->size(); i++ ) {
auto& hit = (*ev_lfhits)[i];
if ( used_hits_v[i]==0 ) {
std::vector<float> pt = { hit[0], hit[1], hit[2] };
std::vector<int> coord_v = { hit.targetwire[0], hit.targetwire[1], hit.targetwire[2], hit.tick };
noise_cluster.points_v.push_back( pt );
noise_cluster.imgcoord_v.push_back( coord_v );
noise_cluster.hitidx_v.push_back( i );
lfnoise.push_back( hit );
}
}
cluster_pca( noise_cluster );
larlite::pcaxis noise_pca = cluster_make_pcaxis( noise_cluster );
evout_noise_lfcluster->push_back( lfnoise );
}
larlite::larflowcluster DBScanLArMatchHits::makeLArFlowCluster( cluster_t& cluster,
const std::vector<larlite::larflow3dhit>& source_lfhit_v ) {
larlite::larflowcluster lfcluster;
lfcluster.reserve( cluster.points_v.size() );
for ( size_t ii=0; ii<cluster.ordered_idx_v.size(); ii++ ) {
int ihit = cluster.ordered_idx_v[ii];
larlite::larflow3dhit lfhit;
lfhit.resize(3,0); // (x,y,z,pixU,pixV,pixY,matchprob)
// transfer 3D points
for (int i=0; i<3; i++) lfhit[i] = cluster.points_v[ihit][i];
// transfer image coordates
lfhit.srcwire = cluster.imgcoord_v[ihit][2];
lfhit.targetwire.resize(3,0);
lfhit.targetwire[0] = cluster.imgcoord_v[ihit][0];
lfhit.targetwire[1] = cluster.imgcoord_v[ihit][1];
lfhit.targetwire[2] = cluster.imgcoord_v[ihit][2];
lfhit.tick = cluster.imgcoord_v[ihit][3];
lfcluster.emplace_back( std::move(lfhit) );
}//end of hit loop
return lfcluster;
}
cluster_t DBScanLArMatchHits::absorb_nearby_hits( const cluster_t& cluster,
const std::vector<larlite::larflow3dhit>& hit_v,
std::vector<int>& used_hits_v,
float max_dist2line ) {
cluster_t newcluster;
int nused = 0;
for ( size_t ihit=0; ihit<hit_v.size(); ihit++ ) {
auto const& hit = hit_v[ihit];
if ( used_hits_v[ ihit ]==1 ) continue;
// apply quick bounding box test
if ( hit[0] < cluster.bbox_v[0][0] || hit[0]>cluster.bbox_v[0][1]
|| hit[1] < cluster.bbox_v[1][0] || hit[1]>cluster.bbox_v[1][1]
|| hit[2] < cluster.bbox_v[2][0] || hit[2]>cluster.bbox_v[2][1] ) {
continue;
}
// else calculate distance from pca-line
float dist2line = cluster_dist_from_pcaline( cluster, hit );
if ( dist2line < max_dist2line ) {
std::vector<float> pt = { hit[0], hit[1], hit[2] };
std::vector<int> coord_v = { hit.targetwire[0], hit.targetwire[1], hit.targetwire[2], hit.tick };
newcluster.points_v.push_back( pt );
newcluster.imgcoord_v.push_back( coord_v );
newcluster.hitidx_v.push_back( ihit );
used_hits_v[ihit] = 1;
nused++;
}
}
if (nused>=10 ) {
LARCV_DEBUG() << "[absorb_nearby_hits] cluster absorbed " << nused << " hits" << std::endl;
cluster_pca( newcluster );
}
else {
// throw them back
LARCV_DEBUG() << "[absorb_nearby_hits] cluster hits " << nused << " below threshold" << std::endl;
for ( auto& idx : newcluster.hitidx_v )
used_hits_v[idx] = 0;
newcluster.points_v.clear();
newcluster.imgcoord_v.clear();
newcluster.hitidx_v.clear();
}
return newcluster;
}
void DBScanLArMatchHits::makeCluster( const std::vector<larlite::larflow3dhit>& inputhits,
std::vector<cluster_t>& output_cluster_v,
std::vector<int>& used_hits_v ) {
const int max_pts_to_cluster = 30000;
TRandom3 rand(12345);
used_hits_v.resize( inputhits.size(), 0 );
output_cluster_v.clear();
// count points remaining
int total_pts_remaining = 0;
// on first pass, all points remain
total_pts_remaining = (int)inputhits.size();
// downsample points, if needed
std::vector<larlite::larflow3dhit> downsample_hit_v;
downsample_hit_v.reserve( max_pts_to_cluster );
float downsample_fraction = (float)max_pts_to_cluster/(float)total_pts_remaining;
if ( total_pts_remaining>max_pts_to_cluster ) {
for ( size_t ihit=0; ihit<inputhits.size(); ihit++ ) {
if ( used_hits_v[ihit]==0 ) {
if ( rand.Uniform()<downsample_fraction ) {
downsample_hit_v.push_back( inputhits[ihit] );
}
}
}
}
else {
for ( size_t ihit=0; ihit<inputhits.size(); ihit++ ) {
if ( used_hits_v[ihit]==0 ) {
downsample_hit_v.push_back( inputhits[ihit] );
}
}
}
LARCV_INFO() << inputhits.size() << " hits downsampled to " << downsample_hit_v.size() << std::endl;
// cluster these hits
std::vector<larflow::reco::cluster_t> cluster_pass_v;
larflow::reco::cluster_sdbscan_larflow3dhits( downsample_hit_v, cluster_pass_v, _maxdist, _minsize, _maxkd ); // external implementation, seems best
larflow::reco::cluster_runpca( cluster_pass_v );
// we then absorb the hits around these clusters
for ( auto const& ds_cluster : cluster_pass_v ) {
cluster_t dense_cluster = absorb_nearby_hits( ds_cluster,
inputhits,
used_hits_v,
10.0 );
if ( dense_cluster.points_v.size()>0 )
output_cluster_v.emplace_back( std::move(dense_cluster) );
}
int nused_tot = 0;
for ( auto& used : used_hits_v ) {
nused_tot += used;
}
LARCV_NORMAL() << "Made " << output_cluster_v.size() << " clusters; "
<< nused_tot << " of " << used_hits_v.size() << " hits used"
<< std::endl;
}
}
}