View Full Version : How do I import image with a color profile?
lansing
12th March 2020, 22:07
My tiff image has an color profile "Adobe RGB (1998)", and when I import it to vs, the program discarded the profile and displayed the wrong color. What do I do?
clip = core.imwri.Read(file)
poisondeathray
12th March 2020, 22:28
vapoursynth, avisynth, ffmpeg etc... do not support icc color profiles
You can use imagemagick's convert.exe to batch convert to sRGB
eg as a windows batch file (use one % instead of two if executing from command line)
for %%a in ("*.tiff") do "D:\ImageMagick\convert" "%%a" -colorspace sRGB -profile "D:\ICC color profiles\sRGB2014.icc" "OUTPUTPATH\%%~na.png"
pause
lansing
13th March 2020, 04:07
vapoursynth, avisynth, ffmpeg etc... do not support icc color profiles
You can use imagemagick's convert.exe to batch convert to sRGB
eg as a windows batch file (use one % instead of two if executing from command line)
for %%a in ("*.tiff") do "D:\ImageMagick\convert" "%%a" -colorspace sRGB -profile "D:\ICC color profiles\sRGB2014.icc" "OUTPUTPATH\%%~na.png"
pause
That's one hassle that I wanted to avoid. I read that Adobe Premiere does the conversion automatically when importing images.
poisondeathray
13th March 2020, 05:07
That's one hassle that I wanted to avoid. I read that Adobe Premiere does the conversion automatically when importing images.
All color managed programs can handle it automatically
_Al_
13th March 2020, 05:59
looking at this link,
https://stackoverflow.com/questions/33168615/how-to-read-jpeg-image-with-adobe-rgb-colorspace-in-opencv
if that iccp profile is bytes pulled from that info, you could use just Python using PIL and numpy modules:
import PIL
import PIL.ImageCms
import numpy as np
import functools
clip_placeholder = core.std.BlankClip(width = 800, height = 605, format= vs.RGB24, length=1)
rgbp = PIL.ImageCms.createProfile("sRGB")
im = PIL.Image.open(r'D:\Photos\5102_3493.jpg')
def get_clip(n, f, im):
try:
iccp = im.info['icc_profile']
except KeyError as e:
#no icc_profile in image
return f
icc2rgb = PIL.ImageCms.buildTransformFromOpenProfiles(rgbp, iccp, "RGB", "RGB")
im = PIL.ImageCms.applyTransform(im, icc2rgb)
npArray = np.array(im)
vsFrame = f.copy()
[np.copyto(np.asarray(vsFrame.get_write_array(i)), npArray[:, :, i]) for i in range(3)]
return vsFrame
clip = core.std.ModifyFrame(clip_placeholder, clip_placeholder, functools.partial(get_clip, im=im))
clip.set_output()
ok this way it is without error, but still not sure if that iccp is correct bytes type
lansing
13th March 2020, 07:08
I'm getting a black frame from the script
Now when I pass in a jpg with the AdobeRGB 1998 icc profile, I'm getting "Invalid type for Profile"
_Al_
13th March 2020, 07:46
if image needs to be passed without profile it would need to be:
def get_clip(n, f, im):
vsFrame = f.copy()
try:
iccp = im.info['icc_profile']
except KeyError as e:
#no profile pass image to vs as is
[np.copyto(np.asarray(vsFrame.get_write_array(i)), np.array(im)[:, :, i]) for i in range(3)]
return vsFrame
#other part if profile is present ...
there might be a type problem , wrong type of iccp input for that buildTransform function, maybe it expects a file, so file needs to be written from those iccp bytes
or if you have that one, you can use that line to create that iccp:
iccp = PIL.ImageCms.getOpenProfile("profile.icc")
Myrsloik
13th March 2020, 07:54
Create an issue and I'll see if I can add support later.
lansing
13th March 2020, 08:15
Create an issue and I'll see if I can add support later.
Thank you
lansing
13th March 2020, 08:31
if image needs to be passed without profile it would need to be:
def get_clip(n, f, im):
vsFrame = f.copy()
try:
iccp = im.info['icc_profile']
except KeyError as e:
#no profile pass image to vs as is
[np.copyto(np.asarray(vsFrame.get_write_array(i)), np.array(im)[:, :, i]) for i in range(3)]
return vsFrame
#other part if profile is present ...
there might be a type problem , wrong type of iccp input for that buildTransform function, maybe it expects a file, so file needs to be written from those iccp bytes
or if you have that one, you can use that line to create that iccp:
iccp = PIL.ImageCms.getOpenProfile("profile.icc")
Thanks, I got it working.
I matched the blankclip resolution to the size of the image, loaded the AdobeRGB icc profile to the "iccp", switch place the inputProfile/outputProfile in the buildTransformFromOpenProfiles function. And it works.
poisondeathray
13th March 2020, 15:36
Thanks, I got it working.
I matched the blankclip resolution to the size of the image, loaded the AdobeRGB icc profile to the "iccp", switch place the inputProfile/outputProfile in the buildTransformFromOpenProfiles function. And it works.
Color seems off. I might be doing something wrong
Can you provide the full script and/or more clear instructions?
EDIT: nevermind, stupid mistake, it works
Thanks _Al_ and lansing .
poisondeathray
13th March 2020, 16:16
I'm having difficulty loading an image sequence with PIL, any pointers ?
It seems like ImageSequence.Iterator should work, but I can't get it to work
https://pillow.readthedocs.io/en/3.0.x/reference/ImageSequence.html
Or is there a way to use imwri.Read to load the sequence, then apply the function? I couldn't get that to work either
_Al_
13th March 2020, 17:43
To load sequence of images,
Python could be used to get a list of your images, and then pass it in ModifyFrame instead of one image. You can select tupple of extensions, if more , it should load properly if named with some increase number pattern, you need import os as well, blankclip should match dimensions and length depending how many images there is, set fps numerator and fps denominator:
import PIL
import PIL.ImageCms
import numpy as np
import functools
import os
ext = (".jpg", ".tiff")
directory = r'G:\Photos\'
image_path_list = []
for file in os.listdir(directory):
if file.lower().endswith(tuple(ext)):
image_path = os.path.join(directory, file)
image_path_list.append(image_path)
clip_placeholder = core.std.BlankClip(width = 3648, height = 2736, fpsnum=60000, fpsden=1001, format= vs.RGB24, length=len(image_path_list))
rgbp = PIL.ImageCms.createProfile("sRGB")
def get_clip(n, f, image_path_list):
im = PIL.Image.open(image_path_list[n])
vsFrame = f.copy()
try:
iccp = im.info['icc_profile']
except KeyError as e:
npArray = np.array(im)
[np.copyto(np.asarray(vsFrame.get_write_array(i)), npArray[:, :, i]) for i in range(3)]
return vsFrame
#other part that treats if profile present
clip = core.std.ModifyFrame(clip_placeholder, clip_placeholder, functools.partial(get_clip, image_path_list=image_path_list))
clip.set_output()
also name for that function get_clip is misleading, it rather should be get_frame, to invoke what it returns, especially if working with images, that only one frame is returned using ModifyFrame, not clip
_Al_
13th March 2020, 18:43
Using imwri.Read creates a clip right? So that would be your clip_placeholder in your case and within that function, it would need to be changed to numpy, then, PIL's format:
clip_placeholder = clip #should be RGB
def get_clip(n, f):
vsFrame = f.copy()
npArray = np.dstack([np.array(f.get_read_array(i), copy=False) for i in range(3)])
im = PIL.Image.fromarray(npArray, 'RGB')
#.....
clip = core.std.ModifyFrame(clip_placeholder, clip_placeholder, get_clip)
clip.set_output()
age
15th March 2020, 01:54
It wouldn't be easier to use fmtconv and manually do the conversion inside vapoursynth?
poisondeathray
15th March 2020, 02:25
It wouldn't be easier to use fmtconv and manually do the conversion inside vapoursynth?
Yes.
And, I did try this before, with ProPhoto and AdobeRGB... but wrong colors...
I just revisited it, and it turns out it does work. I just did it incorrectly before.
The "trick" is to linearize the transfer function first, before applying the primaries correction, then adjusting the transfer to srgb
.
.
.
clip = core.fmtc.bitdepth (clip, bits=32)
clip = core.fmtc.transfer (clip, transs="adobergb", transd="linear")
clip = core.fmtc.primaries (clip, prims="adobe98", primd="srgb")
clip = core.fmtc.transfer (clip, transs="linear", transd="srgb")
#clip = core.fmtc.bitdepth (clip, bits=8)
clip.set_output()
lansing
15th March 2020, 05:20
Yes.
And, I did try this before, with ProPhoto and AdobeRGB... but wrong colors...
I just revisited it, and it turns out it does work. I just did it incorrectly before.
The "trick" is to linearize the transfer function first, before applying the primaries correction, then adjusting the transfer to srgb
.
.
.
clip = core.fmtc.bitdepth (clip, bits=32)
clip = core.fmtc.transfer (clip, transs="adobergb", transd="linear")
clip = core.fmtc.primaries (clip, prims="adobe98", primd="srgb")
clip = core.fmtc.transfer (clip, transs="linear", transd="srgb")
#clip = core.fmtc.bitdepth (clip, bits=8)
clip.set_output()
Memory spikes very high when doing this. On my 4200 x 3400 image, ModifyFrame uses 200 MB RAM while this one uses 860 MB.
poisondeathray
15th March 2020, 07:10
Memory spikes very high when doing this. On my 4200 x 3400 image, ModifyFrame uses 200 MB RAM while this one uses 860 MB.
You can use less memory when not using RGBS
The fmtc conversion is slightly more accurate for whatever reason even at RGB24 or RGB48 , but still consumes more memory
But at least there are more options, and image sequence loading is easier with imwri.Read
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.