11 #ifndef MESH_PROCESS_SIGNAL_HPP
12 #define MESH_PROCESS_SIGNAL_HPP
39 setName(
"Mesh/System/View");
40 setDesc(
"Modify how the current mesh is viewed. Useful for scripts.");
41 setIcon(QIcon(
":/images/Palette.png"));
43 addParm(
"Show Surface",
"Draw mesh as a continuous surface",
"", QStringList() <<
"" <<
"Yes" <<
"No");
44 addParm(
"Use Parents",
"Use parent labels",
"", QStringList() <<
"" <<
"Yes" <<
"No");
45 addParm(
"Surface Type",
"Vertex: show projected signal, Tris: color by triangle, Cells: Color by Label)",
"",
46 QStringList() <<
"" <<
"Vertex" <<
"Tris" <<
"Cells");
47 addParm(
"Vertex Signal",
"Signal: show projected signal, Stack Texture: Use 3D stack as texture, Image Texture: Use 2D texture (height map)",
"",
48 QStringList() <<
"" <<
"Signal" <<
"Stack Texture" <<
"Image Texture");
49 addParm(
"Cells Signal",
"Label: show labels, Label Heat: show heat map, Wall Heat: show wall heat map, Cell Color: show cell color",
"",
50 QStringList() <<
"" <<
"Label" <<
"Label Heat" <<
"Wall Heat" <<
"Cell Color");
51 addParm(
"Blend",
"Semi-transparent mesh, for example to superimpose to meshes or view the stack through the mesh.",
"",
52 QStringList() <<
"" <<
"Yes" <<
"No");
53 addParm(
"Cull",
"Color the triangles (with signal or labels) only on the top of the mesh.",
"",
54 QStringList() <<
"" <<
"Yes" <<
"No");
55 addParm(
"Show Mesh",
"Draw triangle edges and nodes",
"", QStringList() <<
"" <<
"Yes" <<
"No");
56 addParm(
"Mesh View",
"All: draw all triangles, Border: draw outside edge of the mesh only, Cells: draw cell outlines only, "
57 "Selected: draw selected nodes only",
"", QStringList() <<
"" <<
"All" <<
"Border" <<
"Cells" <<
"Selected");
58 addParm(
"Show Lines",
"Show connecting lines between nodes in the mesh.",
"", QStringList() <<
"" <<
"Yes" <<
"No");
59 addParm(
"Show Points",
"Show mesh nodes.",
"", QStringList() <<
"" <<
"Yes" <<
"No");
60 addParm(
"Show Map",
"Mapping of text on the labels (e.g. label number)",
"", QStringList() <<
"" <<
"Yes" <<
"No");
61 addParm(
"Scale",
"Change scaling of mesh/stacks, independently in 3 directions (x,y,z). NB: ",
"", QStringList() <<
"" <<
"Yes" <<
"No");
62 addParm(
"Transform",
"a stack saved with 'Scale' turned on will have a modified voxel size, while saved meshes are unaffected. ",
"",
63 QStringList() <<
"" <<
"Yes" <<
"No");
64 addParm(
"BBox",
"Apply rotation and translation to the mesh/stack.",
"", QStringList() <<
"" <<
"Yes" <<
"No");
65 addParm(
"Brightness",
"Display the bounding box (i.e. total size) of a stack.",
"-1");
66 addParm(
"Opacity",
"Brightness of signal, labels or heat",
"-1");
81 setName(
"Mesh/Signal/Project Signal");
82 setDesc(
"Project signal onto mesh, perpendicular to its curved surface.");
83 setIcon(QIcon(
":/images/ProjectColor.png"));
85 addParm(
"Use absolute",
"Use absolute values of signal, instead of normalizing it, useful for signal quantification.",
"No",booleanChoice());
86 addParm(
"Min Dist (µm)",
"Distance (triangle-voxel) above which the signal is projected.",
"2.0");
87 addParm(
"Max Dist (µm)",
"Maximal distance (triangle-voxel) used for signal projection.",
"6.0");
88 addParm(
"Min Signal",
"Lower bound of signal value if 'Use absolute' is chosen",
"0.0");
89 addParm(
"Max Signal",
"Upper bound of projected signal value.",
"60000.0");
94 if(!checkState().store(STORE_NON_LABEL).mesh(MESH_NON_EMPTY))
96 return run(currentStack()->currentStore(), currentMesh(),
stringToBool(parm(
"Use absolute")),
97 parm(
"Min Dist (µm)").toFloat(), parm(
"Max Dist (µm)").toFloat(), parm(
"Min Signal").toFloat(), parm(
"Max Signal").toFloat());
100 bool run(
const Store* store,
Mesh* mesh,
bool useAbsSignal,
float minDist,
101 float maxDist,
float absSignalMin,
float absSignalMax);
102 void projSignal(
const Stack* stack,
const HVecUS& data,
vertex v,
float mindist,
float maxdist);
117 setName(
"Mesh/Segmentation/Project 3D Labels on Mesh");
118 setDesc(
"Project labels onto mesh, perpendicular to its curved surface.");
119 setIcon(QIcon(
":/images/ProjectColor.png"));
121 addParm(
"Use absolute",
"Use absolute values of signal, instead of normalizing it, useful for signal quantification.",
"No",booleanChoice());
122 addParm(
"Min Dist (µm)",
"Distance (triangle-voxel) above which the signal is projected.",
"2.0");
123 addParm(
"Max Dist (µm)",
"Maximal distance (triangle-voxel) used for signal projection.",
"6.0");
124 addParm(
"Labeling Method",
"Labeling Method",
"Majority",QStringList() <<
"Majority" <<
"Absolute Majority");
125 addParm(
"Ignore Zero",
"Ignore Zero",
"No",booleanChoice());
130 return run(currentStack()->currentStore(), currentMesh(),
131 parm(
"Min Dist (µm)").toFloat(), parm(
"Max Dist (µm)").toFloat(), parm(
"Labeling Method"),
stringToBool(parm(
"Ignore Zero")));
134 bool run(
const Store* store,
Mesh* mesh,
float minDist,
135 float maxDist, QString method,
bool ignoreZero);
136 void projLabel(
const Stack* stack,
const HVecUS& data,
vertex v,
float mindist,
float maxdist,
int zeroLabel, QString method,
bool ignoreZero);
150 setName(
"Mesh/Segmentation/Project Nearest 3D Label on Mesh");
151 setDesc(
"Find the stack labeled for the positions of each vertex. Might not be needed anymore!");
152 setIcon(QIcon(
":/images/MakeHeatMap.png"));
154 addParm(
"Split Border",
"Split Border",
"Yes",booleanChoice());
155 addParm(
"Search Radius",
"Search Radius",
"0");
160 Stack* s1 = currentStack();
162 Mesh* m = currentMesh();
163 return run(s1, store1, m,
stringToBool(parm(
"Split Border")), parm(
"Search Radius").toInt());
166 bool run(
Stack* s1,
Store* store1,
Mesh* m,
bool splitBorder,
int searchNeighborhood);
182 setName(
"Mesh/Signal/Smooth Mesh Signal");
183 setDesc(
"Averages the signal of each node, based on its immediate neighbors.");
184 setIcon(QIcon(
":/images/SmoothColor.png"));
186 addParm(
"Passes",
"Number of smoothing iterations.",
"3");
191 if(!checkState().mesh(MESH_NON_EMPTY))
193 return run(currentMesh(), parm(
"Passes").toUInt());
209 setName(
"Mesh/Signal/Mesh Brighness");
210 setDesc(
"Changes the brightness of the signal on a mesh.");
211 setIcon(QIcon(
":/images/Brightness.png"));
213 addParm(
"Amount",
"Amount to multiply the signal, >1 is brighter",
"2.0");
218 if(!checkState().mesh(MESH_NON_EMPTY))
220 return run(currentMesh(), parm(
"Amount").toFloat());
223 bool run(
Mesh* mesh,
float amount);
237 setName(
"Mesh/Signal/Clear Mesh Signal");
238 setDesc(
"Erase the signal on the mesh");
239 setIcon(QIcon(
":/images/ClearSignal.png"));
241 addParm(
"Value",
"Assign this signal value to the mesh.",
"50000");
246 if(!checkState().mesh(MESH_NON_EMPTY))
248 return run(currentMesh(), parm(
"Value").toUInt());
266 setName(
"Mesh/Signal/Project Mesh Curvature");
267 setDesc(
"Compute curvature at each node of the mesh, for a given neighborhood size. Curvature values are stored as signal.");
268 setIcon(QIcon(
":/images/Curvature.png"));
270 addParm(
"Output",
"Name of output file, if desired.",
"");
271 addParm(
"Type",
"Minimal = minCurv, Maximal = maxCurv, Gaussian = maxCurv * minCurv, SumSquare = maxCurv^2 + minCurv^2, Average = (maxCurv + minCurv)/2, SignedAverageAbs = sign(max or min) x (abs(maxCurv) + abs(minCurv))/2",
"Gaussian", QStringList() <<
"Minimal" <<
"Maximal" <<
"Gaussian" <<
"SumSquare" <<
"Average" <<
"SignedAverageAbs");
272 addParm(
"Neighborhood (µm)",
"Neighborhood (µm)",
"3.0");
273 addParm(
"AutoScale",
"Clip max and min signal range according to curvature distribution",
"Yes",booleanChoice());
274 addParm(
"Min Curv",
"Minimal curvature value displayed",
"-50.0");
275 addParm(
"Max Curv",
"Maximal curvature value displayed",
"50.0");
276 addParm(
"Autoscale percentile",
"Auto-scale signal range based on curvature percentile",
"85");
281 if(!checkState().mesh(MESH_NON_EMPTY))
284 float neighborhood = parm(
"Neighborhood (µm)").toFloat(&ok);
286 return setErrorMessage(
"Error, parameter 'Neighborhood' must be a number");
287 float mincurv = parm(
"Min Curv").toFloat(&ok);
289 return setErrorMessage(
"Error, parameter 'Min Curv' must be a number");
290 float maxcurv = parm(
"Max Curv").toFloat(&ok);
292 return setErrorMessage(
"Error, parameter 'Max Curv' must be a number");
293 float percentile = parm(
"Autoscale percentile").toFloat(&ok);
295 return setErrorMessage(
"Error, parameter 'Percentile' must be a number");
296 return run(currentMesh(), parm(
"Output"), parm(
"Type"), neighborhood,
stringToBool(parm(
"AutoScale")),
297 mincurv, maxcurv, percentile);
300 bool run(
Mesh* mesh, QString output, QString type,
float neighborhood,
301 bool auto_scale,
float mincurv,
float maxcurv,
int percentile);
316 setName(
"Mesh/Signal/Signal Gradient");
317 setDesc(
"Gradient of mesh signal");
318 setIcon(QIcon(
":/images/Blur.png"));
320 addParm(
"Radius (µm)",
"Size of neighborhood used for Gaussian blur. The blur function standard deviation is given by sigma = radius/2. ",
"2.0");
325 if(!checkState().mesh(MESH_NON_EMPTY))
327 return run(currentMesh());
330 bool run(
Mesh* mesh);
346 setName(
"Mesh/Signal/Gaussian Blur");
347 setDesc(
"Apply Gaussian Blur to mesh signal");
348 setIcon(QIcon(
":/images/Blur.png"));
350 addParm(
"Radius (µm)",
"Size of neighborhood used for Gaussian blur. The blur function standard deviation is given by sigma = radius/2. ",
"2.0");
355 if(!checkState().mesh(MESH_NON_EMPTY))
357 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
360 bool run(
Mesh* mesh,
float radius);
374 setName(
"Mesh/Signal/Difference of Gaussians");
375 setDesc(
"Calculate a difference of Gaussians for the mesh signal");
376 setIcon(QIcon(
":/images/Blur.png"));
378 addParm(
"Radius1 (µm)",
"Size of first neighborhood",
"1.0");
379 addParm(
"Radius2 (µm)",
"Size of second neighborhood",
"5.0");
384 if(!checkState().mesh(MESH_NON_EMPTY))
386 return run(currentMesh(), parm(
"Radius1 (µm)").toFloat(), parm(
"Radius2 (µm)").toFloat());
389 bool run(
Mesh* mesh,
float radius1,
float radius2);
403 setName(
"Mesh/Segmentation/Auto Seeding");
404 setDesc(
"Put a seed at local minima of mesh signal.");
405 setIcon(QIcon(
":/images/LocalMinima.png"));
407 addParm(
"Radius (µm)",
"Size of neighborhood used for search of local minima. Typically, the radius of smallest cells in the sample.",
"3.0");
408 addParm(
"Consider existing Labels",
"Consider existing Labels",
"Yes",booleanChoice());
413 if(!checkState().mesh(MESH_NON_EMPTY))
415 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
418 bool run(
Mesh* mesh,
float radius);
432 setName(
"Mesh/Signal/Normalize Signal");
433 setDesc(
"Normalize mesh signal locally.");
434 setIcon(QIcon(
":/images/Normalize.png"));
436 addParm(
"Radius (µm)",
"Size of neighborhood used for normalization.",
"5.0");
441 if(!checkState().mesh(MESH_NON_EMPTY))
443 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
447 bool run(
Mesh* mesh,
float radius);
463 setName(
"Mesh/Signal/Dilate Signal");
464 setDesc(
"Morphological dilation of signal on mesh.");
465 setIcon(QIcon(
":/images/Dilate.png"));
467 addParm(
"Radius (µm)",
"Size of neighborhood used for dilation.",
"1.0");
472 if(!checkState().mesh(MESH_NON_EMPTY))
474 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
477 bool run(
Mesh* mesh,
float radius);
493 setName(
"Mesh/Segmentation/Dilate Labels");
494 setDesc(
"Morphological dilation of labels on mesh.");
495 setIcon(QIcon(
":/images/Dilate.png"));
497 addParm(
"Radius (µm)",
"Size of neighborhood used for dilation.",
"1.0");
502 if(!checkState().mesh(MESH_NON_EMPTY))
504 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
507 bool run(
Mesh* mesh,
float radius);
525 setName(
"Mesh/Signal/Erode Signal");
526 setDesc(
"Apply morphological erosion to mesh signal (opposite to Dilate Signal).");
527 setIcon(QIcon(
":/images/Erode.png"));
529 addParm(
"Radius (µm)",
"Size of neighborhood used for erosion.",
"1.0");
534 if(!checkState().mesh(MESH_NON_EMPTY))
536 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
539 bool run(
Mesh* mesh,
float radius);
555 setName(
"Mesh/Segmentation/Erode Labels");
556 setDesc(
"Apply morphological erosion to mesh signal (opposite to Dilate Labels).");
557 setIcon(QIcon(
":/images/Erode.png"));
559 addParm(
"Radius (µm)",
"Size of neighborhood used for erosion.",
"1.0");
564 if(!checkState().mesh(MESH_NON_EMPTY))
566 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
569 bool run(
Mesh* mesh,
float radius);
585 setName(
"Mesh/Signal/Close Signal");
586 setDesc(
"Apply morphological dilation followed by erosion to mesh signal.");
587 setIcon(QIcon(
":/images/Closing.png"));
589 addParm(
"Radius (µm)",
"Size of neighborhood used for dilation/erosion.",
"1.0");
594 if(!checkState().mesh(MESH_NON_EMPTY))
596 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
599 bool run(
Mesh* mesh,
float radius);
614 setName(
"Mesh/Signal/Open Signal");
615 setDesc(
"Apply morphological erosion followed by dilation to mesh signal.");
616 setIcon(QIcon(
":/images/Opening.png"));
618 addParm(
"Radius (µm)",
"Size of neighborhood used for erosion/dilation.",
"1.0");
623 if(!checkState().mesh(MESH_NON_EMPTY))
625 return run(currentMesh(), parm(
"Radius (µm)").toFloat());
628 bool run(
Mesh* mesh,
float radius);
637 setName(
"Mesh/Signal/Rescale Signal");
638 setDesc(
"Change the colorbar of the signal. \n"
639 "If percentile is set to 0, it uses the minimum and maximum arguments. \n"
640 "Only the visualization is affected, the signal projection remains unchanged");
641 setIcon(QIcon(
":/images/Normalize.png"));
643 addParm(
"Zero as reference",
"If true, 0 will be used as a reference. \n"
644 "If the signal is all positive (resp. negative), 0 will be added as a minimum (resp. maximum). \n"
645 "If the signal is both positive and negative, 0 will be place at the center of the range",
"No",booleanChoice());
646 addParm(
"Percentile",
"Keep only this percentage of the signal to compute the range.",
"99");
647 addParm(
"Minimum",
"If the percentile specified is 0, uses this as the minimum value for the range",
"0");
648 addParm(
"Maximum",
"If the percentile specified is 0, uses this as the maximum value for the range",
"1");
653 if(!checkState().mesh(MESH_NON_EMPTY))
656 float percentile = parm(
"Percentile").toFloat(&ok);
658 return setErrorMessage(
"Error, argument 'Percentile' must be a number");
659 float minimum = parm(
"Minimum").toFloat(&ok);
661 return setErrorMessage(
"Error, argument 'Minimum' must be a number");
662 float maximum = parm(
"Maximum").toFloat(&ok);
664 return setErrorMessage(
"Error, argument 'Maximum' must be a number");
665 return run(currentMesh(),
stringToBool(parm(
"Zero as reference")), percentile, minimum, maximum);
668 bool run(
Mesh* mesh,
bool use_zero,
float percentile,
float minimum,
float maximum);
682 setName(
"Mesh/Signal/Set Signal");
683 setDesc(
"Set the signal for the whole mesh, or for the currently selected part of it.");
684 setIcon(QIcon(
":/images/Sharpen.png"));
686 addParm(
"Value",
"New value for the signal",
"1");
687 addParm(
"Rescale",
"If true, the signal bounds will be rescaled",
"Yes",booleanChoice());
688 addParm(
"Percentile",
"If rescaling, which percentile to use?",
"100");
689 addParm(
"Use zero",
"If rescaling, should we use zero as reference?",
"No",booleanChoice());
694 if(not checkState().mesh(MESH_VISIBLE))
697 float value = parm(
"Value").toFloat(&ok);
699 return setErrorMessage(
"Parameter 'Value' must be a number");
700 float percentile = parm(
"Percentile").toFloat(&ok);
702 return setErrorMessage(
"Parameter 'Percentile' must be a number");
703 return run(currentMesh(), value,
stringToBool(parm(
"Rescale")), percentile,
707 bool run(
Mesh* m,
float value,
bool rescale,
float percentile,
bool use_zero);
717 FloatVec& values, std::vector<Curvature>& curvs);
718 void operator()(
int i);
726 std::vector<Curvature>& curvs;
733 void operator()(
int i);
747 void operator()(
int i);
760 void operator()(
int i);
775 void operator()(
int i);
788 void operator()(
int vi);
801 void operator()(
int vi);
814 void operator()(
int vi);
827 void operator()(
int vi);
842 setName(
"Mesh/Signal/Export Histogram Circular");
843 setDesc(
"Computes a circular histogram in counter-clockwise direction of the active main store signal values around the given cartesian axis.");
844 setIcon(QIcon(
":/images/StackHistoCirc.png"));
846 addParm(
"Central Axis",
"Central Axis",
"Z", QStringList() <<
"X" <<
"Y" <<
"Z");
847 addParm(
"Bin Number",
"Number of bins for the whole circle",
"360");
848 addParm(
"Value Threshold (%)",
"Ignore voxels with values lower than this threshold (% from max value). Set to 0 to include all",
"1.0");
849 addParm(
"Distance Min (um)",
"Only consider voxels with a minimum distance to the Bezier larger than this. Set to -1 to include all.",
"-1");
850 addParm(
"Distance Max (um)",
"Only consider voxels with a maximum distance to the Bezier smaller than this. Set to -1 to include all.",
"-1");
851 addParm(
"Align at Max",
"Align at Max",
"No", QStringList() <<
"Align at Max of Signal Sum" <<
"Align at Signal Max" <<
"No");
852 addParm(
"Weight by Area",
"Weight signal values by the triangle area",
"Yes",booleanChoice());
853 addParm(
"Filename",
"Filename",
"");
854 addParm(
"Set Mesh Labels to Bin",
"Set Mesh Labels to Bin",
"No",booleanChoice());
857 bool initialize(QWidget* parent);
861 Stack* s1 = currentStack();
862 Mesh* m1 = currentMesh();
863 return run(s1, m1, parm(
"Central Axis"), parm(
"Bin Number").toInt(), parm(
"Value Threshold (%)").toDouble(), parm(
"Distance Min (um)").toDouble(),
864 parm(
"Distance Max (um)").toDouble(), parm(
"Align at Max"),
stringToBool(parm(
"Weight by Volume")), parm(
"Filename"),
stringToBool(parm(
"Set Mesh Labels to Bin")));
866 bool run(
Stack* s1,
Mesh* m1, QString centralAxis,
int binNumber,
double thresholdValue,
double minDis,
double maxDis, QString align,
bool weightVol, QString filename,
bool writeLabels);