Program Listing for File makecontourflowmatches.cxx¶
↰ Return to documentation for file (larflow/FlowContourMatch/makecontourflowmatches.cxx
)
#include "makecontourflowmatches.h"
#include "larcv/core/Base/larcv_logger.h"
#include "larcv/core/ROOTUtil/ROOTUtils.h"
#include "TGraph.h"
#include "TH2D.h"
#include "TBox.h"
#include "opencv2/imgproc.hpp"
namespace larflow {
void createMatchData( const ublarcvapp::ContourClusterAlgo& contour_data,
const larcv::Image2D& src_adc_full,
const larcv::Image2D& tar_adc_full,
const larcv::Image2D& flow_img_crop,
const larcv::Image2D& src_adc_crop,
const larcv::Image2D& tar_adc_crop,
ContourFlowMatchDict_t& matchdict,
const float threshold,
const float max_dist_to_target_contour,
const larcv::msg::Level_t verbosity,
const bool visualize )
{
larcv::logger log("createMatchData");
log.set(verbosity);
int src_planeid = src_adc_crop.meta().plane();
int tar_planeid = tar_adc_crop.meta().plane();
// if ( log.debug() )
// log.send(larcv::msg::kDEBUG,__FUNCTION__,__LINE__)
// << " source plane=" << src_planeid << " "
// << " target plane=" << tar_planeid
// << std::endl;
const larcv::ImageMeta& srcfullmeta = src_adc_full.meta();
const larcv::ImageMeta& tarfullmeta = tar_adc_full.meta();
const larcv::ImageMeta& srcmeta = src_adc_crop.meta();
const larcv::ImageMeta& tarmeta = tar_adc_crop.meta();
// allocate arrays for image pixel to contour index lookup
if ( !matchdict.index_map_initialized ) {
matchdict.src_ctr_index_map.resize( src_adc_full.meta().rows()*src_adc_full.meta().cols(), -1 );
matchdict.tar_ctr_index_map.resize( tar_adc_full.meta().rows()*tar_adc_full.meta().cols(), -1 );
matchdict.index_map_initialized = true;
}
if ( !matchdict.src_ctr_pixel_v_initialized )
matchdict.src_ctr_pixel_v.resize( contour_data.m_plane_atomics_v.at(src_planeid).size() );
// if we visualize, we fill points here
std::vector<float> vis_row[2];
std::vector<float> vis_col[3];
int nsrcpix_in_ctr = 0; // number of source image pixels inside a contour
int ntarpix_in_ctr = 0; // number of target image pixels inside a contour
int nflow_into_ctr = 0; // number of pixels that flow into a contour. unlikely zero, so here for a check
for ( int r=0; r<(int)srcmeta.rows(); r++) {
// for each row, we find the available contours on the images.
// saves us search each time
std::set< int > tar_ctr_ids; // (crop) index of target contours in this row
std::vector<int> src_cols_in_ctr; // columns on the source (crop) image that have ctrs
std::map<int,int> src_cols2ctrid; // map from (crop) src col to src ctr
//src_cols_in_ctr.reserve(20);
// std::cout << "------------------------------------------" << std::endl;
// std::cout << "Find row=" << r << " contours" << std::endl;
// Find contours on source image in this row
// std::cout << "source: ";
for ( int c=0; c<(int)srcmeta.cols(); c++) {
if ( src_adc_crop.pixel(r,c)<threshold )
continue;
float full_row = srcfullmeta.row( srcmeta.pos_y(r) );
float full_col = srcfullmeta.col( srcmeta.pos_x(c) );
cv::Point pt( full_col, full_row ); // point in the full image
// search the contours
bool found_contour = false;
float closestdist = -20000;
for ( size_t ictr=0; ictr<contour_data.m_plane_atomics_v[src_planeid].size(); ictr++ ) {
auto const& ctr = contour_data.m_plane_atomics_v[src_planeid][ictr];
auto const& ctrmeta = contour_data.m_plane_atomicmeta_v[src_planeid][ictr];
// bbox check
if ( pt.x < ctrmeta.getMinX() || pt.x > ctrmeta.getMaxX() ) continue;
if ( pt.y < ctrmeta.getMinY() || pt.y > ctrmeta.getMaxY() ) continue;
double result = cv::pointPolygonTest( ctr, pt, true );
if ( closestdist < result )
closestdist = result;
if ( result>-1 ) {
src_cols_in_ctr.push_back( c );
src_cols2ctrid[c] = ictr;
//std::cout << " source pix (" << r << "," << c << ") "
// << "found in ctr=" << ictr << ". nelems=" << src_cols_in_ctr.size() << std::endl;
// store in lookup map for crop
int pixindex = full_row*srcfullmeta.cols() + full_col;
matchdict.src_ctr_pixel_v.at( ictr ).push_back( pixindex );
matchdict.src_ctr_index_map[ pixindex ] = ictr;
nsrcpix_in_ctr++;
found_contour = true;
if ( visualize ) {
// source points with charge
vis_row[0].push_back( srcmeta.pos_y(r) );
vis_col[0].push_back( full_col );
}
break;
}
}//end of contour loop
if ( !found_contour && log.debug() ) {
log.send( larcv::msg::kDEBUG,__FUNCTION__,__LINE__ ) << "did not find source contour for point (col,row)=(" << pt.x << "," << pt.y << ")! "
<< " closest dist=" << closestdist << std::endl;
}
}//end of cropped column loop
//std::cout << std::endl;
// Find Contours on the target image in this row
//std::cout << "target: ";
for ( int c=0; c<(int)tarmeta.cols(); c++) {
if ( tar_adc_crop.pixel(r,c)<threshold )
continue;
float full_row = tarfullmeta.row( tarmeta.pos_y(r) );
float full_col = tarfullmeta.col( tarmeta.pos_x(c) );
cv::Point pt( full_col, full_row );
// search the contours
float closest_dist = -1000000;
bool found_contour = false;
for ( size_t ictr=0; ictr<contour_data.m_plane_atomics_v[tar_planeid].size(); ictr++ ) {
auto const& ctr = contour_data.m_plane_atomics_v[tar_planeid][ictr];
auto const& ctrmeta = contour_data.m_plane_atomicmeta_v[tar_planeid][ictr];
// bbox check
if ( pt.x < ctrmeta.getMinX() || pt.x > ctrmeta.getMaxX() ) continue;
if ( pt.y < ctrmeta.getMinY() || pt.y > ctrmeta.getMaxY() ) continue;
double result = cv::pointPolygonTest( ctr, pt, true );
if ( result > closest_dist )
closest_dist = result;
if ( result>=-1 ) {
tar_ctr_ids.insert( ictr );
matchdict.tar_ctr_index_map[ full_row*tarfullmeta.cols() + full_col ] = ictr;
ntarpix_in_ctr++;
found_contour = true;
break;
}
}//end of target contour loop
if ( !found_contour && log.debug() ) {
log.send( larcv::msg::kDEBUG,__FUNCTION__,__LINE__ )
<< "did not find target contour for point (col,row)=(" << pt.x << "," << pt.y << ")! "
<< " localpix=(" << c << "," << r << ") "
<< " closest dist=" << closest_dist << std::endl;
}
}//end of target col loop
//std::cout << std::endl;
// Nothing in this row, move on to the next row
if ( src_cols_in_ctr.size()==0 || tar_ctr_ids.size()==0 ) {
// if ( log.debug() )
// log.send(larcv::msg::kDEBUG,__FUNCTION__,__LINE__)
// << "nothing to match. "
// << " srcwires=" << src_cols_in_ctr.size()
// << " tarwires=" << tar_ctr_ids.size()
// << std::endl;
continue;
}
else if ( src_cols_in_ctr.size()>0 && tar_ctr_ids.size()>0 ) {
// if ( log.debug() )
// log.send(larcv::msg::kDEBUG,__FUNCTION__,__LINE__)
// << " srcwires=" << src_cols_in_ctr.size()
// << " tarwires=" << tar_ctr_ids.size()
// << std::endl;
}
// now loop over source columns in contours and make matches to target contours
for ( auto const& source_crop_col : src_cols_in_ctr ) {
float flow = flow_img_crop.pixel(r,source_crop_col);
int target_crop_col = source_crop_col+flow;
//std::cout << " source-crop-col flow (" << r << "," << source_crop_col << ") flow=" << flow << " target-crop-col=" << target_crop_col << std::endl;
if ( target_crop_col>= tarmeta.cols() )
continue; // flow out of bounds
if ( target_crop_col<0 )
continue; // flow out of bounds
float tar_row_full = tarfullmeta.row( tarmeta.pos_y(r) );
float tar_col_full = tarfullmeta.col( tarmeta.pos_x(target_crop_col) );
cv::Point tar_pt( tar_col_full, tar_row_full );
// retrieve the contour we're in
int src_ctr_id = src_cols2ctrid[source_crop_col];
// loop through the target contours, find the contour closest to the flowed-to target wire
int closest_contour_idx = -1;
float closest_dist = -50;
for ( auto const& ctrid : tar_ctr_ids ) {
// have to move point back to full image coordinates
float dist = cv::pointPolygonTest( contour_data.m_plane_atomics_v[tar_planeid][ctrid], tar_pt, true );
// if dist is negatice, its outside the contour
// if dist is positive, its inside the contour
if ( dist>=0 ) {
// inside, no need to search further
closest_contour_idx = ctrid;
closest_dist = 0.;
nflow_into_ctr++;
break;
}
else if ( dist>-1*max_dist_to_target_contour ) {
// enforce a max distance to a contour
if ( closest_contour_idx<0 || closest_dist < dist ) {
closest_contour_idx = ctrid;
closest_dist = dist;
}
}
}//end of contour loop
// if no contour found, move on
//std::cout << "source -> tar contour index=" << closest_contour_idx << ". closest dist=" << closest_dist << std::endl;
if ( closest_contour_idx<0 ) {
continue;
}
if ( visualize ) {
vis_row[1].push_back( tarmeta.pos_y(r) );
vis_col[1].push_back( tar_col_full );
}
// else we store/append a src-tar contour match for this source pixel
// store the match data
// --------------------
// create a pair key
SrcTarPair_t idpair = { src_ctr_id, closest_contour_idx };
// check if we have one for this pair already
auto it_indexmap = matchdict.find( idpair );
if ( it_indexmap==matchdict.end() ) {
// if the map doesn't have the pair we're looking for, we create the data
ContourFlowMatch_t x( src_ctr_id, closest_contour_idx);
matchdict.insert( std::pair<SrcTarPair_t,ContourFlowMatch_t>(idpair,x) );
it_indexmap = matchdict.find(idpair);
}
// store the specific pixel flow information
float src_full_wire = srcmeta.pos_x(source_crop_col);
float tar_full_wire = tarmeta.pos_x(target_crop_col);
float in_contour_wire = tar_full_wire;
if ( closest_dist<0 ) {
// if we missed a contour, we find the offset that moves us into it
const ublarcvapp::Contour_t& tar_ctr = contour_data.m_plane_atomics_v[tar_planeid][closest_contour_idx];
bool shift_pos = false;
float shifted_pos = 0;
for (int ioffset=-1; ioffset<=1; ioffset+=2) {
float tar_col_full_shifted = tar_full_wire + float(ioffset)*fabs(closest_dist);
float testdist = cv::pointPolygonTest( tar_ctr, cv::Point( tar_col_full_shifted, tar_row_full ), true );
if ( testdist>=0 || (testdist>-max_dist_to_target_contour && fabs(testdist)<fabs(closest_dist)) ) {
shifted_pos = tar_col_full_shifted;
//std::cout << "shifted position better: dist=" << closest_dist << " to " << testdist << std::endl;
closest_dist = testdist;
shift_pos = true;
}
}
// replace, as we did better
if ( shift_pos )
in_contour_wire = shifted_pos;
}
if ( visualize )
vis_col[2].push_back( in_contour_wire );
ContourFlowMatch_t::FlowPixel_t flowpix;
flowpix.src_wire = src_full_wire;
flowpix.tar_wire = in_contour_wire;
flowpix.tar_orig = tar_full_wire;
flowpix.row = tar_row_full;
flowpix.tick = tarfullmeta.pos_y( tar_row_full );
flowpix.pred_miss = std::fabs(closest_dist);
flowpix.dist2cropcenter = std::fabs(source_crop_col - (float)srcmeta.cols()/2);
int srcindex = (int)flowpix.row * srcfullmeta.cols() + (int)flowpix.src_wire;
std::vector<ContourFlowMatch_t::FlowPixel_t>& flowpix_v = it_indexmap->second.getFlowPixelList( srcindex );
flowpix_v.emplace_back( std::move(flowpix) );
// debug
if ( log.debug() )
log.send( larcv::msg::kDEBUG,__FUNCTION__,__LINE__)
<< "creating a src-tar datapoint: "
<< "[src=" << src_full_wire << " -> "
<< "tar(orig)=" << tar_full_wire << " tar(shift)=" << in_contour_wire << "] "
<< "dist2ctr=" << closest_dist << "(orig) "
<< std::endl;
}//end of loop over source cols
}//end of loop over rows
if ( log.info() )
log.send( larcv::msg::kINFO,__FUNCTION__,__LINE__ )
<< "Number of pixels inside crop that flowed into a contour: "
<< nflow_into_ctr
<< std::endl;
if ( visualize ) {
// we plot all three planes.
log.send( larcv::msg::kDEBUG,__FUNCTION__,__LINE__ )
<< "number of src pts, " << vis_row[0].size() << ", "
<< " tar pts, " << vis_row[1].size() << "."
<< std::endl;
log.send( larcv::msg::kDEBUG,__FUNCTION__,__LINE__ )
<< "source meta: " << src_adc_crop.meta().dump()
<< std::endl;
log.send( larcv::msg::kDEBUG,__FUNCTION__,__LINE__ )
<< "target meta: " << tar_adc_crop.meta().dump()
<< std::endl;
TCanvas c("cflow","FlowContourMatch",1400,600);
c.Divide(2,1);
TH2D hadc_source = larcv::rootutils::as_th2d( src_adc_full, "hadc_source" );
TH2D hadc_target = larcv::rootutils::as_th2d( tar_adc_full, "hadc_target" );
TGraph gsrcpts( vis_row[0].size(), vis_col[0].data(), vis_row[0].data() );
TGraph gtarpts( vis_row[1].size(), vis_col[1].data(), vis_row[1].data() );
TGraph gtarcontourpts( vis_col[2].size(), vis_col[2].data(), vis_row[1].data() );
TBox src_box( src_adc_crop.meta().min_x(), src_adc_crop.meta().min_y(),
src_adc_crop.meta().max_x(), src_adc_crop.meta().max_y() );
TBox tar_box( tar_adc_crop.meta().min_x(), tar_adc_crop.meta().min_y(),
tar_adc_crop.meta().max_x(), tar_adc_crop.meta().max_y() );
src_box.SetLineColor(kRed);
src_box.SetLineWidth(2);
src_box.SetFillStyle(0);
tar_box.SetLineColor(kRed);
tar_box.SetLineWidth(2);
tar_box.SetFillStyle(0);
c.Draw();
gsrcpts.SetMarkerStyle(24);
gtarpts.SetMarkerStyle(24);
gtarcontourpts.SetLineColor(kRed);
gtarcontourpts.SetMarkerColor(kRed);
gtarcontourpts.SetMarkerStyle(24);
c.cd(1);
hadc_source.Draw("colz");
gsrcpts.Draw("p");
src_box.Draw("same");
c.cd(2);
hadc_target.Draw("colz");
gtarpts.Draw("psame");
gtarcontourpts.Draw("psame");
tar_box.Draw("same");
c.Update();
TCanvas ccheck("cropcheck","Crop Check",1400,600);
ccheck.Divide(3,1);
ccheck.Draw();
ccheck.cd(1);
TH2D hsrc_crop = larcv::rootutils::as_th2d( src_adc_crop, "hsrc_crop" );
hsrc_crop.Draw("colz");
ccheck.cd(2);
TH2D htar_crop = larcv::rootutils::as_th2d( tar_adc_crop, "htar_crop" );
htar_crop.Draw("colz");
ccheck.cd(3);
TH2D hflow_crop = larcv::rootutils::as_th2d( flow_img_crop, "hflow_crop" );
//hflow_crop.GetZaxis()->SetRangeUser(-832,832);
hflow_crop.Draw("colz");
ccheck.Update();
char cname[100];
sprintf( cname, "flowcheck_src%d_to_tar%d_%d_%d.png",
(int)src_adc_crop.meta().plane(),(int)tar_adc_crop.meta().plane(),
(int)src_adc_crop.meta().min_x(),(int)src_adc_crop.meta().min_y() );
c.SaveAs(cname);
//std::cout << "[enter] to continue." << std::endl;
//std::cin.get();
}
}
}