In light of the Coronavirus crisis, please help make sure nothing stands in the way of social distancing in the VFX industry.

This petition asks the MPAA to act accordingly:


Sign the petition on Change.org

Be safe, everyone.

need debug help with my sorting fuse

User avatar
pingking
Fusionista
Posts: 744
Joined: Thu Aug 14, 2014 9:10 am

need debug help with my sorting fuse

#1

Post by pingking » Sun Sep 02, 2018 8:19 am

hi,

i am building on a new fuse and i got very far but as life is there is always something not working.

in my actual fuse i do the sorting different and its fast and reliable. but i need to sort each channel on its own. which doenst allow me to try different sorting parameters

now i build this quick test fuse to see if i can sort each channels at once. this works for very small images but as soon as i use a large image it crashes fusion without any error.
on my machine it work fine with images about 60x60 pixel but above that it crashes

can anybody take a look and give me a hint what might be the problem?

Code: [Select all] [Expand/Collapse] [Download] (pixelsort_test.Fuse)
  1. --[[--
  2. pixelsort_test.Fuse
  3.  
  4. A simplyfied version of my pixelsort fuse
  5.  
  6. version 2.0
  7.  
  8. --]]--
  9.  
  10. FuRegisterClass("PixelSort22", CT_Tool, {
  11.     REGS_Category = "Fuses",
  12.     REGS_OpIconString = "PixS22",
  13.     REGS_OpDescription = "PixelSorter22 Fuse",
  14.  
  15.     })
  16.  
  17.  
  18. function Create()
  19.     InImage = self:AddInput("Input", "Input", {
  20.         LINKID_DataType = "Image",
  21.         LINK_Main = 1,
  22.     })
  23.  
  24.     OutImage = self:AddOutput("Output", "Output", {
  25.         LINKID_DataType = "Image",
  26.         LINK_Main = 1,
  27.         })
  28.  
  29. end
  30.  
  31. --in-place quicksort
  32. function quicksort(t, start, endi)
  33.     start, endi = start or 1, endi or #t
  34.     if(endi - start < 1) then return t end
  35.     local pivot = start
  36.     for i = start + 1, endi do
  37.         if t[i]["R"] <= t[pivot]["R"] then
  38.             if i == pivot + 1 then
  39.                 t[pivot],t[pivot+1] = t[pivot+1],t[pivot]
  40.             else
  41.                 t[pivot],t[pivot+1],t[i] = t[i],t[pivot],t[pivot+1]
  42.             end
  43.             pivot = pivot + 1
  44.         end
  45.     end
  46.     t = quicksort(t, start, pivot - 1)
  47.     return quicksort(t, pivot + 1, endi)
  48. end
  49.  
  50.  
  51.  
  52. function Process(req)
  53.     self:SetProgress(0.0)
  54.     local img = InImage:GetValue(req)
  55.    
  56.     local out = img:Copy()
  57.     local temp = img:Copy()
  58.    
  59.     local p = Pixel({A=1})
  60.    
  61.     local pixelArray = {}
  62.    
  63.     local pix = {}
  64.    
  65.  
  66.         for y=0, img.Height-1 do
  67.             if self.Status ~= "OK" then break end
  68.             -- getting all pixels of a row in a array
  69.             for x=0,img.Width-1 do
  70.                 img:GetPixel(x,y,p)
  71.                 pix = {R = p.R, G = p.G , B = p.B}
  72.                
  73.                 pixelArray[x] = pix
  74.             end
  75.             --sorting the pixels
  76.             for bx = 0, img.Width-1 do
  77.                 pixelArray = quicksort(pixelArray, 0, img.Width-1)
  78.             end
  79.             -- building the output image
  80.             for bx=0, img.Width-1 do
  81.                 img:GetPixel(bx,y,p)
  82.                 p.R = pixelArray[bx]["R"]
  83.                 p.G = pixelArray[bx]["G"]
  84.                 p.B = pixelArray[bx]["B"]
  85.                 out:SetPixel(bx,y, p)
  86.             end
  87.             self:SetProgress(y/img.Height)
  88.         end
  89.     OutImage:Set(req, out)
  90. end

Tags:

User avatar
SecondMan
Site Admin
Posts: 4229
Joined: Thu Jul 31, 2014 5:31 pm
Answers: 15
Location: Vancouver, Canada
Been thanked: 58 times
Contact:

Re: need debug help with my sorting fuse

#2

Post by SecondMan » Sun Sep 02, 2018 11:23 am

My guess would be that you are storing all the pixels in a table "manually" which seems an inefficient way of doing this. So you may already be using a table containing 14400 entries for RGBA with your 60x60 image. Not that that should crash Fusion, but I bet there are better ways to do this in Fusion.

I'm on my phone and on holidays so I can't really dive into this properly, but perhaps check out MultiProcessPixels() instead? A search should get you some results from the forum. Bryan has been playing with it as well I seem to remember.

Added in 13 minutes 36 seconds:
Actually, is this a continuation of your start here? Mind if I merge the topics?

User avatar
pingking
Fusionista
Posts: 744
Joined: Thu Aug 14, 2014 9:10 am

Re: need debug help with my sorting fuse

#3

Post by pingking » Sun Sep 02, 2018 12:04 pm

i use the same sorting algorithm and structure of the fuse in my prototype. there i sort the pixels 3x (each for the red, green and blue channel)
this works (relative) fast and without problems with the resolution. ( i test id with a UHD image and i took about 30sec. to sort)


of course could be the processing made faster, but first i would like to make it work with more then 1 channel at a time.
(if i wrote my code correct it will only store one line of the image, sort that, then goes on to the next line)

User avatar
Midgardsormr
Fusionator
Posts: 1601
Joined: Wed Nov 26, 2014 8:04 pm
Answers: 11
Location: Los Angeles, CA, USA
Been thanked: 51 times
Contact:

Re: need debug help with my sorting fuse

#4

Post by Midgardsormr » Sun Sep 02, 2018 4:47 pm

SecondMan wrote:
Sun Sep 02, 2018 11:36 am
Bryan has been playing with it as well I seem to remember.

Reading the pixels into a linear array could be problematic with MPP since multiple threads could try to insert data into the same index.

I've had similar problems with a histogram equalizer fuse I was trying to write. It works great up to a certain size, and then it really bogs down. I've had other things to think about since I started that one, though, so I haven't taken the time to try to make it any better.

