--[[ DoD Union Finder DoDUnionFinder_CTModifier.Fuse Designed to be a modifier for SetDomain in Set mode, it samples the Wireless Link image over time to find the extents of the DataWindow. Useful for preparing a DoD for temporal sampling. There are 4 outputs, one for each of the sliders. Apply the modifier to the Left slider, then just connect the other sliders to the appropriate inputs. The range slider sets the sample range. Samples are taken according to the Sample Rate slider. Higher rate is more accurate, but slower. The Pad slider adds pixels to the DoD, 1 unit is one pixel of the Image Input (not the SetDomain's Input image) Tip 1: The Image Input does not have to be the same size and the SetDomain Input image. If you set the Range Start and Range End to be the current time, you will be able to copy the DoD from a different sized image. Tip 2: You can "Remove" the modifer from the SetDomain sliders to lock the result in place. This prevents the SetDomain tool from needing to sample the DoDUnionFinder Image Input. This fuse uses a wireless link to attach the image input. The wireless link, however loses it's input when duplicated. Not much I can do about that, the only workaround I can come up with is to copy/paste INSTANCE and then de-instance. There may be some error messages in the console along the lines of "DoDUnionFinder1 cannot get DoD for Image Input at time 146". These are typical errors related to DoD seen at least in Fusion 6 build 511. Feel free to report any other errors to me, though. --]] version = "version 1.0 (Apr 1, 2010)" --[[ Written by Chad Capeland (ccapeland[REMOVE-ME]@anatomicaltravel.com) Copyright (c) 2010 Anatomical Travelogue LLC (http://www.anatomicaltravel.com/research) The authors hereby grant permission to use, copy, and distribute this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. Additionally, the authors grant permission to modify this software and its documentation for any purpose, provided that such modifications are not distributed without the explicit consent of the authors and that existing copyright notices are retained in all copies. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. --]] FuRegisterClass("DoDUnionFinder", CT_Modifier, { REGS_Category = "ATI", REGS_OpIconString = "fDunM", REGS_OpDescription = "DoD Union Finder Modifier", REGID_DataType = "Number", REGID_InputDataType = "Number", REG_Fuse_NoEdit = true, REG_Fuse_NoReload = true, REGS_HelpTopic = "http://www.anatomicaltravel.com/research", REG_SupportsDoD = true, }) function Create() InLabel = self:AddInput(version, "version", { LINKID_DataType = "Text", INPID_InputControl = "LabelControl", INP_External = false, INP_Passive = true, }) InImage = self:AddInput("Image Input", "ImageInput", { LINKID_DataType = "Image", INPID_InputControl = "ImageControl", LINK_Main = 1, }) InRangeS = self:AddInput("Range Start", "RangeStart", { LINKID_DataType = "Number", INPID_InputControl = "RangeControl", INP_Default = 0, INP_Integer = true, IC_ControlGroup = 1, IC_ControlID = 0, IC_Visible = true, }) InRangeE = self:AddInput("Range End", "RangeEnd", { LINKID_DataType = "Number", INPID_InputControl = "RangeControl", INP_Default = 100, INP_Integer = true, IC_ControlGroup = 1, IC_ControlID = 1, }) InRate = self:AddInput("Sample Rate (per frame)", "SampleRate", { LINKID_DataType = "Number", INPID_InputControl = "SliderControl", INP_Default = 1, INP_MaxScale = 10, INP_MinAllowed = .01 }) InInflate = self:AddInput("Pad", "Pad", { LINKID_DataType = "Number", INPID_InputControl = "SliderControl", INP_Default = 0, INP_Integer = true, INP_MaxScale = 10, }) OutL = self:AddOutput("Left", "Left", { LINKID_DataType = "Number", LINK_Main = 1, }) OutB = self:AddOutput("Bottom", "Bottom", { LINKID_DataType = "Number", LINK_Main = 2, }) OutR = self:AddOutput("Right", "Right", { LINKID_DataType = "Number", LINK_Main = 3, }) OutT = self:AddOutput("Top", "Top", { LINKID_DataType = "Number", LINK_Main = 4, }) end function Process(req) local img = InImage:GetValue(req) local rs = InRangeS:GetValue(req).Value local re = InRangeE:GetValue(req).Value local pad = InInflate:GetValue(req).Value local rate = InRate:GetValue(req).Value if rate < 1 then rate = (1/(math.floor(1/rate))) end if re ~= rs then -- Using the range slider sofar1 = 1000000 sofar2 = 1000000 sofar3 = -1000000 sofar4 = -1000000 for i = rs, re, 1/rate do if self.Status ~= "OK" then break end sam = InImage:GetSource(i, REQF_SecondaryTime) if sam then if sam.DataWindow[1] < sofar1 then sofar1 = sam.DataWindow[1] end if sam.DataWindow[2] < sofar2 then sofar2 = sam.DataWindow[2] end if sam.DataWindow[3] > sofar3 then sofar3 = sam.DataWindow[3] end if sam.DataWindow[4] > sofar4 then sofar4 = sam.DataWindow[4] end else print("Couldn't get DoD at frame "..i) end end else -- Getting instantaneous DataWindow (useful when comparing images of 2 different sizes, something SetDomain does not do. Also lets you use the "set" mode and read in the DoD, instead of resetting to {0,0,1,1}.) sam = InImage:GetSource(re, REQF_SecondaryTime) sofar1 = sam.DataWindow[1] sofar2 = sam.DataWindow[2] sofar3 = sam.DataWindow[3] sofar4 = sam.DataWindow[4] end OutL:Set(req, (sofar1-pad)/img.Width) OutB:Set(req, (sofar2-pad)/img.Height) OutR:Set(req, (sofar3+pad)/img.Width) OutT:Set(req, (sofar4+pad)/img.Height) end