我正在尝试将TIFF图像存档在数据库中,我想尽可能地压缩图像,即使以更高的CPU使用率和高内存为代价。
为了测试LibTiff.NET中可用的压缩,我使用了以下代码(从this sample修改):
//getImageRasterBytes and convertSamples are defined in the sample
void Main() {
foreach (Compression cmp in Enum.GetValues(typeof(Compression))) {
try {
using (Bitmap bmp = new Bitmap(@"D:\tifftest\200 COLOR.tif")) {
using (Tiff tif = Tiff.Open($@"D:\tifftest\output_{cmp}.tif", "w")) {
byte[] raster = utils.getImageRasterBytes(bmp, PixelFormat.Format24bppRgb);
tif.SetField(TiffTag.IMAGEWIDTH, bmp.Width);
tif.SetField(TiffTag.IMAGELENGTH, bmp.Height);
tif.SetField(TiffTag.COMPRESSION, cmp);
tif.SetField(TiffTag.PHOTOMETRIC, Photometric.RGB);
tif.SetField(TiffTag.ROWSPERSTRIP, bmp.Height);
tif.SetField(TiffTag.XRESOLUTION, bmp.HorizontalResolution);
tif.SetField(TiffTag.YRESOLUTION, bmp.VerticalResolution);
tif.SetField(TiffTag.BITSPERSAMPLE, 8);
tif.SetField(TiffTag.SAMPLESPERPIXEL, 3);
tif.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
int stride = raster.Length / bmp.Height;
utils.convertSamples(raster, bmp.Width, bmp.Height);
for (int i = 0, offset = 0; i < bmp.Height; i++) {
tif.WriteScanline(raster, offset, i, 0);
offset += stride;
}
}
}
} catch (Exception ex) {
//code was run in LINQPad
ex.Dump(cmp.ToString());
}
}
}
测试图像为200dpi 24bpp,宽度为1700,高度为2200,并使用LZW压缩;文件大小接近7 MB。 (图像代表我想要存储的图像。)
在有效的算法(some failed with various errors)中,最小的压缩文件是使用Compression.Deflate
创建的,但只压缩到5MB,我希望它明显更小(小于1 MB)。
必须有一些更高压缩的算法;包含此图像的PDF文件类似于500Kb。
如果特定算法与其他TIFF查看器/库不兼容,这不是问题,只要我们可以从数据库中提取压缩的TIFF并使用LibTiff.Net将其转换为System.Drawing.Bitmap
或某些其他图书馆。
如何使用无损压缩生成更小的文件?这些图像甚至可以实现吗?
更新
答案 0 :(得分:3)
只是在示例图像(tiff one)上给出一些数字。所有压缩都是无损的,可以重新创建任何其他无损格式,如bmp / png(已经过检查)。
tiff-orig 5.779.814
png (unoptimized) 3.084.641 53.37%
png (optimized) 2.795.230 48.36%
png (zopfli) 2.791.680 48.30%
jpeg2000 2.230.967 38.60%
webp 2.021.710 34.98% BSD
gralic 1.795.457 31.06%
flif 1.778.976 30.78% LGPL3
由于噪声是杀死无损压缩电位的最重要因素,让我们删除一些。我们正在使用这个基于python的代码执行此操作,但还有更多可能的方法。以下代码使用非线性滤波器,它试图在保持重要边缘的同时消除噪声。
当然信息在这里丢失了,但我实际上更喜欢去噪图像,因为它更好看(在我看来)。
from skimage.io import imread, imsave
from skimage.restoration import denoise_bilateral
img = imread("200 DPI.tif")
img_denoised = denoise_bilateral(img, multichannel=True, sigma_range=0.05, sigma_spatial=15)
imsave("200 DPI_denoised.png", img_denoised)
flif (denoised) 1.140.497 19.73%
答案 1 :(得分:1)
答案的两个部分:
以您选择的方式使其有损,而不是有损编解码器的方式。例如,如果您正在处理扫描的文本图像,请执行亮度/对比度标准化(可能是局部标准化),以使页面背景为纯白色。这将大大提高可压缩性;它可以制作一个10MB灰度文本页面,几乎但不完全是白色背景,分为200kB页面,纯白色背景和灰度文本(使用LZW)
使用JPEG2000。如果你想要最好的无损压缩,那么带有无损设置的JPEG2000可能会击败任何其他算法,例如PNG,特别是对于像照片这样的内容,也适用于扫描页面。将JPEG2000存储在TIFF容器中也应该是可能的,但它不是TIFF库的常见功能。你可能想要也可能不想那样做。我认为JPEG2000在一个文件中也有多个图像的功能。
答案 2 :(得分:0)
阅读G4压缩方法: https://en.wikipedia.org/wiki/Group_4_compression
平均来说,该方法可以提供20:1的压缩率。
这是C#示例(信用到:https://www.experts-exchange.com/viewCodeSnippet.jsp?codeSnippetId=20-41218205-1):
byte[] imgBits = File.ReadAllBytes(@"multipage_tif.tif");
using (MemoryStream ms = new MemoryStream(imgBits)) {
using (Image i = Image.FromStream(ms)) {
EncoderParameters parms = new EncoderParameters(1);
ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders().FirstOrDefault(decoder => decoder.FormatID == ImageFormat.Tiff.Guid);
parms.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionCCITT4);
i.Save("out.tif", codec, parms);
}
}