User avatar
pingking
Fusionista
Posts: 744
Joined: Thu Aug 14, 2014 9:10 am

Re: need debug help with my sorting fuse

#5

Post by pingking » Thu Sep 06, 2018 12:31 pm

instead of using
local out = img:Copy()

i use now:
local out = img:CopyOf()

and everything seems to be more stable

User avatar
pingking
Fusionista
Posts: 744
Joined: Thu Aug 14, 2014 9:10 am

Re: need debug help with my sorting fuse

#6

Post by pingking » Mon Sep 10, 2018 3:58 pm

coming from here: viewtopic.php?f=6&t=1184#p19236

i prepared a little demo fuse which shows the speed difference between sorting (float) numbers and tables (with floats)

i invite you to play with it and maybe find something to speed up the table method
Code: [Select all] [Expand/Collapse] [Download] (PixelSort_test.Fuse)
  1. --[[--
  2. PixelSort_test.Fuse
  3.  
  4. A Fuse to create pixel sorting image effects
  5.  
  6. version 2.0
  7. September 11th, 2018
  8.  
  9.  
  10. --]]--
  11.  
  12. FuRegisterClass("PixelSort_test2", CT_Tool, {
  13.     REGS_Category = "Fuses",
  14.     REGS_OpIconString = "PixST2",
  15.     REGS_OpDescription = "PixelSortTest_2 Fuse",
  16.     REG_NoMotionBlurCtrls = true,
  17.     REG_NoObjMatCtrls = true,
  18.     REG_Fuse_NoEdit = true,
  19.     --REG_Fuse_NoReload = true,
  20.     --REG_NoBlendCtrls = true,
  21.  
  22.     })
  23.  
  24.  
  25. function Create()
  26.     InThreshold = self:AddInput("Threshold", "Threshold", {
  27.         LINKID_DataType = "Number",
  28.         INPID_InputControl = "SliderControl",
  29.         INP_MaxScale = 1.0,
  30.         INP_Default = 0.0,
  31.         ICD_Center = 1,
  32.         })
  33.     InMaxlength = self:AddInput("max. length", "Maxlength", {
  34.         LINKID_DataType = "Number",
  35.         INPID_InputControl = "SliderControl",
  36.         INP_MaxScale = 200,
  37.         INP_Default = 0,
  38.         INP_Integer = true,
  39.         --ICD_Center = 1,
  40.         })
  41.     InMethod = self:AddInput("method", "method", {
  42.         LINKID_DataType = "Number",
  43.         INPID_InputControl = "MultiButtonControl",
  44.         INP_Default = 0.0,
  45.         {MBTNC_AddButton = "numbers",   MBTNCD_ButtonWidth = 0.5, },
  46.         {MBTNC_AddButton = "table",     MBTNCD_ButtonWidth = 0.5, },
  47.         })
  48.     InImage = self:AddInput("Input", "Input", {
  49.         LINKID_DataType = "Image",
  50.         LINK_Main = 1,
  51.     })
  52.     OutImage = self:AddOutput("Output", "Output", {
  53.         LINKID_DataType = "Image",
  54.         LINK_Main = 1,
  55.         })
  56. end
  57.  
  58.  
  59. --in-place quicksort
  60. function quicksort(t, start, endi, threshold, maxiter)
  61.     start, endi = start or 1, endi or #t
  62.     if(endi - start < 1) then return t end
  63.     local pivot = start
  64.     local maxiter = maxiter or endi
  65.     local nn = 0
  66.     for i = start + 1, endi do
  67.     if nn > maxiter then break end
  68.         nn = nn + 1
  69.         if math.abs(t[i]["Lum"]) >= threshold then
  70.             if t[i]["Lum"] <= t[pivot]["Lum"] then
  71.                 if i == pivot + 1 then
  72.                     t[pivot],t[pivot+1] = t[pivot+1],t[pivot]
  73.                 else
  74.                      t[pivot],t[pivot+1],t[i] = t[i],t[pivot],t[pivot+1]
  75.                 end
  76.                 pivot = pivot + 1
  77.                
  78.             end
  79.         end
  80.   end
  81.   t = quicksort(t, start, pivot - 1, threshold, maxiter)
  82.   return quicksort(t, pivot + 1, endi, threshold, maxiter)
  83. end
  84.  
  85. function quicksort2(t, start, endi, threshold, maxiter)
  86.     start, endi = start or 1, endi or #t
  87.     threshold = threshold or 0
  88.     if(endi - start < 1) then return t end
  89.     local pivot = start
  90.     local maxiter = maxiter or endi
  91.     local nn = 0
  92.    
  93.     for i = start + 1, endi do
  94.         if nn > maxiter then break end
  95.         nn = nn + 1
  96.         if t[i] >= threshold then
  97.             if t[i] <= t[pivot] then
  98.                 if i == pivot + 1 then
  99.                     t[pivot],t[pivot+1] = t[pivot+1],t[pivot]
  100.                 else
  101.                      t[pivot],t[pivot+1],t[i] = t[i],t[pivot],t[pivot+1]
  102.                 end
  103.                 pivot = pivot + 1
  104.             end
  105.         end
  106.     end
  107.     t = quicksort2(t, start, pivot - 1, threshold, maxiter)
  108.     return quicksort2(t, pivot + 1, endi, threshold, maxiter)
  109. end
  110.  
  111.  
  112.  
  113. function Process(req)
  114.     self:SetProgress(0.0)
  115.     local img = InImage:GetValue(req)
  116.     local threshold = InThreshold:GetValue(req).Value
  117.     local sort_method = InMethod:GetValue(req).Value
  118.     local maxiter = InMaxlength:GetValue(req).Value
  119.     if maxiter == 0 then maxiter = img.Height-1 end
  120.    
  121.    
  122.     local out = img:CopyOf()
  123.    
  124.     local p = Pixel({A=1})
  125.    
  126.     local pixelArray = {}
  127.     local pixelArrayR = {}
  128.     local pixelArrayG = {}
  129.     local pixelArrayB = {}
  130.     local pixelArrayA = {}
  131.    
  132.     local px = {}
  133.    
  134.     local n = 0
  135.    
  136.     if sort_method == 1 then
  137.         for y=0,img.Height-1 do
  138.             if self.Status ~= "OK" then break end
  139.             -- getting all pixels of a row in a array
  140.             for x=0,img.Width-1 do
  141.                 px = {R = nil, G = nil , B = nil}
  142.                 img:GetPixel(x,y,p)
  143.                 Lum = (p.R*.2126)+(p.G*.7152)+(p.B*.0722)
  144.                 px = {R = p.R, G = p.G , B = p.B, A = p.A, Lum = Lum}
  145.                 pixelArray[x] = px
  146.                
  147.             end
  148.             --sorting the pixels in the lines
  149.                 pixelArray = quicksort(pixelArray, 0, img.Width-1, threshold, maxiter)
  150.            
  151.             --building the image from the sorted pixels
  152.             for bx=0, img.Width-1 do
  153.                 local out_px = Pixel({ R = 1.0, G = 0.0, B = 0.0 })
  154.                 out_px.R = pixelArray[bx]["R"]
  155.                 out_px.G = pixelArray[bx]["G"]
  156.                 out_px.B = pixelArray[bx]["B"]
  157.                 out_px.A = pixelArray[bx]["A"]
  158.                 out:SetPixel(bx,y, out_px)
  159.             end
  160.             self:SetProgress(y/img.Height)
  161.         end
  162.     else
  163.         for y=0,img.Height-1 do
  164.             if self.Status ~= "OK" then break end
  165.             -- getting all pixels of a row in a array
  166.             for x=0,img.Width-1 do
  167.                 --p = {R = nil, G = nil , B = nil}
  168.                 img:GetPixel(x,y,p)
  169.                 pixelArrayR[x] = p.R
  170.                 pixelArrayG[x] = p.G
  171.                 pixelArrayB[x] = p.B
  172.                 -- pixelArrayA[x] = p.A
  173.                
  174.             end
  175.            
  176.             --sorting the pixels in the lines
  177.                 pixelArrayR = quicksort2(pixelArrayR, 0, img.Width-1, threshold, maxiter)
  178.                 pixelArrayG = quicksort2(pixelArrayG, 0, img.Width-1, threshold, maxiter)
  179.                 pixelArrayB = quicksort2(pixelArrayB, 0, img.Width-1, threshold, maxiter)
  180.                 -- pixelArrayA = quicksort2(pixelArrayA, 0, img.Width-1, threshold, maxiter)
  181.             --end
  182.             --building the image from the sorted pixels
  183.             for bx=0, img.Width-1 do
  184.                 img:GetPixel(bx,y,p)
  185.                 p.R = pixelArrayR[bx]
  186.                 p.G = pixelArrayG[bx]
  187.                 p.B = pixelArrayB[bx]
  188.                 -- p.A = pixelArrayA[bx]
  189.                
  190.                 out:SetPixel(bx,y, p)
  191.             end
  192.             self:SetProgress(y/img.Height)
  193.         end
  194.     end
  195.    
  196.    
  197.     OutImage:Set(req, out)
  198. end
  199.  

