View Full Version : ImageMagick writer/reader
Myrsloik
22nd December 2017, 19:44
Test 9 added to first post. Try it and see how it works. Namespace is now always imwri.
poisondeathray
22nd December 2017, 20:41
vapoursynth R41 x64 test 2 / imwri r41 x64 test9
Just a quick test, I'll try some more things later
It doesn't seem to load a regular PNG, with or without alpha, or even a JPG. vsedit reports RGB24, correct dimensions, but it's black screen in vapoursynth editor . Is it a compatiblity issue with vsedit ? I tried converting to COMPATBGR32 still not working. But no error messages, just black screen.
Swapping out back to imwri test 8 (and using imwrif) works fine under R41 x64 test 2 to load a basic PNG or JPG , so it doesn't seem to be a vapoursynth R41 test 2 issue . Other than the namespace, was there some other syntax changes to the plugin ?
Myrsloik
25th December 2017, 20:49
It's probably miscompiled then. Happens now and then with imagemagick stuff, especially since producing a single monolithic dll requires evil mingw stuff. Will make another attempt.
Myrsloik
28th December 2017, 13:56
vapoursynth R41 x64 test 2 / imwri r41 x64 test9
Just a quick test, I'll try some more things later
It doesn't seem to load a regular PNG, with or without alpha, or even a JPG. vsedit reports RGB24, correct dimensions, but it's black screen in vapoursynth editor . Is it a compatiblity issue with vsedit ? I tried converting to COMPATBGR32 still not working. But no error messages, just black screen.
Swapping out back to imwri test 8 (and using imwrif) works fine under R41 x64 test 2 to load a basic PNG or JPG , so it doesn't seem to be a vapoursynth R41 test 2 issue . Other than the namespace, was there some other syntax changes to the plugin ?
I tested it and it does work well here with the images I tried. You're doing it wrong (probably). Give it another try.
poisondeathray
28th December 2017, 16:58
I tested it and it does work well here with the images I tried. You're doing it wrong (probably). Give it another try.
I have more faith in your testing, but still the same results. I don't see how I'm doing it wrong when it works with test8
I upgraded to Vapoursynth x64 R41 test 4, downloaded plugin again in case it was corrupt, upgraded VSEdit to R18, still doesn't work
The same source image works with imwri_test8 , or other source filters like ffms2 etc... so it's not a source issue and VSEdit is working correctly
I used the correct namespace, tried the wrong namespace, tried different arrays , Alpha=True vs False
Again, it's just a black screen. It reports everything else correctly, dimensions, etc... and Gray8 when returning the alpha [1], or RGB24 when returning [0]
Myrsloik
28th December 2017, 16:59
I have more faith in your testing, but still the same results. I don't see how I'm doing it wrong when it works with test8
I upgraded to R41 test 4, downloaded plugin again in case it was corrupt, upgraded VSEdit to R18, still doesn't work
The same source image works with imwri_test8 , or other source filters like ffms2 etc... so it's not a source issue
I used the correct namespace, tried the wrong namespace, tried different arrays , Alpha=True vs False
Can I have one of the not working images? Maybe it's something broken in the latest imagemagick...
poisondeathray
28th December 2017, 17:04
Can I have one of the not working images? Maybe it's something broken in the latest imagemagick...
It's a super simple alpha channel test 1280x720 8bit RGBA png
http://www.mediafire.com/file/8pr2lx962cmxc5c/logo.png
Myrsloik
28th December 2017, 17:22
It's a super simple alpha channel test 1280x720 8bit RGBA png
http://www.mediafire.com/file/8pr2lx962cmxc5c/logo.png
Doh, I only tested with high bitdepth images. A bug in how the output scaling is calculated made all below 16 bit images black.
Myrsloik
28th December 2017, 17:49
Download test9 again. It's been updated.
poisondeathray
28th December 2017, 17:54
Download test9 again. It's been updated.
This works now, but the alpha returned on that simple test is messed up. It's like an edge outline/mask
Myrsloik
28th December 2017, 18:30
This works now, but the alpha returned on that simple test is messed up. It's like an edge outline/mask
Sigh, found the reason for that too now. Can you test writing with this build as well?
poisondeathray
28th December 2017, 20:15
yes, I have time to test out a bunch of things, formats, read/write , bitdepths in the next few days.
But I stumbled on step 1 with a simple 8bit png :)
Is the next build up ?
Myrsloik
28th December 2017, 20:42
yes, I have time to test out a bunch of things, formats, read/write , bitdepths in the next few days.
But I stumbled on step 1 with a simple 8bit png :)
Is the next build up ?
Yes, updated the links again.
poisondeathray
29th December 2017, 02:51
The reader seems to be working well with different common image formats & compressions
-Instead of importing higher bit depth formats automatically as RGBS , it seems to get it correct now (e.g. 16bit RGB PNG would be RGB48 instead of RGBS like before).
-Alpha channel working too.
-(not related to IM, but linear to sRGB for linear image types using the internal VS resize is working correct)
1) EXR float is still imported as RGB48 instead of RGBS, and EXR halffloat is also imported as RGB48 instead of RGBH. But if I'm not mistaken, these are an imagemagick limitation ?
The writer works (abeit slowly), including sequence writing;
2) but imwri does not seem write out high bit depth , or at least I couldn't find the correct switch.
eg. 10bit RGB30 with core.imwri.Write, exporting DPX will write as 8bit
eg. 16bit RGB48 with core.imwri.Write, exporting PNG will write as 8bit
I tried imwrif (instead of imwri), and the docs say
Note that the namespace will be imwrif when compiled with a HDRI ImageMagick to distinguish the behavior and accepted format input/output formats.
yet, this one reads high (and low) bit depth formats, I just can't "convince" it to export high
Myrsloik
30th December 2017, 19:45
I updated the links again. This time it's tested. Mostly with tiff output but I fixed a pile of issues in the writing logic. There's also a float_output argument to force float format when reading images.
If you have a half precision float tiff file that'd be great too. It's the last rare thing I need for my testing. An interesting observation is that imagemagick itself only seems to properly flag that the source file is floating point for tiff, miff and mat. So unless float_output is set all other 16 bit images will be output as integer.
poisondeathray
30th December 2017, 21:09
I updated the links again. This time it's tested. Mostly with tiff output but I fixed a pile of issues in the writing logic. There's also a float_output argument to force float format when reading images.
If you have a half precision float tiff file that'd be great too. It's the last rare thing I need for my testing. An interesting observation is that imagemagick itself only seems to properly flag that the source file is floating point for tiff, miff and mat. So unless float_output is set all other 16 bit images will be output as integer.
Ok thanks I'll test the new one over the next few days
I've never seen a half float tiff, it's an rare subset.
There is an option to export it in natron, but when I use no compression , it's the same filesize as full float tiff. It makes think it's not actually half float. Most other programs don't have half float option; if they do it's only for EXR
Maybe some of the more exotic command line raw converters or some branches of imagemagick or related programs might be able to do it.
dipje
5th January 2018, 21:29
Photoshop has the option to save a floating-point image as FP32, FP24 or FP16. Filesizes when saving with no compression are correct (as in, they are all different).
I know 'the fact that Photoshop does it does not make it a standard' is always a thing :), but it does mean there is at least one high-profile bit of software there.
poisondeathray
6th January 2018, 05:39
Photoshop has the option to save a floating-point image as FP32, FP24 or FP16. Filesizes when saving with no compression are correct (as in, they are all different).
I know 'the fact that Photoshop does it does not make it a standard' is always a thing :), but it does mean there is at least one high-profile bit of software there.
Yes, you're right. How could I forget about PS ???!
exiftool reports a bunch of info and can distinguish between F32 and F16 Tiffs as well
Do you still need a samply Myrsloik ?
Myrsloik
6th January 2018, 12:29
Yes, I still want that elusive half precision tiff. I'm curious about what will happen.
poisondeathray
6th January 2018, 16:27
F16 Tiff
http://www.mediafire.com/file/a8rc4w1pdryzq7e/Bars_F16.7z
Myrsloik
6th January 2018, 22:00
F16 Tiff
http://www.mediafire.com/file/a8rc4w1pdryzq7e/Bars_F16.7z
Verified it and it's properly output as single precision float (nobody likes half precision float for later processing anyway)
poisondeathray
8th January 2018, 05:18
Will there ever be a build that has FP16/32 EXR (or TIFF I guess) export ? Or is that just not on the timeline whatsoever ?
Myrsloik
8th January 2018, 10:26
Will there ever be a build that has FP16/32 EXR (or TIFF I guess) export ? Or is that just not on the timeline whatsoever ?
You should be able to export F32 tiff right now. Not sure about which format exr will pick if you give it F32 input. F16 will probably need another option to set the number of floating point bits on output.
dipje
8th January 2018, 14:11
I did some EXR tests lately with the recent imwri sources.
1) it works (After Effects reads it just fine)
2) It 'seems' half-precision? (32bit EXR is more of an extension, right?). At least, when I export the same image-sequence again from AE without any changes, and select the same compression and half-precision, the files are pretty much the same size.
poisondeathray
8th January 2018, 18:50
1) confirmed, F32 tiff write works .
2) confirmed dipje's observations , EXR for write is F16 when using default setting (exiftool reports it as half, and can distinguish between common EXR compression formats for F16/32)
3) Not directly an imwri issue, but there seems to be a loss of precision when doing a linear<=>srgb conversion . I think it's a resize/zimg issue.
Usually float formats are linearized in other programs . So if you import an EXR, usually you need to specify the transfer parameters to delinearlize if converting to sRGB/Rec709
In F32/16, I would have expected this operation to be "reversible"
Recall this thread:
https://forum.doom9.org/showthread.php?t=174839
Recall this YUV420P10 to RGBS back to YUV420P10 is lossless
import vapoursynth as vs
core = vs.get_core()
clip = core.lsmas.LWLibavSource(r'F:\testchart720.png')
clip = core.resize.Bicubic(clip, format=vs.YUV420P10, matrix_s="709")
clip2 = core.resize.Point(clip, format=vs.RGBS, matrix_in_s="709", dither_type="none")
clip3 = core.resize.Point(clip2, format=vs.YUV420P10, matrix_s="709", dither_type="none")
d = core.std.MakeDiff(clip, clip3)
da = core.std.Levels(d, min_in=511, max_in=513, gamma=1, min_out=0, max_out=1023, planes=[0,1,2])
da.set_output()
So if you write out a non linearized TIFF or EXR it works. But most programs "expect" linear float
So adding linearization (in the attempt to write out a linear EXR or TFF F16/32) makes it non reversible or some loss . (I've omitted the write step here, but that's where I noticed the issue, and I'm working backwards to trace the issue)
import vapoursynth as vs
core = vs.get_core()
clip = core.lsmas.LWLibavSource(r'F:\testchart720.png')
clip = core.resize.Bicubic(clip, format=vs.YUV420P10, matrix_s="709")
clip2 = core.resize.Point(clip, format=vs.RGBS, matrix_in_s="709", dither_type="none", transfer_in_s="srgb", transfer_s="linear")
clip3 = core.resize.Point(clip2, format=vs.YUV420P10, matrix_s="709", dither_type="none", transfer_in_s="linear", transfer_s="srgb")
d = core.std.MakeDiff(clip, clip3)
da = core.std.Levels(d, min_in=511, max_in=513, gamma=1, min_out=0, max_out=1023, planes=[0,1,2])
da.set_output()
I've tried full range, splitting out the steps (converting to RGBS first, then specifying the transfer later instead of 1 step)
What am I missing ?
EDIT: sRGB <=> linear transfer using core.fmtc.transfer also exhibits differences
EDIT#2: But "61966-2-4" using fmtconv does not show differences for the transfer portion, and works. Must be those negative values ?
IEC 61966-2-4, xvYCC. Same as BT.709, but with an extended range, inlcuding negative values.
import vapoursynth as vs
core = vs.get_core()
clip = core.lsmas.LWLibavSource(r'F:\testchart720.png')
clip = core.resize.Bicubic(clip, format=vs.YUV420P10, matrix_s="709")
clip2 = core.resize.Point(clip, format=vs.RGBS, matrix_in_s="709", dither_type="none", range_in_s="full")
clip2a = core.fmtc.transfer(clip2, transs="61966-2-4", transd="linear")
clip2b = core.fmtc.transfer(clip2a, transs="linear", transd="61966-2-4")
clip3 = core.resize.Point(clip2b, format=vs.YUV420P10, matrix_s="709", dither_type="none", range_s="full")
d = core.std.MakeDiff(clip, clip3)
da = core.std.Levels(d, min_in=511, max_in=513, gamma=1, min_out=0, max_out=1023, planes=[0,1,2])
da.set_output()
I do not see "61966-2-4" as a valid entry for zimg/resize for transfer_s or transfer_in_s
dipje
8th January 2018, 22:49
I was testing with loading in HDR footage, and in floating point scaling it to linear light, writing it out as EXR and grade it for SDR in After Effects / Premiere.
And I discovered the same. fmtconv's transfer function clips (and it says so in the manual) which is a shame but OK. I figure that z.img (core.resize.xxx) does the same when messing with transfer_in / transfer.
converting color-primaries needs to be done in linear-light (according to fmtconv) so it's kinda a shame.
Also (unrelated to vapoursynth): If z.img transfer-conversion clips (not confirmed yet to be honest), that means that ffmpeg's tonemapping filter (which needs float and in the manual is recommended by using z.img to convert to linear-light, then the tonemap filter, then convert to your target transfer) also will have issues if you're not careful. I was expectng the float to be handy for HDr->SDR to you can map to a 'usable' brighness but with all the overbrights in the > 1.0 range, and then use tonemapping to do something with it. Apparently not :).
Myrsloik
8th January 2018, 22:49
If you use the R41 RC you can use "xvycc" as transfer. A lot of stuff was added in zimg.
poisondeathray
8th January 2018, 22:56
But the fmtconv transfer still is not quite right in other programs. Nothing is lost when you use "61966-2-4" (at least on that small test) , but the contrast black/white point has changed in other programs when using linear interpretation
zimg's looks more correct (or what you would expect) but there is some loss, it looks almost as if it was working in 16bit int, like ffmpeg's linear conversion does too. You see the loss in almost the same areas
I'll try some more tests with the newer R41RC
But none of this is the imwri plugin's fault - that appears to be working now
poisondeathray
8th January 2018, 23:20
Can you explain the problem with z.lib? When operating in fast mode (e.g. with VapourSynth), transfer conversions to/from linear are evaluated at 14-bit precision and also clipped. The API supports full-precision transfer functions, but it is dramatically slower.
The problem is as you described. The transfer portion appears to exhibit loss when dealing with linear float formats
Is there a way to access the full precision / slow mode ?
poisondeathray
8th January 2018, 23:37
VapourSynth does not expose the option to trade precision/range for speed. However, you can control this option indirectly by setting the "cpu" parameter to "none". However, from a workflow point of view, it is not clear to me why out-of-range non-linear values would be desirable. Normally one would perform all the limiting steps in the linear RGB domain, which is the output of the EXR decoder.
That is only a synthetic, simple test example
In real workflows, either with CG , Raw and HDR cameras, you have those out of range values, and the workflow is usually linear. So a transfer function that can maniuplate linear float formats would useful
Thanks for the "cpu" parameter tip , I will do some more tests later
poisondeathray
9th January 2018, 03:29
Yes, cpu_type="none" works
It's nice to have a delinearize/linearize transfer function workflow option that does not produce additional loss
The reason why you would use "transfer" in the first place is to "linearize" something to prepare it for another program. For example color manipluations ,filters. On the round trip back, you might have to "delinearize" or apply the transfer back to sRGB and eventually YUV
A typical example would be a prores acquisition from a camera. You might have to do some filtering in vapoursynth in YUV (maybe some noise reduction), then send it to some other program for color work in linear RGB. Or on the trip back, into vapoursynth to apply some other manipulations
poisondeathray
9th January 2018, 04:42
Since the fast mode for transfer functions is a LUT, z.lib has limited ability to handle out-of-range values. Would extending the coverage from [0.0,1.0] to [-0.5,1.5] (normalized, non-linear RGB) handle the out-of-range values you encounter in practice?
I would assume so, it's not something I measure regularly
Everything works with cpu_type="none", at least on a few quickie tests, but what is the typical speed penalty for "slow" mode ? I know it would vary by source, hardware setup etc.., but just ballpark estimate? I guess I could measure it too...
What would be the "cons" of implementing extended coverage range? For example would it slow down conversions that don't need it ? That would involve a more complex LUT , right ? Would it negatively impact something even when the transfer function wasn't called ?
But I would imagine someone calling the transfer function most frequently used would be sRGB <=> linear , and if you're going to be using float formats with linear workflow, the main point was probably precision in the first place... I would argue for those types of workflows you might as well go all the way
Selur
11th January 2018, 21:07
Small feature request:
Would be nice if
Read(string[] filename[, int firstnum=0, bint mismatch=False, bint alpha=False, bint float_output = False])
could also get a
int lastnum
parameter like Avisynths Image source.
Cu Selur
Myrsloik
11th January 2018, 21:09
Small feature request:
Would be nice if
Read(string[] filename[, int firstnum=0, bint mismatch=False, bint alpha=False, bint float_output = False])
could also get a
int lastnum
parameter like Avisynths Image source.
Cu Selur
What? To only read a limited number of images? But that could be solved with trim after just as easy...
LigH
11th January 2018, 21:51
Even if you could prove that it is not the case ... it may make the user feel that it takes more resources than required (first reads images it dismisses later). ;)
Selur
11th January 2018, 21:55
What? To only read a limited number of images? But that could be solved with trim after just as easy...
Okay I assumed that all the images would be scanned first and with for example an image count of 2 000 000 using 'firstnum=15' and 'clip = core.std.Trim(clip=clip, length=15691)' would be less effective,..
If not all images have to be scanned first, then I agree and trim is fine. :)
Cu Selur
Myrsloik
11th January 2018, 22:34
Okay I assumed that all the images would be scanned first and with for example an image count of 2 000 000 using 'firstnum=15' and 'clip = core.std.Trim(clip=clip, length=15691)' would be less effective,..
If not all images have to be scanned first, then I agree and trim is fine. :)
Cu Selur
The only check that's done is if the files exists so unless you have a ridiculously long sequence you should never need it. So the answer is somewhere inbetween. If you ever find a sequence that's slow I'll add it.
Selur
12th January 2018, 05:08
Okay. Thanks! :)
TheFluff
12th January 2018, 15:56
Even if you could prove that it is not the case ... it may make the user feel that it takes more resources than required (first reads images it dismisses later). ;)
Please stop disrespecting old Donald Knuth ("premature optimization is the root of all evil"). You really shouldn't encourage people to micro-optimize things based on intuition and guesswork. It's very common in Avisynth circles (c.f. the guy who wrote 3000 lines of asm to optimize bitblt with zero real-world performance improvement, the continued insistence on compiling with all kinds of completely pointless instruction sets enabled because it feels good or something, etc etc) but it's a really awful idea. Testing for the existence of 100k files takes on the order of 0.1 seconds on any reasonably modern hardware, and it's only done once.
poisondeathray
14th January 2018, 01:28
This experimental build (https://www.dropbox.com/s/m63ly0ahbtrnjjt/VapourSynth.dll?dl=0) of VapourSynth R41 preserves some BTB/WTW information when applying transfer functions. It may or may not work for you. Replace the vapoursynth.dll in the "Lib\site-packages\vapoursynth" directory of your Python installation.
Thanks!
@Myrsloik - when you get a chance, can you add EXR F32 write option ?
Myrsloik
14th January 2018, 11:07
Thanks!
@Myrsloik - when you get a chance, can you add EXR F32 write option ?
If imagemagick doesn't write it when you give it 32bit float its simply an imagemagick limitation.
feisty2
28th January 2018, 04:50
can I output floating point TIFFs?
clp = core.imwrif.Write(clp, "tiff", "%06d.tif", 0, compression_type="None")
#clp is GrayS but this gives me a Gray16 sequence
according to the imagemagick documentation (https://imagemagick.org/script/formats.php), I need to append "-define quantum:format=floating-point" in the command line, how do I do that with imwri?
poisondeathray
28th January 2018, 05:05
can I output floating point TIFFs?
clp = core.imwrif.Write(clp, "tiff", "%06d.tif", 0, compression_type="None")
#clp is GrayS but this gives me a Gray16 sequence
according to the imagemagick documentation (https://imagemagick.org/script/formats.php), I need to append "-define quantum:format=floating-point" in the command line, how do I do that with imwri?
Did you update your vapoursynth? It works here with GRAYS
It's imwri.Write now, not imwrif.Write , so you must be using older version
feisty2
28th January 2018, 05:48
Did you update your vapoursynth? It works here with GRAYS
It's imwri.Write now, not imwrif.Write , so you must be using older version
yeah I just updated to test 9 and it's working now
foxyshadis
5th March 2018, 11:22
I wouldn't normally ask for updates except that I have zero confidence in being able to set up an ImageMagick build environment, but 7.0.7.22 was released with HEIF/HEIC support recently, and it'd be a lot of fun to play around with that capability. I'm strongly leaning toward it for general purposes unless a competitor pops up from Xiph or Google soon, since JXR went nowhere.
jackoneill
5th March 2018, 16:05
I wouldn't normally ask for updates except that I have zero confidence in being able to set up an ImageMagick build environment, but 7.0.7.22 was released with HEIF/HEIC support recently, and it'd be a lot of fun to play around with that capability. I'm strongly leaning toward it for general purposes unless a competitor pops up from Xiph or Google soon, since JXR went nowhere.
Is that built into ImageMagick, or does it need an external library?
foxyshadis
6th March 2018, 03:14
Is that built into ImageMagick, or does it need an external library?
Requires libde265 be present, as an additional dependency.
jackoneill
6th March 2018, 14:04
I wouldn't normally ask for updates except that I have zero confidence in being able to set up an ImageMagick build environment, but 7.0.7.22 was released with HEIF/HEIC support recently, and it'd be a lot of fun to play around with that capability. I'm strongly leaning toward it for general purposes unless a competitor pops up from Xiph or Google soon, since JXR went nowhere.
Imwri with ImageMagick 7.0.7-25 and libde265 1.0.2 (http://savedonthe.net/download/2110/imwri-r43-win64.html)
foxyshadis
8th March 2018, 13:39
Thanks for the build. It looks like IM's current implementation has some big bugs, maybe it only works specifically with Apple's files, since its own image reader can't read the conformance files. Probably down to the MP4 parsing. I'll see if I can narrow down what's going on and get them to patch it.
Alexkral
9th April 2020, 01:00
Hi, sorry if I am not understanding how this can be used, I am new to Vapoursynth. I am trying to run this Python script on Windows through the command line:
import vapoursynth as vs
core = vs.get_core()
src = core.imwri.Read("C:/image_01.png")
src = core.imwri.Write(src, imgformat="PNG", filename="C:/image_02.png")
src.get_frame(0)
src.set_output()
This doesn't write anything to disk, as I understand this is because frames are not being required from IMWRI, so get_frame doesn't work for it. Is there a different way to do it by running a Python script through the command line?
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.