// 06/12/2022 // K. Terretaz // C. Leterrier var first_click = 1; var tolerance = 0; var box_size = 20; var add_to_manager = 1; var tolerance_threshold = 30; var prominence = 500; var roi_factor = 1; var def_size = 4; /* Reminder for getCursorLoc Flags : * shift = +1 * ctrl = +2 * cmd = +4 (Mac) * alt = +8 * middle click is just 8 * leftClick = +16 * cursor over selection = +32 * So e.g. if (leftclick + alt) Flags = 24 */ macro "Synapse Tool - N55CbbbCaaaDc0Dc1Dd0Dd1De0De1CaaaDa0Db0CaaaD90Db1Dc2Dd2De2CaaaDa1De3CaaaD80Db2Dd3C999D70D91Da2Dc3C999D60Db3Dd4De4C999Dc4C999D0eD81C888D50C888D1eD71D92Da3Dd5De5C888Dc5C888D40C888Db4C777D61C777D07D0dD2eD51C777D08D30C777D04D05D06D82C777D15Db5C666D09D17D93De6C666D16D41Da4Dc6C666Dd6C666D57C666D14D18D1dD26D31C666D03D0aD27D3eD52D58C555D20D21D42D67Db6C555D25D36D68D6eC555D00D0bD46D47D4eD5eC555D0cC555D01D10D11D32D37C444D13D22D48D69D77D78D7eDebC444D02D12D72C444D19D56D62C444DecC444D28D43Da5Dc7DedDeeC444DeaC333D24D79D94Db7C333D2dD6aD7aDdbC333D23D53D59C333D33D38C333Da6C333D66DdaC222D1cD35C222D76Db8DdcC222D45D7bD86D95Db9C222Da8C222C111Da9C111D83C111D29D88Da7C111D87D8eC111D34D55D96DddC111D44D7dDc8Dc9C000DcaC000D49C000D1aD54C000D39C000D85DdeC000D98C000D89C000D6dD7cC000D1bD3dDd7C100D5aC100D63D97D99C100D8bC101D8aC201D6bDd9C201DbaDe7C201DcbC301D3aD84C301D65C301DaaDe9C301D8dC302D2aD2cD73C302D4dC402D5dD9eC402D4aC402D8cC402D75D9aC402DccC402C502C512C612C613DcdC613D6cC613C713D64C713DceC713C813Dd8C813DaeC823D2bC923Ca32D9bD9dCa32De8Ca32D74Ca32Cb32Cb42D3bCb41D9cDbeCb41Cc51D3cCc51Cc61D5bCc61Cd61Cd71DbbCd71DadCd71Cd81DbdCd81Cd91DabCd91Ce91Ce92D4bCea2D5cCea2Cea3Ceb3Ceb4DbcCeb4Cec4DacCec5Cec6D4cCec6Ced7Cfd7Cfd8Cfd9Cfe9CfeaCfebCfecCffdCffeCfffBf0CbbbD60Da0CbbbD30D40D41D50D51D52D61D62D70D71D73D80D81D90D91D92D93Da1Da2Da3Da4Da5CaaaD00D10D11D12D20D21D31D42D53D63D72D82D83D84D85D94D95Da6CaaaD01D22D32D33D43D54D64D65D74D75D86D96D97Da7CaaaD02D23D34D44D55D66D76D87D98Da8CaaaD03D13D24D45D56D77Da9CaaaD67D88D99CaaaD14D35D46C999DaaC999D04D78C999D25D36D57D89C999D9aC999D05D15D47D68C888D26DabC888D37D79C888D58D8aD9bC888D48C777D16C777D06D27D69C777D38DacC777D8bC777D39C666D28D49C666D17D9cDadC666D59D7aC666D1aD1bD1cD29D2aD2bC666D3aC555D0cD1dDaeC555D0bD0dD0eD6aC555D19D3bC555D0aD2cD4aC555D18D1eD4bD5aC444D2dD3cD7bC444D4cD8cC444D5bC444D3dD6bC444C333D9dC333D07D2eC333D4dC333D3eC222D5cD9eC222D09C222D7cC222C111D5dC111D4eD6cC111C000D08C000D5eD6dC000D8dC000C100D7dC100C101C201D8eC301D6eC301C302C402D7eC502C512C612C613C713C813C823C923Ca32Cb32Cb42Cb41Cc51Cc61Cd61Cd71Cd81Cd91Ce91Ce92Cea2Cea3Ceb3Ceb4Cec4Cec5Cec6Ced7Cfd7Cfd8Cfd9Cfe9CfeaCfebCfecCffdCffeCfffB0fCbbbCaaaC999D0aC999D09C999D1aC999D2aC999D08D19D3aC888D07D18D29D4aC888D17C888D39C888D06D28C777D16D49D5aC777D05D15Da6C777D96C777D38Da7C777D27C777D48C666D14D65D75D97Da5C666D04D25D26D35D36D37D47D59D95C666D24D85D86C666D34D55D57C666D13D56D58D64D6aC555D46D54D66D74C555D45D76C555D84D87Da8C555D23D44C555D94C444D00D10Da0Da4C444D12D33C444D98C444D43C333D11D53C333D03C333D67D7aC333D22C333D63Da9C222D8aC222D20C222D88C111D77C111D21Da3C111D90C111D01C111D73C111D99C000D83D89C000DaaC000Da1C000D02D32C000D69D93C000D30C000C100C101D9aC201D68C201D52Da2C201C301D31D42C301C302D91C402D62C402D79C402C502C512C612C613D78C613C713D92C713D80C713D40C713C813D82C813C823C923Ca32D72Ca32Cb32D50Cb42D41Cb42D60Cb41Cc51D51Cc51Cc61Cd61D61Cd61Cd71D81Cd71D70Cd71Cd81Cd91Ce91Ce92Cea2Cea3Ceb3Ceb4Cec4Cec5Cec6Ced7Cfd7Cfd8D71Cfd8Cfd9Cfe9CfeaCfebCfecCffdCffeCfffNf0CbbbD0aD18D19D1aD28D29D2aD3aCbbbD06D07D08D09D15D16D17D25D27D37D38D39D48D49D4aD58D59D5aD69D6aD78D79D7aD89D9aCaaaD03D04D05D14D26D34D35D36D46D47D55D56D57D67D68D77D88D8aD99Da9DaaCaaaD13D23D24D33D43D44D45D54D65D66D75D76D86D87D97D98Da7Da8Db8Db9DbaDcaCaaaD02D22D63D64D85D96Da6Dc9DdaCaaaD12D32D42D53D74D95Db7Dc8Dd9CaaaD01D11D21D52D73D84Db6Dd8DeaCaaaD31D62Da5Dc7De9C999D00D41D72D83D94C999D10D51Dc6Dd7De8C999D61Da4Db5Dd6C999D20De7C999D82D93Dc5C888D50C888D30D40D71De6C888Dd5C888D60Db4C888D92De5C777D81C777Da3C777D70C777C666D91C666Dc4C666Da2C666C555De4C555D80Dd4C555Db3C444Da1C444C333D90C333C222De0C222C111C000Db2C000Da0C000Db1C000C100C101C201Dd0C201Dc3C201C301C302C402De3C402Db0C502Dc0C502C512C612C613C713C813C823De1C823C923Dd3C923Ca32Dc1Ca32Cb32Cb42Cb41Cc51Cc61Cd61Cd71Dd1Cd71Dc2Cd71Cd81De2Cd81Cd91Ce91Ce92Cea2Cea3Ceb3Ceb4Cec4Cec5Cec6Ced7Cfd7Cfd8Cfd9Cfe9CfeaCfebCfecCffdCffeCfffDd2"{ getCursorLoc(x, y, z, flags); run("ROI Manager..."); roiManager("show all without labels"); last_x = x; while(true){ if (flags>=32) flags -= 32; //remove "cursor in selection" flag if (flags == 8) { //mouse wheel click Overlay.remove; run("Select None"); first_click = 1; exit(); } else if (flags == 16) { //left click magicWand(); if (add_to_manager) { roiManager("Add"); } } else if (x != last_x) { // no click Overlay.remove; makeRectangle(x-(box_size/2),y-(box_size/2),box_size,box_size); Overlay.addSelection("magenta"); tolerance = estimateTolerance(); Roi.getBounds(wand_x, wand_y, width, height); makePoint(wand_x, wand_y, "small magenta cross add"); doWand(wand_x, wand_y, tolerance, "Legacy"); getRawStatistics(wand_area); if (wand_area > box_size * box_size) { makeOval(wand_x-def_size/2, wand_y-def_size/2, def_size, def_size); } } last_x = x; wait(30); getCursorLoc(x, y, z, flags); if (first_click) { first_click = 0; run("cancel Add To Manager [z]"); } } } macro "Synapse Tool Options"{ Dialog.createNonBlocking("Interactive magic wand tool"); Dialog.addNumber("Maxima window size", box_size); Dialog.addSlider("tolerance estimation threshold", 0, 100, tolerance_threshold); Dialog.addSlider("Maxima prominence", 0, 2000, prominence); Dialog.addNumber("Max ROI size in multiples of box size (0 for none)", roi_factor); Dialog.addNumber("Default ROI diameter in pixels", def_size); Dialog.addCheckbox("auto add ROI?", add_to_manager); Dialog.show(); box_size = Dialog.getNumber(); tolerance_threshold = Dialog.getNumber(); prominence = Dialog.getNumber(); roi_factor = Dialog.getNumber(); def_size = Dialog.getNumber(); add_to_manager = Dialog.getCheckbox(); } macro "cancel Add To Manager [z]"{ roiManager("Select", roiManager("count")-1); roiManager("delete"); } function magicWand() { getCursorLoc(x2, y2, z2, flags2); //origin getCursorLoc(x, y, z, flags); if (flags>=32) flags -= 32; //remove "cursor in selection" flag zoom = getZoom(); tolerance = estimateTolerance(); Roi.getBounds(wand_x, wand_y, width, height); while (flags >= 16) { getCursorLoc(x, y, z, flags); if (flags>=32) flags -= 32; //remove "cursor in selection" flag distance = (x*zoom - x2*zoom); if (distance < 0) newTolerance = tolerance - pow(abs(distance), 2); else newTolerance = tolerance + pow(abs(distance), 2); showStatus(newTolerance); doWand(wand_x, wand_y, newTolerance, "Legacy"); getRawStatistics(wand_area); if (wand_area > box_size * box_size * roi_factor && roi_factor > 0) { makeOval(wand_x-def_size/2, wand_y-def_size/2, def_size, def_size); } wait(30); } } function estimateTolerance(){ run("Select None"); setBatchMode(1); getCursorLoc(x, y, z, flags); makeRectangle(x-(box_size/2),y-(box_size/2),box_size,box_size); power = 1; factor = pow(1-tolerance_threshold/100, power); // power dispensable I think //change next lines to use Find Maxima or j.Mutterer's gaussian fit for point detection run("Find Maxima...", "prominence=" + prominence + " output=[Point Selection]"); if (Roi.getType() == "rectangle") { // catch the no maximum detected case and put cursor at center makePoint(x, y); } else { // selects only the brightest maxima if several detected Roi.getCoordinates(xpoints, ypoints); seed_x = xpoints[0]; seed_y = ypoints[0]; point_i0 = getPixel(xpoints[0], ypoints[0]); for (c = 0; c < xpoints.length; c++) { point_i = getPixel(xpoints[c], ypoints[c]); if (point_i > point_i0) { seed_x = xpoints[c]; seed_y = ypoints[c]; } } makePoint(seed_x, seed_y); } // makePoint(x-(box_size/2) + gaussianFit(true), y-(box_size/2) + gaussianFit(false), "large orange circle"); getStatistics(maxArea, maxMean); tolerance = factor * maxMean; // tolerance as a % of max value return tolerance; } function gaussianFit(horizontal) { if (!horizontal) setKeyDown("alt"); k = getProfile(); setKeyDown("none"); Fit.doFit("Gaussian", Array.getSequence(k.length), k); return Fit.p(2); }