User avatar
tberakis
Posts: 31
Joined: Mon Dec 29, 2014 2:30 pm
Been thanked: 1 time

Re: need debug help with my sorting fuse

#7

Post by tberakis » Mon Sep 10, 2018 7:16 pm

Well, there are probably a few other improvements that can be made, but the big one is to not allocate a Pixel object every pixel. Note in the table case you create 'out_px' within the loops. Either move it out to the same scope as where 'p' is created, or just use 'p'.

Added in 28 minutes 4 seconds:
I've added another method that you could try. As well as being a bit faster, this has the advantage of actually getting the real source pixels, which means any aux channels (Z, etc) will be sorted properly too.

It still isn't as quick as would be nice, though.

Added in 22 minutes 51 seconds:
Making it multithreaded improves things a bit, too.
Code: [Select all] [Expand/Collapse] [Download] (PixelSort_test.Fuse)
  1. --[[--
  2. PixelSort_test.Fuse
  3.  
  4. A Fuse to create pixel sorting image effects
  5.  
  6. version 2.0
  7. September 11th, 2018
  8.  
  9.  
  10. --]]--
  11.  
  12. FuRegisterClass("PixelSort_test2", CT_Tool, {
  13.     REGS_Category = "Fuses",
  14.     REGS_OpIconString = "PixST2",
  15.     REGS_OpDescription = "PixelSortTest_2 Fuse",
  16.     REG_NoMotionBlurCtrls = true,
  17.     REG_NoObjMatCtrls = true,
  18.     REG_Fuse_NoEdit = true,
  19.     --REG_Fuse_NoReload = true,
  20.     --REG_NoBlendCtrls = true,
  21.  
  22.     })
  23.  
  24.  
  25. function Create()
  26.     InThreshold = self:AddInput("Threshold", "Threshold", {
  27.         LINKID_DataType = "Number",
  28.         INPID_InputControl = "SliderControl",
  29.         INP_MaxScale = 1.0,
  30.         INP_Default = 0.0,
  31.         ICD_Center = 1,
  32.         })
  33.     InMaxlength = self:AddInput("max. length", "Maxlength", {
  34.         LINKID_DataType = "Number",
  35.         INPID_InputControl = "SliderControl",
  36.         INP_MaxScale = 200,
  37.         INP_Default = 0,
  38.         INP_Integer = true,
  39.         --ICD_Center = 1,
  40.         })
  41.     InMethod = self:AddInput("method", "method", {
  42.         LINKID_DataType = "Number",
  43.         INPID_InputControl = "MultiButtonControl",
  44.         INP_Default = 0.0,
  45.         {MBTNC_AddButton = "numbers",   MBTNCD_ButtonWidth = 0.5, },
  46.         {MBTNC_AddButton = "table",     MBTNCD_ButtonWidth = 0.5, },
  47.         {MBTNC_AddButton = "index/value struct",    MBTNCD_ButtonWidth = 1.0, },
  48.         })
  49.     InImage = self:AddInput("Input", "Input", {
  50.         LINKID_DataType = "Image",
  51.         LINK_Main = 1,
  52.     })
  53.     OutImage = self:AddOutput("Output", "Output", {
  54.         LINKID_DataType = "Image",
  55.         LINK_Main = 1,
  56.         })
  57. end
  58.  
  59.  
  60. --in-place quicksort
  61. function quicksort(t, start, endi, threshold, maxiter)
  62.     start, endi = start or 1, endi or #t
  63.     if(endi - start < 1) then return t end
  64.     local pivot = start
  65.     local maxiter = maxiter or endi
  66.     local nn = 0
  67.     for i = start + 1, endi do
  68.     if nn > maxiter then break end
  69.         nn = nn + 1
  70.         if math.abs(t[i]["Lum"]) >= threshold then
  71.             if t[i]["Lum"] <= t[pivot]["Lum"] then
  72.                 if i == pivot + 1 then
  73.                     t[pivot],t[pivot+1] = t[pivot+1],t[pivot]
  74.                 else
  75.                      t[pivot],t[pivot+1],t[i] = t[i],t[pivot],t[pivot+1]
  76.                 end
  77.                 pivot = pivot + 1
  78.  
  79.             end
  80.         end
  81.   end
  82.   t = quicksort(t, start, pivot - 1, threshold, maxiter)
  83.   return quicksort(t, pivot + 1, endi, threshold, maxiter)
  84. end
  85.  
  86. function quicksort2(t, start, endi, threshold, maxiter)
  87.     start, endi = start or 1, endi or #t
  88.     threshold = threshold or 0
  89.     if(endi - start < 1) then return t end
  90.     local pivot = start
  91.     local maxiter = maxiter or endi
  92.     local nn = 0
  93.  
  94.     for i = start + 1, endi do
  95.         if nn > maxiter then break end
  96.         nn = nn + 1
  97.         if t[i] >= threshold then
  98.             if t[i] <= t[pivot] then
  99.                 if i == pivot + 1 then
  100.                     t[pivot],t[pivot+1] = t[pivot+1],t[pivot]
  101.                 else
  102.                      t[pivot],t[pivot+1],t[i] = t[i],t[pivot],t[pivot+1]
  103.                 end
  104.                 pivot = pivot + 1
  105.             end
  106.         end
  107.     end
  108.     t = quicksort2(t, start, pivot - 1, threshold, maxiter)
  109.     return quicksort2(t, pivot + 1, endi, threshold, maxiter)
  110. end
  111.  
  112.  
  113. function quicksort3(t, start, endi, threshold, maxiter)
  114.     start, endi = start or 1, endi or #t
  115.     if(endi - start < 1) then return t end
  116.     local pivot = start
  117.     local maxiter = maxiter or endi
  118.     local nn = 0
  119.     for i = start + 1, endi do
  120.     if nn > maxiter then break end
  121.         nn = nn + 1
  122.         if math.abs(t[i].Value) >= threshold then
  123.             if t[i].Value <= t[pivot].Value then
  124.                 if i == pivot + 1 then
  125.                     t[pivot].Index,t[pivot+1].Index = t[pivot+1].Index,t[pivot].Index
  126.                     t[pivot].Value,t[pivot+1].Value = t[pivot+1].Value,t[pivot].Value
  127.                 else
  128.                      t[pivot].Index,t[pivot+1].Index,t[i].Index = t[i].Index,t[pivot].Index,t[pivot+1].Index
  129.                      t[pivot].Value,t[pivot+1].Value,t[i].Value = t[i].Value,t[pivot].Value,t[pivot+1].Value
  130.                 end
  131.                 pivot = pivot + 1
  132.  
  133.             end
  134.         end
  135.   end
  136.   t = quicksort3(t, start, pivot - 1, threshold, maxiter)
  137.   return quicksort3(t, pivot + 1, endi, threshold, maxiter)
  138. end
  139.  
  140. function mp_init()
  141.     if not _G._HAS_PIXELSORTSTRUCT then
  142.         _G._HAS_PIXELSORTSTRUCT = true
  143.         ffi.cdef[[
  144.             struct pixelSortStruct
  145.             {
  146.                 int32 Index;
  147.                 float32 Value;
  148.             };
  149.         ]]
  150.     end
  151.  
  152.     pixelArray = ffi.new("struct pixelSortStruct[?]", img.Width)
  153.  
  154.     p = Pixel()
  155.     sp = PixPtr(img, p)
  156.     dp = PixPtr(out, p)
  157. end
  158.  
  159. function mp_func(y)
  160.     sp:GotoXY(0, y)
  161.     for x=0,img.Width-1 do
  162.         sp:GetNextPixel(p)
  163.         pixelArray[x].Index = x
  164.         pixelArray[x].Value = (p.R*.2126)+(p.G*.7152)+(p.B*.0722)
  165.     end
  166.     --sorting the pixels in the lines
  167.         pixelArray = quicksort3(pixelArray, 0, img.Width-1, threshold, maxiter)
  168.  
  169.     --building the image from the sorted pixels
  170.     dp:GotoXY(0, y)
  171.     for bx=0, img.Width-1 do
  172.         img:GetPixel(pixelArray[bx].Index,y, p)
  173.         dp:SetNextPixel(p)
  174.     end
  175. end
  176.  
  177.  
  178.  
  179. function Process(req)
  180.     self:SetProgress(0.0)
  181.     local img = InImage:GetValue(req)
  182.     local threshold = InThreshold:GetValue(req).Value
  183.     local sort_method = InMethod:GetValue(req).Value
  184.     local maxiter = InMaxlength:GetValue(req).Value
  185.     if maxiter == 0 then maxiter = img.Height-1 end
  186.  
  187.  
  188.     local out = img:CopyOf()
  189.  
  190.     local p = Pixel({A=1})
  191.     local out_px = Pixel({ R = 1.0, G = 0.0, B = 0.0 })
  192.  
  193.     local pixelArray = {}
  194.     local pixelArrayR = {}
  195.     local pixelArrayG = {}
  196.     local pixelArrayB = {}
  197.     local pixelArrayA = {}
  198.  
  199.     local px = {}
  200.  
  201.     local n = 0
  202.  
  203.     if sort_method == 2 then
  204.         self:DoMultiProcess(mp_init, {
  205.             img = img,
  206.             out = out,
  207.             maxiter = maxiter,
  208.             threshold = threshold,
  209.             quicksort3 = quicksort3,
  210.             }, out.Height, mp_func)
  211.     elseif sort_method == 1 then
  212.         for y=0,img.Height-1 do
  213.             if self.Status ~= "OK" then break end
  214.             -- getting all pixels of a row in a array
  215.             for x=0,img.Width-1 do
  216.                 px = {R = nil, G = nil , B = nil}
  217.                 img:GetPixel(x,y,p)
  218.                 Lum = (p.R*.2126)+(p.G*.7152)+(p.B*.0722)
  219.                 px = {R = p.R, G = p.G , B = p.B, A = p.A, Lum = Lum}
  220.                 pixelArray[x] = px
  221.  
  222.             end
  223.             --sorting the pixels in the lines
  224.                 pixelArray = quicksort(pixelArray, 0, img.Width-1, threshold, maxiter)
  225.  
  226.             --building the image from the sorted pixels
  227.             for bx=0, img.Width-1 do
  228.                 out_px.R = pixelArray[bx]["R"]
  229.                 out_px.G = pixelArray[bx]["G"]
  230.                 out_px.B = pixelArray[bx]["B"]
  231.                 out_px.A = pixelArray[bx]["A"]
  232.                 out:SetPixel(bx,y, out_px)
  233.             end
  234.             self:SetProgress(y/img.Height)
  235.         end
  236.     else
  237.         for y=0,img.Height-1 do
  238.             if self.Status ~= "OK" then break end
  239.             -- getting all pixels of a row in a array
  240.             for x=0,img.Width-1 do
  241.                 --p = {R = nil, G = nil , B = nil}
  242.                 img:GetPixel(x,y,p)
  243.                 pixelArrayR[x] = p.R
  244.                 pixelArrayG[x] = p.G
  245.                 pixelArrayB[x] = p.B
  246.                 -- pixelArrayA[x] = p.A
  247.  
  248.             end
  249.  
  250.             --sorting the pixels in the lines
  251.                 pixelArrayR = quicksort2(pixelArrayR, 0, img.Width-1, threshold, maxiter)
  252.                 pixelArrayG = quicksort2(pixelArrayG, 0, img.Width-1, threshold, maxiter)
  253.                 pixelArrayB = quicksort2(pixelArrayB, 0, img.Width-1, threshold, maxiter)
  254.                 -- pixelArrayA = quicksort2(pixelArrayA, 0, img.Width-1, threshold, maxiter)
  255.             --end
  256.             --building the image from the sorted pixels
  257.             for bx=0, img.Width-1 do
  258.                 img:GetPixel(bx,y,p)
  259.                 p.R = pixelArrayR[bx]
  260.                 p.G = pixelArrayG[bx]
  261.                 p.B = pixelArrayB[bx]
  262.                 -- p.A = pixelArrayA[bx]
  263.  
  264.                 out:SetPixel(bx,y, p)
  265.             end
  266.             self:SetProgress(y/img.Height)
  267.         end
  268.     end
  269.  
  270.  
  271.     OutImage:Set(req, out)
  272. end
  273.  

