################################################################### UPDATE: 26 Apr 2024 ################################################################### Summary: (1) 4-step undo edit in tkmedit (one-step redo) (2) tksurfer gradient arrows pruning function (3) tkmedit range and 2nd image range edit functs (mouse,do-all) (4) tkmedit brightness-centerable distance-dep contrast ramp (5) new filled gradient arrowheads (6) new funct to distance sort single-vertex-wide label paths (7) new R-clk buttonbars (label S/T/X, val R/CLR/CS, SMOOTH, area D) ------------------------------------------- 4-step undo, 1-step redo in tkmedit ------------------------------------------- There is now (finally!) a basic undo/redo edit function in tkmedit. It is a 4-step undo, which means it can undo up to four sequential right-clicks or right-click-drags (to black) or middle-clicks or middle-click-drags (to white), and a 1-step redo (undo the most recent undo). To undo, use alt/cmd-z (small 'z') in the image or tools window. To redo one previously undone edit, use alt/cmd-Z (shift/capital 'Z'). Alternate undo/redo clicks in the image window are ctrl-left-click (undo) and shift-ctrl-left-click (redo). The undo and redo functions also work with any tkmedit operations that affect the editable buffer (im) such as: TRUNC (options that affect im, not im2) PF/PFGAU (options that affect im, not im2) SMOOTHSTRUCT COMPARE (shift-left-click-COMPARE for visible_to_im) APPLY (F3 panel linear/gaussian ramps, applied to im) OP (edit im using color ellipse from im,im2) Enabling undo very slightly slows editing on 512^3 data sets. It can be disabled with the "un" tickbox next to the CORONAL button (to see the small difference). ------------------------------------------- New filled arrowheads option ------------------------------------------- The default arrowhead for display of vector data (e.g., gradients) were line arrows (line for stem, two lines for arrow barbs). These are well adapted to dense arrow displays. However, now that there is way to prune vector fields (see next), a new arrow type with a filled arrowhead has been added. The filled arrowheads are made of four adjustable triangles: two for the arrow barbs, and two forming a diamond for the point. Here are the parameters for fine-tuning the arrow display for the two types: line arrows $arrownormflag -- normalize all arrows to same length $arrowscale -- adjust all arrows lengths $arrowline -- adjust thickness of arrow line $arrowheadfracauto -- scale arrowhead to stem length $set arrowheadmin -- minimum size of scaled arrow $line_arrowbarbangle -- angle between barb and stem Filled Arrows $arrownormflag -- normalize all arrows to same length $arrowscale -- adjust all arrows lengths $arrowline -- adjust thickness of arrow stem $arrowheadfracauto -- scale arrowhead to stem length $set arrowheadmin -- minimum size of scaled arrow $filled_arrowtipangle -- tip/stem angle $filled_arrowbarbangle -- back of barb/stem angle ------------------------------------------- Pruning gradient vectors ------------------------------------------- Gradient calculations result in a very large number of gradient arrows (one per vertex), which will look cluttered (unless the surface is strongly zoomed). A R-click on the unlabeled tickbox to the left of "fs:" (middle left), brings up a popup for controlling gradient (and fieldsign) arrows. There is a PRUNE ARROWS button at the bottom of the popup. The density of arrows is set by the $gridsize parameter (in mm) on the popup. The "prunearrowsflag" toggles between pruning and no pruning. N.B.: click PRUNE ARROWS again to see the effect of adjusting $gridsize. The pruning works by only showing one arrow for each specified-size grid cell. Since the actual vertex location of the arrow is used, the grid will be slightly irregular. Also remember that *.val (or *.stat) thresholds can be used to prune 'noise' arrows by setting $fthresh (or $sfthresh if "mask" is ticked), and then recalculating the gradient arrows. ---------------------------------------------- New tkmedit funct: crop_im_using_im2cols ---------------------------------------------- This can crop an edtabale image using another imageset. This requires that a second image has been loaded using "R" on the bottom middle "im2:" line. A control-mid-click on the TRUNC button truncates the editable buffer (im) using locations in the second buffer (im2) that have colors within/including $while_lolim to $white_hilim (entries immediately right of TRUNC button) to a new color, $gray_hilim (entry to right of PF button): for im2 range: lo: $white_lolim hi: $white_hilim im new: $gray_hilim The editable buffer can then be saved with SAVE IMGS (overwrites editable image), or "W" on "im:" line (F1 interface) if you want to SaveAs/rename the result. To duplicate the result of a hand-edit to black, use target color 1 (EDITED_TO_OFF). This can be used, for example, to crop the background of the editable image set using a different (already processed) image set. ---------------------------------------------- New tkmedit funct: crop_im_using_im2cols_save ---------------------------------------------- Similar to crop_im_using_im2cols above, but only edits image if im (editable image) is outside the range of: lo: $edit_lolim2 hi: $edit_hilim2 This second pair of limits allows saving more structure in the editable image. For a mouse-driven version of the same thing, use shift-left-click in the image window. First do R-click on the entries to the right of the TRUNC button to get a popup to control $edit_lolim2 and $edit_hilim2. ------------------------------------------- New tkmedit funct: cp_im_to_im2_replacing_cols ------------------------------------------- This can edit a range of colors in an editable image to a single color. A shift-right-click copies the entire contents of the editable buffer to im2, replacing a range of colors (including range limit values) in the editable buffer with a single im2 color. shift-right-click TRUNC. The im color range to replace is specified by the values in the 2 entries to the right of the TRUNC button, and the new/replaced im2 color by the entry to the right of the PF button: for im range: lo: $white_lolim hi: $white_hilim im2 new: if within range: $gray_hilim else: same as im To save the color-replaced im2 buffer, first swap it to editable buffer: middle-click-COMPARE SAVE IMGS *or* "W" on "im:" line In contrast to the in-place operation above, crop_im_using_im2cols, this allows a blink comparison using the COMPARE button, because only one image is initially loaded. To duplicate the result of a hand-edit to black, use target color 1 (EDITED_TO_OFF). This can be used, for example, to edit bright fluid to black in place. ------------------------------------------- New image window mouse editing options ------------------------------------------- In parallel with the three functions above, bounds-dependent editing also works with interactive mouse-driven edits in the image window, using a shift-left-click. First, do a R-click on the entries to the right of WMTRUNC to get a popup with all controlling parameters. (1) Bounds-dependent mouse edit on im Edit pixels in the editable image (im) within currently specified bounds (2 entries to right of TRUNC button, also in popup) to a target value (entry to right of PF button, also in popup). (2) Bounds-dependent mouse edit on im using im2 If $im2boundsflag is 1 (middle click "la" tickbox to toggle), edit pixels in the editable image, but test whether pixels in im2 are within the requested bounds (N.B.: edits still go to the editable im). To preserve structure of the editable image, use $edit_lolim2 and $edit_hilim2 to block edits if editable pix is within these bounds (see popup). This can save structure in the editable image. ------------------------------------------- New tkmedit funct: visible_to_im ------------------------------------------- A third alternate shift-middle-click of the COMPARE button copies the contrast-adjusted visible pixel values (N.B.: currently in the editable buffer) to the editable buffer, overwriting its current contents. N.B.: the contrast-adjusted image is typically the result of a non-linear (e.g., sigmoid) function. To avoid applying the contrast adjustments recursively, $linearflag is set to 1 (see interface button on lower right of large F4 interface panel). This can be used, for example, to save a contrast-reversed image (negative value for "contr:"), or a contrast-enhanced image. N.B.: using SAVE IMGS will overwrite the initial dataset, so to save the contrast-adjusted images to a new file, enter a name in the upper right "im:" entry and click "W". ------------------------------------------- New brightness-centerable distance-dep contrast ramp ------------------------------------------- On the [fn-]F3 tkmedit interface, a left-click on the middle-right "PieceWiseLinNorm" title brings up a popup with controls for setting the $contrastnochange value and $constrastslope. When a piecewise linear ramp (or a spherical linear or Gaussian ramp) is applied, the contrast can be increased as a function of distance. This will have no effect unless ffrac0,1,2,3 are changed from the default 1.0 (no brightness change). ------------------------------------------- Interface support for 'paintball' annots ------------------------------------------- A shift-middle click on the SMOOTH button brings up a popup providing interface support to run the C/tcl function, neighop_val2stat (with operation=3), for generating 'paintball' label/annots. This function generates a set of non-overlapping label/annotation regions, whose size is specified by vertex neighbor order (1=justneighbors, 2=neighbors-of-neighbors, etc). The special operation=3 here is the only one that ignores the .val field while writing to the .stat field (the other operations for neighop_val2stat are parallel to the operations in searchlightop_val2stat). Here are the neighbor counts for the fsaverage surfaces: 1-neighbors: 7 2-neighbors: 19 3-neighbors: 37 4-neighbors: 61 5-neighbors: 91 6-neighbors: 127 When neighop_val2stat is run with operation=3, it generates the non-overlapping regions as sequentially-numbered, integer values in the .stat field. There will be small unlabeled regions in between each non-overlapping, approximately circular patch. To fill these in, click the GROW STAT IDNUMS button (C/tcl function grow_stat_idnums). This selects a shuffled vertex and then, if it is empty, adds it to an existing region if any of its neighbors already have an idnum in the .stat field. The .stat idnum regions can then be turned into an MGH annotation in order to use these regions for further analysis. This was originally written to display the size of hypothetical granule cell patches in the cerebellar cortex :-} The regions are given random (non-overlapping) colors in the output MGH annot file. To see or use the result: (1) save the .stat regions to a randcol annot file: --R-click "label:" line "W" to get popup --choose output file name in "label:" entry --"Write StatIds to RandCol MGH Annot" button (2) display/use resulting annot file: --use "label:" line "D" button ------------------------------------------- New function to sort single-vertex-wide label paths ------------------------------------------- A new function, write_sorted_by_pathdist_label, reads the current label ("label:" entry) and then sorts the lines in the ASCII file by the Euclidean distance along a path from the last interactively selected vertex (e.g., the beginning of a single-vertex-wide label path). It simply copies any overlay data that may or may not be included in the original label file. The second vertex will be the closest to the initially selected vertex, the third vertex will be the closest to the second vertex, and so on (so this is not equivalent to merely sorting vertices by distance from the initial vertex). Standard freesurfer/csurf labels are normally written in vertex number order (but since the csurf/freesurfer label-reading code ignores the order of lines in the label file, the sorted file will still be readable). However, an external program can now use the re-ordered lines in the sorted output file to find the path order. This function can successfuly sort a path label containing a series of vertices along a line that curves back on itself (as long as it doesn't cross itself, since there is no linearity constraint). N.B.: this function overwrites the input label, but first saves it aside with a tilde (~) suffix. This is useful for sampling data (e.g., phase data) along an arbitrary curved line of vertices. First, save a standard label from a sequence of selected vertices (write_selected_list_to_label, or "Selected Vertices to Label" from R-click help pop-up on "W" on "label:" line) that contains the phase data you want, then path-sort that line label using this function ("Sort Label By Dist From Last Clk" on same popup). This was first written to sort the geodesic path output of mris_pmake. It is also useful for sorting a single vertex line label made by selecting vertices along a line, but not necessarily in exact path order (e.g., if missed vertices have been filled in after roughing out the line). ------------------------------------------- New buttonbar shortcuts remaining overloaded buttons ------------------------------------------- New R-click buttonbars were added for all remaining overloaded buttons lacking them. These include: "area:' line: D (display area ratio curr surf distort) "label:" line: T (t-course), S (stat), X (searchlight xcorr) "val:" line: R (read), CLR (clear), CS (cluster, FDR) SMOOTH button In the process there was a massive cleanup of the buttonbar code to remove event generate hacks. ----------------------------------------------- Bug fixes, small changes ---------------------------------------------- fix draw_arrows3d arrownormflag bug (dz accidentally repeated dx) add labelcol_to_vtxcol to R-click "D" on "label:" line button bar rm dependence on glu.h, -lGLU (tksurfer, wheel) ########################################################################## UPDATE: 26 Apr 2024 ########################################################################## [tmprelease 240426] --tksurfer.tcl: new buttonbar for areal-line "D" button --tksurfer.tcl: new buttonbar for "SMOOTH" button --tksurfer.tcl: conv val-line "W" butt bind's to procs (rm event generate hacks) --tksurfer.tcl: new buttonbar for val line "CLR" button (just 2: val, all) --tksurfer.tcl: new buttonbar for val-line "CS" button (just 2: cluster, FDR) --tksurfer.tcl: conv val-line "S/V" butt bind's to procs (rm event gen hacks) --tksurfer.tcl: new buttonbar for val-line "R" button (bind's -> proc's) --tksurfer.tcl: new button bar for label-line "X" butt (bind's -> proc's) --tksurfer.tcl: new button bar for label-line "S" butt (bind's -> proc's) --tksurfer.tcl: new button bar for label-line "T" butt (bind's -> proc's) --tksurfer.tcl: conv fs-line GR butt bind's to procs (rm event generate hacks) --tksurfer.tcl: conv label-line W butt bind's to procs (rm event generate hack) --tksurfer.tcl: conv label-line R butt bind's to procs (rm event generate hack) --tksurfer.tcl: conv label-line CLR butt bind's to procs (rm eventgenerate hack) --tksurfer.tcl: conv label-line C butt bind's to procs (rm event generate hack) --tksurfer.tcl: conv label-line D butt bind's to procs (rm event generate hack) --tksurfer.tcl: fix stale funct name: read_poi_annot -> read_poi_to_annot [tmprelease 240418] --lib/help/tksurfer/label_write: update write_sorted_by_pathdist_label --tksurfer.tcl: R-clk label W for C pathsort: write_sorted_by_pathdist_label --lib/help/tksurfer/label_write: update neighop_val2stat >op=3> usage --tksurfer.c: add write_sorted_by_dist_label(), uses last click for start vtx --sortlabel: standalone tcl script sorts label by Euclidean dist from start vtx --tksurfer.tcl: sort Dijk label to pathorder, opt insert overlay data into label --tksurfer.tcl: better feedback on Dijk output file, check overwrite --tksurfer.tcl: warn re-run startup, block init-run non-standalone SURFACE-STATS --tkmedit.c: saveim_for_undo() before flip_corview_xyz, im2wmedits_to_im [tmprelease 240129] --tkmedit.c: add parallel image window [shift]-ctrl-left-click for undo/redo --tkmedit.tcl: update cmd-z/Z for new extracted saveim's --tkmedit.c: 1-step redo_edit(), extract/export saveim_for_redo(), undoeditflag --tkmedit.c: rm edit_pixel {UNDO,REDO}_EDIT to export functs {undo,redo}_edit() [tmprelease 240110] --tkmedit.c: fix off-edge access of tmp array for finding existing imprevnums [tmprelease 231230] --tkmedit.tcl: add imim2op help to F4 panel ellipse parms --lib/help/tkmedit/{all,clks,wmtrunc,wmfilter{std,gau},smoothstats,clks,imim2op} --tkmedit.tcl: bind tools window cmd-z to undo --tkmedit.c: saveim_for_undo: smooth_3d,smooth_3d_nn,imim2op --tkmedit.c: saveim_for_undo: visible_to_im/norm_allslices_toim2 --tkmedit.c: saveim_for_undo: crop_im_using_im2cols, crop_im_using_im2cols_save --tkmedit.tcl: TRUNC/PF/PFGAU run_wmfilter does saveim_for_undo --tkmedit.c: trunc undo's to num prev sequential edits, export saveim_for_undo --tkmedit.c.c: implement 4-step undo stack/circbuff (TODO: undo stack) --tksurfer.c: fixed missed shift/ctrl/alt keyreleases b/c of popups --csurf: cbx:listcmd_mri for mritypes combo to force update before dropdown [tmprelease 231221] --tkmedit.c: fix shift/ctrl/alt KeyRelease missed b/c of popups (force 0 before) [tmprelease 231219] --tkmedit.c: 2-step undo (but no redo since no undo stack: curr im overwritten) [tmprelease 231217] --tkmedit.c: export right_click (undo spdtest): alloc imprev like im: 17% better --lib/help/tkmedit/nonbinaryfs: update --tksurfer.tcl: add FIELDSIGN/GRADIENT popup button for sparse arrows defaults --lib/help/tkmedit/undoedit: new helpfile --tkmedit.c: cmd-z in image window for undo edit --tkmedit.tcl: proc editfile pre-deletes any stranded script swapfiles --tkmedit.tcl: "un" tickbox R of CORONAL to enable/disable undo edit ability --tkmedit.c: implement 1 edit undo, export edit_pixel(),$undoeditflag (if slow) [tmprelease 231208] --tkmedit.c: raise F3 interface to keep its bottom on screen --tkmedit.tcl: fixed introduced mispelled "constrastslop" --tksurfer.tcl: add centerarrowsflag to "phc" arr control popup, arrownorm help --lib/help/csurf/tksurfer: mention SMOOTH val2stat searchlight popups --lib/help/tksurfer/script_searchlight{area,diff},smooth --tksurfer.tcl: pre-delete stranded TmpTclScript.tcl swapfiles --tksurfer.tcl: proc editfile pre-deletes stranded TmpTclScript.tcl swapfiles --tksurfer.tcl: add second alt SMOOTH controls popup for run neighop_val2stat --tksurfer.tcl: add write_statids2randcolannot to "label:" line "W" (no hotkey) --tksurfer.c: write_statids2randcolannot(): randcol-annot-from-neigh paintballs --tksurfer.c: shuffleUInt() for write_statids2randcolannot() --tksurfer.c: grow_stat_idnums(): grout randcol nearest neighbor patches [tmprelease 231203] --tksurfer.tcl: put code for tickbox binding into do_grad2col, binding uses it --wrappers.tcl: remove +2 from controls edlabval width test for narrower --tksurfer.tcl: DEFAULT LINE/FILL ARROWS butt FIELDSIGN popup (GR already does) --tksurfer.c,tcl: arrowheadtype->filledarrowsflag, arrowheadfrac->append "auto" --tksurfer.c,tcl: rename: line_arrowbarbangle, filled_arrow{tip,barb}angle --tkmedit.tcl: TRUNC popup: disable 2nd struct-save bounds unless im2boundsflag --tksurfer.tcl: add arrowhead{frac,min,angle} to FIELDSIGN and ARROWS popups --tksurfer.tcl: fix Ret in arrowline FIELDSIGN popup bound to PRUNE_ARROWS but --tksurfer.c: export arrowheadfrac, arrowheadmin, arrowheadangle (rad->deg) --tksurfer.tcl: Return in gridsize entry does prune_arrows --tkmedit.tcl: button bar for TRUNC butt, also put up bounds popup (move it up) --tkmedit.tcl: ctrl-R-click TRUNC for crop_im_using_im2col_save() --tkmedit.c: crop_im_using_im2col_save(): also save im within $edit_{lo,hi}lim --lib/help/tkmedit/{wmtrunc,truncparms}, lib/help/csurf/tkmedit: update [tmprelease 231126] --lib/help/tksurfer/{comp_grad,smooth}: update --tksurfer.tcl: add arrownormflag to FIELDSIGN and GRADIENT ARR CTRLS --tksurfer.c: fix draw_arrows3d arrownormflag bug (dz accidentally repeated dx) --tksurfer.c: new prune_arrows algorithm (nearest vs. 1st), add {make,free}int3D --tksurfer.tcl: PRUNE ARROWS/gridsize/prunearrowsflag: FIELDSIGN/GRAD ARR CTRLS --tksurfer.c: export prune_arrows(), prunearrowsflag --tkmedit.tcl: add toggle circleflag to "rad" label, fix lib/help/tkmedit/brush --tkmedit.c: TEST/APPLY also writes to tcl cmdlog, demo standalone tcl script --tkmedit.c: print norm tcl script for TEST or APPLY (already to tcl cmd log) --tkmedit.c: add contrast ramp into spherical norm --lib/help/csurf/tkmedit: update image window popop help --tkmedit.c: add/export $edit_{lo,hi}lim2 for shift-left click edits using im2 --tkmedit.c: add ctrlkey to dbl-clk image win help to block edit->blk,tcourse --tkmedit.tcl: overload "la" tickbox with toggle $im2boundsflag --$im2boundsflag (so can see editable im while using im2 bounds) --lib/help/tkmedit/truncparms: new helpfile, add to mk0 --tkmedit.tcl: new helpfile for TRUNC,PF entries: truncparms --tkmedit.c: shift-left-click edits pix to gray_hilim if within white_{lo,hi}lim --lib/help/tkmedit/wmtrunc: update --tkmedit.c: crop_im_using_im2cols() now accepts im2 range (like replace cols) --tkmedit.c: replace_cols -> cp_im_to_im2_replacing_cols: (vs. inplace->blink) --tkmedit.tcl: 5th overload TRUNC button to replace col range with single color --tkmedit.c: replace_cols(): replace editable colrange using TRUNC, PF entries --tkstrip.c: do_one -> do_all_glx_events, add to shrink for live rotate --tkstrip.c: double click raises GLwin, make -insurf option work --tkmedit.tcl: SAVEIMG (orig img name) warns when new img set read in over orig --tkmedit.tcl: ctrl-mid-TRUNC cp im->im2 repl $white_lolim-hilim w/$gray_hilim --tkmedit.c: crop_im_using_im2col(): crop col set by $white_lolim --lib/help/tkmedit/{compare,bwslope,test1,all}: updates --tkmedit.tcl: R-clk "PieceWiseLinNorm" F3 panel ctrls constrast{nochange,slope} --tkmedit.c: export contrastnochange,constrastslope for piecewise lin ramp hack --tkmedit.c: hack norm_allslices_to_imnum to add centerable lin contrast ramp --tkmedit.tcl: middle-click "contr:" label toggles linearflag --tkmedit.tcl: overload COMPARE button w/visible_to_im (contr-adj'd to editable) --tkmedit.c: visible_to_im(): cp contrast-adjusted editable image to editable [tmprelease 231002] --wheel Makefile: rm -lGLU --wheel.c: 03c: rewrite drawscale plain GL to avoid glu.h/-lGLU/gluPartialDisk --tksurfer Makefile: rm -lGLU --tksurfer.c: rewrite draw_colscaledisk plainGL avoid glu.h/-lGLU/gluPartialDisk --lib/help/tksurfer/label_read: update --tksurfer.tcl: add tenth label "D" overload: ctrl-mid-clk-D: labelcol_to_vtxcol --tksurfer.tcl: fix R-clk "D" popup text: CalcOverlap ->ctrl-shift-mid-clk => R! ########################################################################## UPDATE: 25 Sep 2023 ########################################################################## --tksurfer.c: calc_area_per_brainregion zeros brainregions before area sums --lib/help/tksurfer/{label,label_read}: update --tksurfer.c: print_annot_to_log_ctab also prints $ctabfname.area w/area append --tksurfer.tcl: count_mgh_annot_neigh2stat->areaneigh2stat,fix R-clk "D" menubar --tksurfer.c: read_{mgh,gifti,poi,obj}_annot now always count_mgh_annot_neigh --tksurfer.c: count_mgh_annot_neigh2stat -> count_mgh_annot_neigh+areaneigh2stat --tksurfer.c: fix read_gifti_to_annot off-by-1 bug (extra junk entry in ctab) --tksurfer.c: use print_annot_to_log_ctab() for read_gifti_to_annot --tksurfer.c: count_vtxs_per_brainregion: ignore alpha at compare annot,mghannot --tksurfer.c: rename: read_poi_annot -> read_poi_to_annot --tksurfer.c: hack fix 0vtx cnt by set_annot_alpha *after* count (fixed above) --tksurferc: functify print_annot_to_log_ctab() for read_mgh_annot --tksurfer.c: read_mgh_annot:print_annot_to_log_ctab writes areas to csurf log --tksurfer.tcl: fix "D" read-1-label popup: borders (new def), incl area, help --tksurfer.c: double-mid click also prints brainregion area --tksurfer.c: fix read_{gifti,poi,obj}_to_annot() as below --tksurfer.c: read_mgh_annot() uses 2 functs below --tksurfer.c: functify: count_vtxs_per_brainregion, calc_area_per_brainregion --tksurfer.c: read_label_to_annot_using_col() updates filled_{origarea,currarea} ...