我有一个处理数十个图像文件的脚本(使用Pillow)。最近,我注意到我的脚本因TIF(CMYK / 16)格式而失败。所以我创建了test case。
images = [
"cmyk-8.tif",
"cmyk-16.tif",
"rgb-8.tif",
"rgb-16.tif",
]
for img_name in images:
path = img_dir + "\\" + img_name
try:
img = Image.open(path)
except OSError as e:
print(e)
else:
print("success: " + img_name)
这会产生以下输出:
success: cmyk-8.tif
cannot identify image file '...\\cmyk-16.tif'
success: rgb-8.tif
success: rgb-16.tif
所以问题肯定在于TIF(CMYK / 16)格式。
如何打开此特定格式,或首先将其转换为可打开(?)格式(即RGB / 8,RGB / 16,CMYK / 8),然后将其打开?
在另一个QA中,建议GDAL解决问题。我tried it(安装GDAL,将其与Python相关联,并使其与当前脚本一起使用),但最终放弃了(太有问题)。所以我决定只关注gdal_translate。
我已经GISInternals安装了"gdal-203-1911-x64-core.msi"
,并尝试进行转换:
"C:\Program Files\GDAL\gdal_translate.exe" -scale -ot byte -of JPEG "C:\Users\%username%\Documents\GitHub\dump\python\tif-cmyk-16\images\cmyk-16.tif" "cmyk-16.jpg"
但它没有用。我得到了错误的转换:
我不熟悉GDAL,所以我一定做错了。如何让转换正确?
此外,这是cmd输出:
ERROR 1: Can't load requested DLL: C:\Program Files\GDAL\gdalplugins\ogr_MSSQLSpatial.dll
126: The specified module could not be found.
ERROR 1: Can't load requested DLL: C:\Program Files\GDAL\gdalplugins\ogr_MSSQLSpatial.dll
126: The specified module could not be found.
Input file size is 200, 200
0...10...20...30...40...50...60...70...80...90...100 - done.
Press any key to continue . . .
似乎缺少某些东西,而且我不知道inccorect转换是否与此相关。
可以找到相关脚本和输出文件here。
答案 0 :(得分:1)
以下是转换它的几种方法。前两个使用GDAL,因为你建议,最后一种方法使用libtiff,我认为它更适合你的用例。
来自命令行的GDAL
从纯命令行开始,我使用了两个命令和一个中间的tif。
首先将16位tif转换为8位tif
gdal_translate -scale -ot byte -of GTIFF cmyk-16.tif cmyk-out.tif -co PHOTOMETRIC=CMYK
文件 cmyk-out.tif 现在是8位。现在可以使用以下命令将其转换为jpeg
gdal_translate -of JPEG cmyk-out.tif cmyk-out.jpg
因此,您只需创建一个链接两个命令的批处理脚本(并可能删除中间的tif)
来自python的GDAL(和numpy和PIL)
如果问题似乎是PIL无法打开图像,则可以使用GDAL进行打开,将numpy用于转换为8位,将PIL用于转换为RGB。
from osgeo import gdal
import numpy as np
from PIL import Image
def reduceDepth(image, display_min, display_max):
image -= display_min
image = np.floor_divide(image, (display_min - display_max + 1) / 256)
image = image.astype(np.uint8)
return image
raster = gdal.Open("cmyk-16.tif")
c = raster.GetRasterBand(1).ReadAsArray()
m = raster.GetRasterBand(2).ReadAsArray()
y = raster.GetRasterBand(3).ReadAsArray()
k = raster.GetRasterBand(4).ReadAsArray()
cmyk = np.dstack((c, m, y, k))
cmyk8 = reduceDepth(cmyk, 0, 65536)
im = Image.fromarray(cmyk8)
im = im.convert('RGB')
im.save("cmyk-out.jpeg")
使用libtiff代替GDAL
您也可以使用libtiff打开tif而不是gdal。然后上面的脚本将如下所示
import numpy as np
from PIL import Image
from libtiff import TIFF
input = TIFF.open("cmyk-16.tif").read_image()
def reduceDepth(image, display_min, display_max):
image -= display_min
image = np.floor_divide(image, (display_min - display_max + 1) / 256)
image = image.astype(np.uint8)
return image
v8 = reduceDepth(input, 0, 65536)
im = Image.fromarray(v8)
im = im.convert('RGB')
im.save("cmyk-out.jpeg")