User avatar
pingking
Fusionista
Posts: 744
Joined: Thu Aug 14, 2014 9:10 am

Re: need debug help with my sorting fuse

#8

Post by pingking » Tue Sep 11, 2018 12:46 pm

i'm impressed! this is really fast compared to my "naive" approach

Thanks alot!

i started to play around with Multithreading but couldnt get it to work so far

User avatar
pingking
Fusionista
Posts: 744
Joined: Thu Aug 14, 2014 9:10 am

Re: need debug help with my sorting fuse

#9

Post by pingking » Mon Jan 21, 2019 12:48 pm

because i dont have time to dig deeper into this code and bring it forward i decided to donate my code to the community here.

i still hope someone will pick it up and bring it forward and production ready

the basic functions work and not to slow, some functions are missing and i started to implent ROIDS but that made everything slow and unstable (not active in the version here)

there are not many comments in the code and from the parts i commented out you see i had some ideas where to go
Code: [Select all] [Expand/Collapse] [Download] (PixelSort_test_mp.Fuse)
  1. --[[--
  2. PixelSort_test_mp.Fuse
  3.  
  4. A Fuse to create pixel sorting image effects
  5.  
  6. version 2.0
  7. December 31th, 2018
  8.  
  9.  -- data window
  10.  -- orientation
  11.  -- patches
  12.  -- threshold to threshold
  13.  
  14.  
  15.  
  16.  
  17. Permission is hereby granted, free of charge, to any person obtaining
  18. a copy of this software and associated documentation files (the
  19. "Software"), to deal in the Software without restriction, including
  20. without limitation the rights to use, copy, modify, merge, publish,
  21. distribute, sublicense, and/or sell copies of the Software, and to
  22. permit persons to whom the Software is furnished to do so, subject to
  23. the following conditions:
  24.  
  25. The above copyright notice and this permission notice shall be included
  26. in all copies or substantial portions of the Software.
  27.  
  28. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  29. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  30. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  31. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  32. CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  33. TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  34. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  35. --]]--
  36.  
  37.  
  38.  
  39. FuRegisterClass("PixelSort_mp_prod", CT_Tool, {
  40.     REGS_Category = "Fuses",
  41.     REGS_OpIconString = "PixS_MP",
  42.     REGS_OpDescription = "PixelSort_MP Fuse",
  43.     REG_NoMotionBlurCtrls = true,
  44.     REG_NoObjMatCtrls = true,
  45.     REG_Fuse_NoEdit = true,
  46.     --REG_Fuse_NoReload = true,
  47.     --REG_NoBlendCtrls = true,
  48.     REG_SupportsDoD = false
  49.  
  50.     })
  51.  
  52.  
  53.  
  54. function Create()
  55.  
  56.     -- InThresholdMode = self:AddInput("threshold compare mode", "threshold_mode", {
  57.         -- LINKID_DataType = "Number",
  58.         -- INPID_InputControl = "MultiButtonControl",
  59.         -- INP_Default = 0.0,
  60.         -- {MBTNC_AddButton = "Mode A (all)",   MBTNCD_ButtonWidth = 0.5, },
  61.         -- {MBTNC_AddButton = "Mode B (between)",   MBTNCD_ButtonWidth = 0.5, },
  62.         -- })
  63.     InThresholdCompare = self:AddInput("threshold compare method", "threshold_compare", {
  64.         LINKID_DataType = "Number",
  65.         INPID_InputControl = "MultiButtonControl",
  66.         INP_Default = 0.0,
  67.         {MBTNC_AddButton = "below threshold",   MBTNCD_ButtonWidth = 0.5, },
  68.         {MBTNC_AddButton = "above threshold",   MBTNCD_ButtonWidth = 0.5, },
  69.         })
  70.     InThreshold = self:AddInput("Threshold (0 = no restriction)", "Threshold", {
  71.         LINKID_DataType = "Number",
  72.         INPID_InputControl = "SliderControl",
  73.         INP_MaxScale = 1.0,
  74.         INP_Default = 0.0,
  75.         ICD_Center = 1,
  76.         })
  77.     -- InPatchSize = self:AddInput("Patchsize (0 = no restriction)", "Patchsize", {
  78.         -- LINKID_DataType = "Number",
  79.         -- INPID_InputControl = "SliderControl",
  80.         -- INP_MaxScale = 1920.0,
  81.         -- INP_Default = 0.0,
  82.         -- INP_Integer           = true,
  83.         -- ICD_Center = 1,
  84.         -- })
  85.     -- InLineskip = self:AddInput("skip Lines", "Lineskip", {
  86.         -- LINKID_DataType = "Number",
  87.         -- INPID_InputControl = "SliderControl",
  88.         -- INP_MaxScale = 20,
  89.         -- INP_Default = 0,
  90.         -- INP_Integer = true,
  91.         -- --ICD_Center = 1,
  92.         -- })
  93.     InMaxlength = self:AddInput("max. length (in %)", "Maxlength", {
  94.         LINKID_DataType = "Number",
  95.         INPID_InputControl = "SliderControl",
  96.         INP_MaxScale = 1,
  97.         INP_Default = 1,
  98.         INP_Integer = false,
  99.         --ICD_Center = 1,
  100.         })
  101.     -- InStyle = self:AddInput("Oriention", "Orient", {
  102.         -- LINKID_DataType = "Number",
  103.         -- INPID_InputControl = "MultiButtonControl",
  104.         -- INP_Default = 0.0,
  105.         -- {MBTNC_AddButton = "vertical",   MBTNCD_ButtonWidth = 0.5, },
  106.         -- {MBTNC_AddButton = "horizontal",     MBTNCD_ButtonWidth = 0.5, },
  107.         -- })
  108.     InChannel = self:AddInput("compare to channel", "Channel", {
  109.         LINKID_DataType = "Number",
  110.         INPID_InputControl = "MultiButtonControl",
  111.         INP_Default = 3.0,
  112.         {MBTNC_AddButton = "Red",   MBTNCD_ButtonWidth = 0.5, },
  113.         {MBTNC_AddButton = "Green",     MBTNCD_ButtonWidth = 0.5, },
  114.         {MBTNC_AddButton = "Blue",  MBTNCD_ButtonWidth = 0.5, },
  115.         {MBTNC_AddButton = "Luma",  MBTNCD_ButtonWidth = 0.5, },
  116.         {MBTNC_AddButton = "Hue",   MBTNCD_ButtonWidth = 0.5, },
  117.         {MBTNC_AddButton = "Saturation",    MBTNCD_ButtonWidth = 0.5, },
  118.         })
  119.     -- InLeftRight = self:AddInput("left/right", "left_right", {       
  120.         -- LINKID_DataType = "Number",
  121.         -- INPID_InputControl = "MultiButtonControl",
  122.         -- INP_Default = 0.0,
  123.         -- {MBTNC_AddButton = "left",   MBTNCD_ButtonWidth = 0.5, },
  124.         -- {MBTNC_AddButton = "right",  MBTNCD_ButtonWidth = 0.5, },
  125.         -- })
  126.  
  127.     InImage = self:AddInput("Input", "Input", {
  128.         LINKID_DataType = "Image",
  129.         LINK_Main = 1,
  130.     })
  131.  
  132.     OutImage = self:AddOutput("Output", "Output", {
  133.         LINKID_DataType = "Image",
  134.         LINK_Main = 1,
  135.         })
  136. end
  137.  
  138.  
  139.  
  140. --in-place quicksort
  141. function quicksort3(t, start, endi, threshold, maxiter, threshold_compare)
  142.     start, endi = start or 1, endi or #t
  143.     threshold = threshold or 0
  144.     if threshold == 0 then threshold_compare = 1 end
  145.     if(endi - start < 1) then return t end
  146.     local pivot = start
  147.     local maxiter = maxiter or endi
  148.     local nn = 0
  149.     for i = start + 1, endi do
  150.         if nn > maxiter then break end
  151.         nn = nn + 1
  152.         if threshold_compare == 1 then
  153.             if math.abs(t[i].Value) >= threshold then
  154.                 if t[i].Value <= t[pivot].Value then
  155.                     if i == pivot + 1 then
  156.                         t[pivot].Index,t[pivot+1].Index = t[pivot+1].Index,t[pivot].Index
  157.                         t[pivot].Value,t[pivot+1].Value = t[pivot+1].Value,t[pivot].Value
  158.                     else
  159.                          t[pivot].Index,t[pivot+1].Index,t[i].Index = t[i].Index,t[pivot].Index,t[pivot+1].Index
  160.                          t[pivot].Value,t[pivot+1].Value,t[i].Value = t[i].Value,t[pivot].Value,t[pivot+1].Value
  161.                     end
  162.                     pivot = pivot + 1
  163.                 end
  164.             end
  165.         else --threshold_compare
  166.             if math.abs(t[i].Value) <= threshold then
  167.                 if t[i].Value >= t[pivot].Value then
  168.                     if i == pivot + 1 then
  169.                         t[pivot].Index,t[pivot+1].Index = t[pivot+1].Index,t[pivot].Index
  170.                         t[pivot].Value,t[pivot+1].Value = t[pivot+1].Value,t[pivot].Value
  171.                     else
  172.                          t[pivot].Index,t[pivot+1].Index,t[i].Index = t[i].Index,t[pivot].Index,t[pivot+1].Index
  173.                          t[pivot].Value,t[pivot+1].Value,t[i].Value = t[i].Value,t[pivot].Value,t[pivot+1].Value
  174.                     end
  175.                     pivot = pivot + 1
  176.                 end
  177.             end
  178.         end
  179.     end
  180.     t = quicksort3(t, start, pivot - 1, threshold, maxiter, threshold_compare)
  181.     return quicksort3(t, pivot + 1, endi, threshold, maxiter, threshold_compare)
  182. end
  183.  
  184.  
  185.  
  186. function mp_init()
  187.     if not _G._HAS_PIXELSORTSTRUCT then
  188.         _G._HAS_PIXELSORTSTRUCT = true
  189.         ffi.cdef[[
  190.             struct pixelSortStruct
  191.             {
  192.                 int32 Index;
  193.                 float32 Value;
  194.             };
  195.         ]]
  196.     end
  197.  
  198.     -- pixelArray = ffi.new("struct pixelSortStruct[?]", newdod:Width())
  199.         pixelArray = ffi.new("struct pixelSortStruct[?]", img.Width)
  200.         -- pixelArray2 = ffi.new("struct pixelSortStruct[?]", img.Height)
  201.  
  202.     p = Pixel()
  203.     sp = PixPtr(img, p)
  204.     dp = PixPtr(out, p)
  205. end
  206.  
  207.  
  208.  
  209. function mp_func(scanline)
  210.     local y = scanline
  211.     --sp:GotoXY(newdod.left, y)
  212.     sp:GotoXY(0, y)
  213.     -- for x = newdod.left, newdod.right-1 do
  214.     for x=0,img.Width-1 do
  215.         sp:GetNextPixel(p)
  216.         luma = (p.R*.2126)+(p.G*.7152)+(p.B*.0722)
  217.         max_color = math.max(p.R, math.max(p.G, p.B))
  218.         min_color = math.min(p.R, math.min(p.G, p.B))
  219.         delta = max_color - min_color
  220.         if max_color == min_color then
  221.             sat = luma
  222.         else
  223.             if luma > 0.5 then
  224.                 sat = delta / (2 - delta)
  225.             else
  226.                 sat = delta / (max_color + min_color)
  227.             end
  228.         end
  229.         if p.R == max_color then
  230.             hue = (p.G - p.B)/(max_color - min_color)
  231.         elseif p.G == max_color then
  232.             hue = 2 + (p.B - p.R) / (max_color - min_color)
  233.         else
  234.             hue = 4 + (p.R - p.G) / (max_color - min_color)
  235.         end
  236.         if max_color == min_color then hue = 0 end --achromatic
  237.         hue = hue * 60 -- make it degrees
  238.         if hue < 0 then hue = hue + 360 end -- if hue is negative bring it back to positive degrees
  239.         if hue == 0 then hue = luma end
  240.         hue = hue/360
  241.         pixelArray[x].Index = x
  242.         if sort_channel == 0 then
  243.             pixelArray[x].Value = p.R
  244.         elseif sort_channel == 1 then
  245.             pixelArray[x].Value = p.G
  246.         elseif sort_channel == 2 then
  247.             pixelArray[x].Value = p.B
  248.         elseif sort_channel == 3 then
  249.             pixelArray[x].Value = luma
  250.         elseif sort_channel == 4 then
  251.             pixelArray[x].Value = hue
  252.         else
  253.             pixelArray[x].Value = sat
  254.         end
  255.     end
  256.     if threshold_mode == 1 then
  257.         if threshold > 0 then
  258.             --x = 0
  259.             while startx < img.Width-1 do
  260.                 for x=startx,img.Width-1 do
  261.                     if threshold_compare == 1 then
  262.                         if pixelArray[x].Value >= threshold then
  263.                             startx = x
  264.                             break
  265.                         end
  266.                     else
  267.                         if pixelArray[x].Value <= threshold then
  268.                             startx = x
  269.                             break
  270.                         end
  271.                     end
  272.                 end --find startx
  273.                 for x=startx,img.Width-1 do
  274.                     if threshold_compare == 1 then
  275.                         if pixelArray[x].Value < threshold then
  276.                             endx = x
  277.                             break
  278.                         end
  279.                     else
  280.                         if pixelArray[x].Value > threshold then
  281.                             endx = x
  282.                             break
  283.                         end
  284.                     end
  285.                 end --find endx
  286.                 pixelArray = quicksort3(pixelArray, startx, endx, threshold, maxiter, threshold_compare)
  287.                 dp:GotoXY(startx, y)
  288.                 for bx=startx, endx do
  289.                     img:GetPixel(pixelArray[bx].Index,y, p)
  290.                     dp:SetNextPixel(p)
  291.                 end
  292.                 startx = endx+1
  293.                 if startx < img.Width-1 then break end
  294.             end --while
  295.         else --threshold
  296.             pixelArray = quicksort3(pixelArray, startx, endx, threshold, maxiter, threshold_compare)
  297.             dp:GotoXY(startx, y)
  298.             for bx=startx, endx do
  299.                 img:GetPixel(pixelArray[bx].Index,y, p)
  300.                 dp:SetNextPixel(p)
  301.             end
  302.         end -- threshold
  303.     else --mode
  304.         pixelArray = quicksort3(pixelArray, startx, endx, threshold, maxiter, threshold_compare)
  305.         dp:GotoXY(startx, y)
  306.         for bx=startx, endx do
  307.             img:GetPixel(pixelArray[bx].Index,y, p)
  308.             dp:SetNextPixel(p)
  309.         end
  310.     end
  311. end
  312.  
  313.  
  314.  
  315. function Process(req)
  316.     self:SetProgress(0.0)
  317.     local img = InImage:GetValue(req)
  318.     local threshold = InThreshold:GetValue(req).Value
  319.     -- local orient = InStyle:GetValue(req).Value
  320.     -- local orient = 1
  321.     local threshold_compare = InThresholdCompare:GetValue(req).Value
  322.     -- local left_right = InLeftRight:GetValue(req).Value
  323.     -- local threshold_mode = InThresholdMode:GetValue(req).Value
  324.     local threshold_mode = 0
  325.     local sort_channel = InChannel:GetValue(req).Value
  326.     -- local patchsize = InPatchSize:GetValue(req).Value
  327.      -- if patchsize == 0 then
  328.         -- if orient == 1 then patchsize = img.Height-1
  329.         -- else
  330.             -- patchsize = img.Width-1
  331.         -- end
  332.     -- end
  333.    
  334.     -- local lineskip = InLineskip:GetValue(req).Value
  335.     local maxiter = InMaxlength:GetValue(req).Value*img.Width
  336.     -- if maxiter == 0 then
  337.         -- if orient == 0 then maxiter = img.Height-1
  338.         -- else
  339.             -- maxiter = img.Width-1
  340.         -- end
  341.     -- end
  342.     -- if ((maxiter > patchsize) and (patchsize>0)) then maxiter = patchsize end
  343.  
  344.    
  345. --------------------------------------------------------------------
  346.     -- local dod, roi = req:GetInputDoD(InImage), req:GetRoI()
  347.     -- data window, which is the area this Fuse has to process, starts out as input data window restricted to its DoD
  348.     -- local datawnd = dod:Intersect(img.DataWindow)
  349.     -- restrict further to region of interest (roi will be nil during precalc and thus datawnd won't be restricted)
  350.     -- if roi then
  351.          -- datawnd = roi:Intersect(datawnd)
  352.     -- end
  353.     -- local newdod = datawnd
  354.         -- if roi ~= nil then
  355.         -- datawnd = roi:Intersect(datawnd)
  356.     -- end
  357. --------------------------------------------------------------------
  358.  
  359.  
  360.     --local order = InOrder:GetValue(req).Value
  361.     local out = img:CopyOf()
  362.     -- if left_right == 1 then
  363.         -- out = img:Transform(img, {
  364.         -- XF_XSize = -1,
  365.         -- })
  366.     -- end
  367.     -- local out = Image({
  368.         -- IMG_Like = img,                               -- ...that takes most attributes from the input image
  369.         -- IMG_NoData = req:IsPreCalc(),                 -- ...that doesn't contain data during precalc
  370.         -- IMG_ValidWindow = roi and roi.ValidWindow,       -- only set if roi ~= nil (e.g. not a precalc request)
  371.         -- IMG_DataWindow = datawnd,                     -- ...that contains data within the bounds of datawnd
  372.         -- })
  373.  
  374.     local p = Pixel({A=1})
  375.     local out_px = Pixel({ R = 1.0, G = 0.0, B = 0.0 })
  376.  
  377.     local pixelArray = {}
  378.     local pixelArrayR = {}
  379.     local pixelArrayG = {}
  380.     local pixelArrayB = {}
  381.     local pixelArrayA = {}
  382.  
  383.     local px = {}
  384.     local slices = 1
  385.     local n = 0
  386.     -- if patchsize > 0 then
  387.         -- slices = math.floor(img.Width/patchsize)
  388.         -- for n = 0, slices do
  389.             -- startX = n * patchsize
  390.             -- endX =  n * patchsize + patchsize
  391.             -- if startX > img.Width-1 then startX = img.Width-1 end
  392.             -- if endX > img.Width-1 then endX = img.Width-1 end
  393.             -- self:DoMultiProcess(mp_init, {
  394.                 -- img = img,
  395.                 -- out = out,
  396.                 -- maxiter = maxiter,
  397.                 -- threshold = threshold,
  398.                 -- --order = order,
  399.                 -- sort_channel = sort_channel,
  400.                 -- threshold_compare = threshold_compare,
  401.                 -- threshold_mode = threshold_mode,
  402.                 -- -- newdod = newdod,
  403.                 -- startx = startX,
  404.                 -- endx = endX,
  405.                 -- quicksort3 = quicksort3,
  406.                 -- }, out.Height, mp_func)
  407.         -- end
  408.     -- else --patchsize
  409.         self:DoMultiProcess(mp_init, {
  410.             img = img,
  411.             out = out,
  412.             maxiter = maxiter,
  413.             threshold = threshold,
  414.             --order = order,
  415.             sort_channel = sort_channel,
  416.             threshold_compare = threshold_compare,
  417.             threshold_mode = threshold_mode,
  418.             --orient = orient,
  419.             -- newdod = newdod,
  420.             startx = 0,
  421.             endx = img.Width-1,
  422.             quicksort3 = quicksort3,
  423.             }, out.Height, mp_func)
  424.  
  425.     -- end
  426.    
  427.     OutImage:Set(req, out)
  428. end
  429.  
Added in 15 minutes 21 seconds:
a very short demo, realtime on an old HP Z800 (dual xeon x5650) images size 1920x1080

User avatar
leon_good
Posts: 3
Joined: Sun Aug 18, 2019 7:36 pm

Re: need debug help with my sorting fuse

#10

Post by leon_good » Mon Aug 19, 2019 5:45 am

Hi, How to use this script in davinci resolve 16?

User avatar
leon_good
Posts: 3
Joined: Sun Aug 18, 2019 7:36 pm

Re: need debug help with my sorting fuse

#11

Post by leon_good » Mon Aug 26, 2019 3:48 am

leon_good wrote:
Mon Aug 19, 2019 5:45 am
Hi, How to use this script in davinci resolve 16?
HEY! is there anyone here

User avatar
SecondMan
Site Admin
Posts: 4229
Joined: Thu Jul 31, 2014 5:31 pm
Answers: 15
Location: Vancouver, Canada
Been thanked: 58 times
Contact:

Re: need debug help with my sorting fuse

#12

Post by SecondMan » Mon Aug 26, 2019 9:08 am

It might be your manner of asking. Maybe you can ask a parent to help you?

This may be of help to you, too: https://www.thoughtco.com/asking-a-favo ... sh-4164581

Best wishes,
WSL

User avatar
SirEdric
Fusionator
Posts: 2265
Joined: Tue Aug 05, 2014 10:04 am
Answers: 9
Real name: Eric Westphal
Been thanked: 28 times
Contact:

Re: need debug help with my sorting fuse

#13

Post by SirEdric » Mon Aug 26, 2019 10:52 am

SecondMan wrote:
Mon Aug 26, 2019 9:08 am
This may be of help to you, too: https://www.thoughtco.com/asking-a-favo ... sh-4164581
Would it be too much trouble for you to put that link into the forum guidelines? :-)

User avatar
leon_good
Posts: 3
Joined: Sun Aug 18, 2019 7:36 pm

Re: need debug help with my sorting fuse

#14

Post by leon_good » Mon Aug 26, 2019 12:52 pm

SecondMan wrote:
Mon Aug 26, 2019 9:08 am
It might be your manner of asking. Maybe you can ask a parent to help you?

This may be of help to you, too: https://www.thoughtco.com/asking-a-favo ... sh-4164581

Best wishes,
WSL
Thank you!!! Good site! I don’t know English at all, sorry. I use a translator from Google for now.

User avatar
pingking
Fusionista
Posts: 744
Joined: Thu Aug 14, 2014 9:10 am

Re: need debug help with my sorting fuse

#15

Post by pingking » Tue Aug 27, 2019 1:20 pm

i didnt use Resolve16 or Fusion16 yet, but i guess it should still work (its pure slow CPU code)

you have to save the script as .fuse file on your workstation, put it in your fuse directory (for windows it is: C:\Users\YourUserName\AppData\Roaming\Blackmagic Design\DaVinci Resolve\Fusion\Fuses) then it should be under "add tool --> fuses"