CVNImageUtils.cxx
Go to the documentation of this file.
1 #include <vector>
2 #include <iostream>
3 
5 
7  // Set a default image size
8  SetImageSize(500,500,3);
9  SetPixelMapSize(2880,500);
10  // Defualt is to reverse the y view
11  fViewReverse = {false,true,false};
12 
13  fUseLogScale = false;
15 }
16 
17 cvn::CVNImageUtils::CVNImageUtils(unsigned int nWires, unsigned int nTDCs, unsigned int nViews){
18  SetImageSize(nWires,nTDCs,nViews);
19  SetPixelMapSize(2880,500);
20  fUseLogScale = false;
21 }
22 
24 
25 }
26 
29 }
30 
33 }
34 
35 unsigned char cvn::CVNImageUtils::ConvertChargeToChar(float charge){
36 
37  float peCorrChunk;
38  float truncateCorr;
39  float centreScale = 0.7;
40  if(fUseLogScale){
41  float scaleFrac=(log(charge)/log(1000));
42  truncateCorr= ceil(centreScale*scaleFrac*255.0);
43  }
44  else{
45  peCorrChunk = (1000.) / 255.0;
46  truncateCorr = ceil((charge)/(peCorrChunk));
47  }
48  if (truncateCorr > 255) return (unsigned char)255;
49  else return (unsigned char)truncateCorr;
50 
51 }
52 
53 void cvn::CVNImageUtils::SetImageSize(unsigned int nWires, unsigned int nTDCs, unsigned int nViews){
54  fNWires = nWires;
55  fNTDCs = nTDCs;
56  fNViews = nViews;
57 }
58 
59 void cvn::CVNImageUtils::SetViewReversal(bool reverseX, bool reverseY, bool reverseZ){
60  fViewReverse = {reverseX,reverseY,reverseZ};
61 }
62 
63 void cvn::CVNImageUtils::SetViewReversal(std::vector<bool> reverseViews){
64  if(reverseViews.size() != 3){
65  std::cout << "Expected three views for view reversals... using defaults." << std::endl;
66  }
67  else{
68  SetViewReversal(reverseViews[0],reverseViews[1],reverseViews[2]);
69  }
70  return;
71 }
72 
74  fUseLogScale = setLog;
75 }
76 
77 void cvn::CVNImageUtils::SetPixelMapSize(unsigned int nWires, unsigned int nTDCs){
78  fPixelMapWires = nWires;
79  fPixelMapTDCs = nTDCs;
80 }
81 
82 void cvn::CVNImageUtils::ConvertPixelMapToPixelArray(const PixelMap &pm, std::vector<unsigned char> &pix){
83 
85 
86  // Strip out the charge vectors and use these
87  std::vector<float> v0pe = pm.fPEX;
88  std::vector<float> v1pe = pm.fPEY;
89  std::vector<float> v2pe = pm.fPEZ;
90 
91  ConvertChargeVectorsToPixelArray(v0pe,v1pe,v2pe,pix);
92 
93 }
94 
95 
96 void cvn::CVNImageUtils::ConvertChargeVectorsToPixelArray(std::vector<float> &v0pe, std::vector<float> &v1pe,
97  std::vector<float> &v2pe, std::vector<unsigned char> &pix){
98 
99  // Get the vectors
100  cvn::ViewVector view0;
101  cvn::ViewVector view1;
102  cvn::ViewVector view2;
103  ConvertChargeVectorsToViewVectors(v0pe, v1pe, v2pe, view0, view1, view2);
104 
105  // Actually write the values to the pixel array
106  for (unsigned int view = 0; view < fNViews; ++view){
107  for (unsigned int wire = 0; wire < fNWires; ++wire){
108  for (unsigned int time = 0; time < fNTDCs; ++time){
109 
110  unsigned char val = 0;
111  // Get the index for the pixel map
112  if(view == 0 ){ val = view0[wire][time]; }
113  if(view == 1 ){ val = view1[wire][time]; }
114  if(view == 2 ){ val = view2[wire][time]; }
115 
116  // Get the index for the final image
117  unsigned int i = time + fNTDCs * (wire + fNWires * view);
118  pix[i] = val;
119 
120  }
121  }
122  }
123 
124  return;
125 
126 }
127 
129 
131 
132  // Strip out the charge vectors and use these
133  std::vector<float> v0pe = pm.fPEX;
134  std::vector<float> v1pe = pm.fPEY;
135  std::vector<float> v2pe = pm.fPEZ;
136 
137  ConvertChargeVectorsToImageVector(v0pe, v1pe, v2pe, imageVec);
138 }
139 
141 
143 
144  // Strip out the charge vectors and use these
145  std::vector<float> v0pe = pm.fPEX;
146  std::vector<float> v1pe = pm.fPEY;
147  std::vector<float> v2pe = pm.fPEZ;
148 
149  ConvertChargeVectorsToImageVectorF(v0pe, v1pe, v2pe, imageVec);
150 }
151 
152 void cvn::CVNImageUtils::ConvertChargeVectorsToImageVector(std::vector<float> &v0pe, std::vector<float> &v1pe,
153  std::vector<float> &v2pe, cvn::ImageVector &imageVec){
154 
155  cvn::ViewVector view0;
156  cvn::ViewVector view1;
157  cvn::ViewVector view2;
158 
159  ConvertChargeVectorsToViewVectors(v0pe, v1pe, v2pe, view0, view1, view2);
160 
161  cvn::ImageVector newImage = BuildImageVector(view0,view1,view2);
162 
163  imageVec = newImage;
164 }
165 
166 void cvn::CVNImageUtils::ConvertChargeVectorsToImageVectorF(std::vector<float> &v0pe, std::vector<float> &v1pe,
167  std::vector<float> &v2pe, cvn::ImageVectorF &imageVec){
168 
169  cvn::ViewVector view0;
170  cvn::ViewVector view1;
171  cvn::ViewVector view2;
172 
173  ConvertChargeVectorsToViewVectors(v0pe, v1pe, v2pe, view0, view1, view2);
174 
175  // Convert the ViewVector to ViewVectorF
176  cvn::ViewVectorF floatView0 = ConvertViewVecToViewVecF(view0);
177  cvn::ViewVectorF floatView1 = ConvertViewVecToViewVecF(view1);
178  cvn::ViewVectorF floatView2 = ConvertViewVecToViewVecF(view2);
179 
180  cvn::ImageVectorF newImage = BuildImageVectorF(floatView0,floatView1,floatView2);
181 
182  imageVec = newImage;
183 }
184 
185 
186 void cvn::CVNImageUtils::ConvertChargeVectorsToViewVectors(std::vector<float> &v0pe, std::vector<float> &v1pe, std::vector<float> &v2pe,
187  cvn::ViewVector& view0, cvn::ViewVector& view1, cvn::ViewVector& view2){
188 
189  // Reverse requested views
190  if(fViewReverse[0]) ReverseView(v0pe);
191  if(fViewReverse[1]) ReverseView(v1pe);
192  if(fViewReverse[2]) ReverseView(v2pe);
193 
194  // Get the integrated charge for each wire
195  std::vector< std::vector<float> > wireCharges;
196  for (unsigned int view = 0; view < fNViews; ++view){
197 
198  std::vector<float> tempChargeVec;
199  for (unsigned int wire = 0; wire < fPixelMapWires; ++wire){
200 
201  float totCharge = 0;
202  for (unsigned int time = 0; time < fPixelMapTDCs; ++time){
203  float val = 0.;
204  unsigned int element = time + fPixelMapTDCs * wire;
205  if(view == 0 ){ val = v0pe[element]; }
206  if(view == 1 ){ val = v1pe[element]; }
207  if(view == 2 ){ val = v2pe[element]; }
208  totCharge += val;
209  }
210  tempChargeVec.push_back(totCharge);
211  }
212  wireCharges.push_back(tempChargeVec);
213  }
214 
215  // Get the integrated charge for each tdc
216  std::vector< std::vector<float> > tdcCharges;
217  for (unsigned int view = 0; view < fNViews; ++view){
218 
219  std::vector<float> tempChargeVec;
220  for (unsigned int time = 0; time < fPixelMapTDCs; ++time){
221 
222 
223  float totCharge = 0;
224  for (unsigned int wire = 0; wire < fPixelMapWires; ++wire){
225 
226  float val = 0.;
227  unsigned int element = time + fPixelMapTDCs * wire;
228  if(view == 0 ){ val = v0pe[element]; }
229  if(view == 1 ){ val = v1pe[element]; }
230  if(view == 2 ){ val = v2pe[element]; }
231  totCharge += val;
232  }
233  tempChargeVec.push_back(totCharge);
234  }
235  tdcCharges.push_back(tempChargeVec);
236  }
237 
238  // The output image consists of a rectangular region of the pixel map
239  // We want to find the start and end wires for each view
240  std::vector<unsigned int> imageStartWire(3,0);
241  std::vector<unsigned int> imageEndWire(3,0);
242  // And the same for TDCs
243  std::vector<unsigned int> imageStartTDC(3,0);
244  std::vector<unsigned int> imageEndTDC(3,0);
245 
247  // Do a rough vertex-based selection of the region for each view
248  for(unsigned int view = 0; view < wireCharges.size(); ++view){
249  GetMinMaxWires(wireCharges[view],imageStartWire[view],imageEndWire[view]);
250  GetMinMaxTDCs(tdcCharges[view],imageStartTDC[view],imageEndTDC[view]);
251 
252 // std::cout << " Wires: " << imageStartWire[view] << ", " << imageEndWire[view] << " :: TDCs: "
253 // << imageStartTDC[view] << ", " << imageEndTDC[view] << std::endl;
254  }
255  }
256  else{
257  // Just use the number of wires and TDCs as the maximum values if we want to
258  // use a fixed range of wires and TDC for protoDUNE's APA 3
259  for(unsigned int i = 0; i < imageStartWire.size(); ++i){
260  imageStartWire[i] = 0;
261  imageEndWire[i] = fNWires;
262  imageStartTDC[i] = 0;
263  imageEndTDC[i] = fNTDCs;
264  }
265  }
266 
267  // Write the values to the three vectors
268  for (unsigned int view = 0; view < fNViews; ++view){
269  cvn::ViewVector viewChargeVec;
270  for (unsigned int wire = imageStartWire[view]; wire <= imageEndWire[view]; ++wire){
271  std::vector<unsigned char> wireTDCVec;
272  for (unsigned int time = imageStartTDC[view]; time <= imageEndTDC[view]; ++time){
273 
274  // Get the index for the pixel map
275  unsigned int element = time + fPixelMapTDCs * wire;
276 
277  // We have to convert to char and then convert back to a float
278  unsigned char val = 0;
279  if(view == 0){ val = ConvertChargeToChar(v0pe[element]); }
280  if(view == 1){ val = ConvertChargeToChar(v1pe[element]); }
281  if(view == 2){ val = ConvertChargeToChar(v2pe[element]); }
282  wireTDCVec.push_back(val);
283  }
284  viewChargeVec.push_back(wireTDCVec);
285  }
286  if(view == 0) view0 = viewChargeVec;
287  if(view == 1) view1 = viewChargeVec;
288  if(view == 2) view2 = viewChargeVec;
289  }
290 
291  return;
292 
293 }
294 
295 void cvn::CVNImageUtils::ConvertPixelArrayToImageVectorF(const std::vector<unsigned char> &pixelArray, cvn::ImageVectorF &imageVec){
296 
297  // The pixel arrays is built with indices i = tdc + nTDCs(wire + nWires*view)
298 
299  cvn::ViewVectorF view0;
300  cvn::ViewVectorF view1;
301  cvn::ViewVectorF view2;
302 
303  for(unsigned int v = 0; v < fNViews; ++v){
304  for(unsigned int w = 0; w < fNWires; ++w){
305  std::vector<float> wireVec;
306  for(unsigned int t = 0; t < fNTDCs; ++t){
307  unsigned int index = t + fNTDCs*(w + fNWires*v);
308  wireVec.push_back(pixelArray[index]);
309  }
310  if(v==0) view0.push_back(wireVec);
311  if(v==1) view1.push_back(wireVec);
312  if(v==2) view2.push_back(wireVec);
313  }
314  }
315 
316  imageVec = BuildImageVectorF(view0,view1,view2);
317 
318 }
319 
320 void cvn::CVNImageUtils::GetMinMaxWires(std::vector<float> &wireCharges, unsigned int &minWire, unsigned int &maxWire){
321 
322  minWire = 0;
323  maxWire = fNWires;
324 
325  for(unsigned int wire = 0; wire < wireCharges.size(); ++wire){
326 
327  // If we have got to fNWires from the end, the start needs to be this wire
328  if(wireCharges.size() - wire == fNWires){
329  break;
330  }
331 
332  // For a given plane, look to see if the next 20 planes are empty. If not, this can be out start plane.
333  int nEmpty = 0;
334  for(unsigned int nextWire = wire + 1; nextWire <= wire + 20; ++nextWire){
335  if(wireCharges[nextWire] == 0.0) ++nEmpty;
336  }
337  if(nEmpty < 5){
338  minWire = wire;
339  maxWire = wire + fNWires - 1;
340  return;
341  }
342  }
343 
344  // If we don't find a region where we have fewer than 5 empty planes then we just want to select the fNWires wires containing
345  // the most charge
346  float maxCharge = 0.;
347  unsigned int firstWire = 0;
348  for(unsigned int wire = 0; wire < wireCharges.size() - fNWires; ++wire){
349  float windowCharge = 0.;
350  for(unsigned int nextwire = wire; nextwire < wire + fNWires; ++nextwire){
351  windowCharge += wireCharges[nextwire];
352  }
353  if(windowCharge > maxCharge){
354  maxCharge = windowCharge;
355  firstWire = wire;
356  }
357  }
358  minWire = firstWire;
359  maxWire = firstWire + fNWires - 1;
360 
361  std::cout << "Used alternate method to get min and max wires due to vertex determination failure: " << minWire << ", " << maxWire << std::endl;
362 
363 }
364 
365 void cvn::CVNImageUtils::GetMinMaxTDCs(std::vector<float> &tdcCharges, unsigned int &minTDC, unsigned int &maxTDC){
366 
367  minTDC = 0;
368  maxTDC = fNTDCs;
369 
370  for(unsigned int tdc = 0; tdc < tdcCharges.size(); ++tdc){
371 
372  // If we have got to fNWires from the end, the start needs to be this wire
373  if(tdcCharges.size() - tdc == fNTDCs){
374  break;
375  }
376 
377  // For a given tdc, look to see if the next 20 tdcs are empty. If not, this can be out start tdc.
378  int nEmpty = 0;
379  for(unsigned int nextTDC = tdc + 1; nextTDC <= tdc + 20; ++nextTDC){
380  if(tdcCharges[nextTDC] == 0.0) ++nEmpty;
381  }
382  if(nEmpty < 5){
383  minTDC = tdc;
384  maxTDC = tdc + fNTDCs - 1;
385  return;
386  }
387  }
388 
389  // If we don't find a region where we have fewer than 5 empty tdcs then we just want to select the fNTDCs tdcs containing
390  // the most charge
391  float maxCharge = 0.;
392  unsigned int firstTDC = 0;
393  for(unsigned int tdc = 0; tdc < tdcCharges.size() - fNTDCs; ++tdc){
394  float windowCharge = 0.;
395  for(unsigned int nexttdc = tdc; nexttdc < tdc + fNTDCs; ++nexttdc){
396  windowCharge += tdcCharges[nexttdc];
397  }
398  if(windowCharge > maxCharge){
399  maxCharge = windowCharge;
400  firstTDC = tdc;
401  }
402  }
403  minTDC = firstTDC;
404  maxTDC = firstTDC + fNTDCs - 1;
405 
406  std::cout << "Used alternate method to get min and max tdcs due to vertex determination failure: " << minTDC << ", " << maxTDC << std::endl;
407 
408 
409 }
410 
411 void cvn::CVNImageUtils::ReverseView(std::vector<float> &peVec){
412 
413  std::vector<float> vecCopy(peVec.size(),0.);
414 
415  for (unsigned int w = 0; w < fPixelMapWires; ++w)
416  {
417  // Get our new plane number
418  unsigned int newPlane = fPixelMapWires - w - 1;
419 
420  for (unsigned int t = 0; t < fPixelMapTDCs; ++t)
421  {
422  float val = peVec[t + fPixelMapTDCs * w];
423  vecCopy[t + fPixelMapTDCs * newPlane] = val;
424  }
425  }
426 
427  // Copy the values back into the original vector
428  for(unsigned int e = 0; e < peVec.size(); ++e){
429  float val = vecCopy[e];
430  peVec[e] = val;
431  }
432 
433 }
434 
436 
437  cvn::ViewVectorF newVec;
438  for(size_t w = 0; w < view.size(); ++w){
439  std::vector<float> thisWire;
440  for(size_t t = 0; t < view[w].size(); ++t){
441  float chargeSC = static_cast<float>(view[w][t]);
442  thisWire.push_back(chargeSC);
443  }
444  newVec.push_back(thisWire);
445  }
446  return newVec;
447 }
448 
450 
451  cvn::ImageVectorF newImage;
452  for(size_t w = 0; w < image.size(); ++w){
453  cvn::ViewVectorF thisWire;
454  for(size_t t = 0; t < image[w].size(); ++t){
455  std::vector<float> thisTime;
456  for(size_t v = 0; v < image[w][t].size(); ++v){
457  float chargeSC = static_cast<float>(image[w][t][v]);
458  thisTime.push_back(chargeSC);
459  }
460  thisWire.push_back(thisTime);
461  }
462  newImage.push_back(thisWire);
463  }
464  return newImage;
465 }
466 
468 
469  // Tensorflow wants things in the arrangement <wires, TDCs, views>
470  cvn::ImageVector image;
471  for(unsigned int w = 0; w < v0.size(); ++w){
472  std::vector<std::vector<unsigned char> > wireVec;
473  for(unsigned int t = 0; t < v0[0].size(); ++t){
474  std::vector<unsigned char> timeVec;
475  timeVec.push_back(v0[w][t]);
476  timeVec.push_back(v1[w][t]);
477  timeVec.push_back(v2[w][t]);
478  wireVec.push_back(timeVec);
479  } // Loop over tdcs
480  image.push_back(wireVec);
481  } // Loop over wires
482 
483  return image;
484 
485 }
486 
488 
489  // Tensorflow wants things in the arrangement <wires, TDCs, views>
490  cvn::ImageVectorF image;
491  for(unsigned int w = 0; w < v0.size(); ++w){
492  std::vector<std::vector<float> > wireVec;
493  for(unsigned int t = 0; t < v0[0].size(); ++t){
494  std::vector<float> timeVec;
495  timeVec.push_back(v0[w][t]);
496  timeVec.push_back(v1[w][t]);
497  timeVec.push_back(v2[w][t]);
498  wireVec.push_back(timeVec);
499  } // Loop over tdcs
500  image.push_back(wireVec);
501  } // Loop over wires
502 
503 
504 
505  return image;
506 }
507 
std::vector< ViewVectorF > ImageVectorF
Definition: CVNImageUtils.h:21
std::vector< std::vector< float > > ViewVectorF
Definition: CVNImageUtils.h:20
ImageVectorF ConvertImageVecToImageVecF(ImageVector image)
Convert a ImageVector into a ImageVectorF.
void ConvertChargeVectorsToImageVector(std::vector< float > &v0pe, std::vector< float > &v1pe, std::vector< float > &v2pe, ImageVector &imageVec)
Convert three adc vectors into an image vector (contains all three views)
unsigned int fPixelMapWires
Input pixel map sizes.
std::vector< float > fPEY
Vector of Y PE measurements for pixels.
Definition: PixelMap.h:82
void DisableRegionSelection()
Disable the selection of the wire region and just use the first 500 wires.
void ConvertChargeVectorsToPixelArray(std::vector< float > &v0pe, std::vector< float > &v1pe, std::vector< float > &v2pe, std::vector< unsigned char > &pix)
unsigned int fNWire
Number of wires, length of pixel map.
Definition: PixelMap.h:78
void SetViewReversal(bool reverseX, bool reverseY, bool reverseZ)
Function to set any views that need reversing.
void SetLogScale(bool setLog)
Set the log scale for charge.
std::vector< ViewVector > ImageVector
Definition: CVNImageUtils.h:19
void ConvertPixelMapToPixelArray(const PixelMap &pm, std::vector< unsigned char > &pix)
Convert a Pixel Map object into a single pixel array with an image size nWire x nTDC.
void EnableRegionSelection()
Enable the selection of the wire region.
void ReverseView(std::vector< float > &peVec)
Funtion to actually reverse the view.
void GetMinMaxTDCs(std::vector< float > &tdcCharges, unsigned int &minTDC, unsigned int &maxTDC)
Get the minimum and maximum tdcs from the pixel map needed to make the image.
unsigned char ConvertChargeToChar(float charge)
Convert the hit charge into the range 0 to 255 required by the CVN.
ImageVector BuildImageVector(ViewVector v0, ViewVector v1, ViewVector v2)
Make the image vector from the view vectors.
std::vector< float > fPEZ
Vector of Y PE measurements for pixels.
Definition: PixelMap.h:83
const double e
void ConvertPixelMapToImageVector(const PixelMap &pm, ImageVector &imageVec)
Convert a pixel map into an image vector (contains all three views)
Utilities for producing images for the CVN.
void ConvertChargeVectorsToImageVectorF(std::vector< float > &v0pe, std::vector< float > &v1pe, std::vector< float > &v2pe, ImageVectorF &imageVec)
Float version of conversion for convenience of TF interface.
bool fDisableRegionSelection
Disable the region finding?
void GetMinMaxWires(std::vector< float > &wireCharges, unsigned int &minWire, unsigned int &maxWire)
Get the minimum and maximum wires from the pixel map needed to make the image.
std::vector< float > fPEX
Vector of X PE measurements for pixels.
Definition: PixelMap.h:81
std::vector< bool > fViewReverse
Vector of bools to decide if any views need to be reversed.
void ConvertChargeVectorsToViewVectors(std::vector< float > &v0pe, std::vector< float > &v1pe, std::vector< float > &v2pe, ViewVector &view0, ViewVector &view1, ViewVector &view2)
Base function for conversion of the Pixel Map to our required output format.
unsigned int fNTDCs
Number of TDCs to use for the image height.
unsigned int fNViews
Number of views of each event.
bool fUseLogScale
Use a log scale for charge?
void ConvertPixelMapToImageVectorF(const PixelMap &pm, ImageVectorF &imageVec)
Convert a pixel map into an image vector (float version)
ImageVectorF BuildImageVectorF(ViewVectorF v0, ViewVectorF v1, ViewVectorF v2)
void SetImageSize(unsigned int nWires, unsigned int nTDCs, unsigned int nViews)
Set up the image size that we want to have.
void ConvertPixelArrayToImageVectorF(const std::vector< unsigned char > &pixelArray, ImageVectorF &imageVec)
Convert a pixel array into a ImageVectorF.
ViewVectorF ConvertViewVecToViewVecF(ViewVector view)
Convert a ViewVector into a ViewVectorF.
unsigned int fPixelMapTDCs
unsigned int fNWires
Number of wires to use for the image width.
PixelMap, basic input to CVN neural net.
Definition: PixelMap.h:22
std::vector< std::vector< unsigned char > > ViewVector
Useful typedefs.
Definition: CVNImageUtils.h:18
unsigned int fNTdc
Number of tdcs, width of pixel map.
Definition: PixelMap.h:79
QTextStream & endl(QTextStream &s)
void SetPixelMapSize(unsigned int nWires, unsigned int nTDCs)
Set the input pixel map size.