View Single Post
Old 4th April 2021, 23:57   #211  |  Link
zorr
Registered User
 
Join Date: Mar 2018
Posts: 447
Quote:
Originally Posted by Boulder View Post
Perhaps the only way to make it faster and threadsafe in Avisynth would be to use an array as you suggested.
After some tests I've found that Avisynth doesn't have array variables, only array constants. You cannot store values into an array after it has been created so currently arrays are not an option.

Quote:
Originally Posted by Boulder View Post
Or is it possible to make all the frames create their own log file and combine them when it's time to calculate the total score?
It would be easy to create a separate log file for each frame but that wouldn't make anything faster.

I tried some other ways. You can create a new variable for each frame (using Eval) and store the metric there. It doesn't solve the synchronization problem though, there are sometimes missing variables when it is time to combine the results. So that method only works without Prefetch. It would be useful for Avisynth to have a callback function which would be triggered when all the frames have been processed.

I also thought that maybe there's no need for any extra variables at all, we can simply read the metric from all the frames at the last frame using the offset parameter of propGetFloat(). The good news is that it actually works and is faster than the default method which writes to a file at each frame. The bad news is that the speedup is simply due to writing to the file only once (saves about 1,6ms per frame) and there is no additional speedup when using Prefetch. Here's the code:
Code:
TEST_FRAMES = 50			# how many frames are tested
MIDDLE_FRAME = 100		# middle frame number

RawSourcePlus("D:/optimizer/test/flower/flower_cif.yuv", width=352, height=288, pixel_type="I420")
source=ColorYUV(levels="PC->TV")
noisy=source.AddGrain(25, 0, 0, seed=1)
#return noisy

#denoised=noisy.FFT3DFilter(sigma=4, bt=4, bw=16, bh=16, ow=8, oh=8)		# best settings by Fizick

sigma = 400/100.0 	# optimize sigma = _n_/100.0 | 100..800 | sigma
bt = 4				# optimize bt = _n_ | -1..5 | blockTemporal
blockSize = 32		# optimize blockSize = _n_ | 2..64 ; min:overlap 2 * | blockSize
overlap = 16		# optimize overlap = _n_ | 0..32 ; max:blockSize 2 / | overlap
denoised=noisy.FFT3DFilter(sigma=sigma, bt=bt, bw=blockSize, bh=blockSize, ow=overlap, oh=overlap)

# cut out the part used in quality / speed evaluation
source = source.Trim(MIDDLE_FRAME - TEST_FRAMES/2 + (TEST_FRAMES%2==0?1:0), MIDDLE_FRAME + TEST_FRAMES/2)
denoised = denoised.Trim(MIDDLE_FRAME - TEST_FRAMES/2 + (TEST_FRAMES%2==0?1:0), MIDDLE_FRAME + TEST_FRAMES/2)
last = denoised

last = GMSD(source, denoised, show=false)

# measure runtime, plugin writes the value to global avstimer variable
global avstimer = 0.0
AvsTimer(frames=1, type=0, total=false, name="Optimizer")

# per frame logging (ssim, time)
global delimiter = "; "
global resultFile = "perFrameResults.txt"	# output out1="gmsd: MIN(float)" out2="time: MIN(time) ms" file="perFrameResults.txt"

# write "stop" at the last frame to tell the optimizer that the script has finished
global frame_count = FrameCount()

WriteFileIf(resultFile, function() {
    current_frame == frame_count-1
}, function() {
	gmsd = 0.0
	str = ""
	for (i = 0, frame_count-1) {
		value = propGetFloat("_PlaneGMSD", offset = -i)
		gmsd = gmsd + value
		if (i>0) { str = str + e"\n" }
		str = str + string(current_frame - i) + delimiter + string(value) + delimiter + string(avstimer)
	}
	return str + e"\nstop " + string(gmsd)
}, append=false)

Prefetch(4)

return last
I should also note that the previous GMSD version is not deterministic when used with Prefetch, it's rare but sometimes the last frame is not finished last and one of the frames is left out of the total sum. This version doesn't have that problem.

By the way this is a bit off-topic on this Vapoursynth forum. If any mods happen to read this it might be a good idea to move the posts starting from Worby's to the Avisynth Zopti thread.
zorr is offline   Reply With Quote