如何打开TIF(CMYK,16位)图像文件?

时间:2018-06-08 12:47:46

标签: python windows pillow gdal

我有一个处理数十个图像文件的脚本(使用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"

但它没有用。我得到了错误的转换:

output comparison

我不熟悉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

1 个答案:

答案 0 :(得分:1)

似乎其他图像正在工作,所以我将重点放在16位cmyk tif转换为8位rgb jpeg上。我想这种方法也适用于其他转换,只需进行一些调整。

以下是转换它的几种方法。前两个使用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")