跳转至

暴力法调整 PNG 图像尺寸

原文链接: https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/brute-force-png-image-sizing

11403 给这篇文章评分:

3.3

暴力法调整 PNG 图像尺寸

匿名作者 2016年6月30日,星期四

最近,我参与了一个项目,该项目的输出 .png 文件有非常严格的最大尺寸限制。起初这似乎不是什么大问题,直到我意识到在创建图像之前,要计算 .png 文件的最终大小极其困难。长话短说,这促使我创建了一种暴力方法,用于寻找输出图像的最佳尺寸。

顺便提一句,我知道你们在想什么,“既然这么困难,为什么不选择几个尺寸尝试一下,然后建立一个线性模型,这样以后就不用再处理这个问题了?”嗯,我试过了,但行不通。从图1和图2可以看出,这既不是简单的线性关系,也不是容易预测的关系。图1和图2中的蓝线代表了文件大小与图像像素数量的关系;而红线则是简单的线性回归。可以看出,数据点与趋势线存在明显的偏差。

图 1

图 2

回到手头的任务:暴力法。这个方法相对简单:

  1. 以图像的原始尺寸保存(如果它小于允许的最大尺寸,那么任务就完成了)。
  2. 将原始图像尺寸减小一半,并检查文件大小。
  3. 如果文件大于允许的大小,则取原始图像尺寸的四分之一,换句话说,就是取上一个计算出的过大值(即初始图像尺寸的50%)与上一个计算出的最小尺寸值(因为这是第一次迭代,最小的图像尺寸尚未计算,所以将其设置为零)之间距离的一半。
  4. 如果文件小于允许的大小,则取原始文件尺寸的四分之三,或者取上一个计算出的最大图像尺寸(在本例中是原始图像尺寸)与上一个计算出的最小图像尺寸(即原始尺寸的一半)之间距离的一半。
  5. 继续这种模式,每次取一个要么大于、要么小于刚刚计算的中间点的值。每次都要确保使用整数或长整型值来计算行数和样本数。
  6. 每次迭代后,检查是否已经测试过相同的图像尺寸,如果是,那么这就是最终的图像尺寸,并且已经找到了最优解。

下面的示例应该能更清楚地说明这个执行过程。

;启动应用程序

e = ENVI()

;打开输入文件

File = Filepath('qb_boulder_msi', Subdir=['data'], $

Root_Dir=e.Root_Dir)

Raster = e.OpenRaster(File)

;从 ENVI 任务目录中获取任务

Task = ENVITask('ISODATAClassification')

;定义输入

Task.Input_Raster = Raster

;运行任务

Task.Execute

;提取新的 ISODATA 栅格

ISORaster = Task.OUTPUT_RASTER

;获取元数据

metadata = ISORaster.Metadata

;获取新文件的信息

nb = ISORaster.nb

Raster_ns = ISORaster.ns

Raster_nl = ISORaster.nl

;设置输出文件的文件名

output_file = 'C:\Output\PNG_Test.png'

;设置期望的输出大小(字节)

output_size = 150000

;删除任何同名的旧文件

FILE_DELETE, output_file,/ALLOW_NONEXISTENT

;将图像保存为我们的初始测试

;从 ENVI 任务目录中获取任务

ERTP_Task = ENVITask('ExportRasterToPNG')

;定义输入

ERTP_Task.INPUT_RASTER = ISORaster

;定义输出

ERTP_Task.OUTPUT_URI = output_file

;运行任务

ERTP_Task.Execute

;关闭 PNG 栅格

ERTP_Task.Output_Raster.close

;获取新文件的大小

file_size = ((file_info(output_file)).size) * 1.

;为最大样本数和行数创建一个容器

max_ns = Raster_ns

max_nl = Raster_nl

;为当前样本数和行数创建一个容器

nl = Raster_nl

ns = Raster_ns

;为最小样本数和行数创建一个容器

min_ns = 0

min_nl = 0

;创建一个容器,用于存储图像右下角相对于最大图像尺寸的一维索引值

loc_1d = []

;检查以确保当前图像过大

if file_size gt output_size then begin

;检查相同的图像尺寸是否多次出现。如果是,则停止迭代

while ((where(loc_1d eq (nl * Raster_ns +ns)))[0] eq -1do begin

;以 1D 形式记录图像的宽度和高度

loc_1d = [loc_1d, nl * Raster_ns + ns]

;决定哪一侧的值应该被分成两半

if (file_size gt output_size) then side = 'right'

if (file_size lt output_size) then side = 'left'

case side of

;图像过大,必须减小尺寸

'right' : begin

; 确定图像的新尺寸(即上限值减去当前值的一半)

ns = max_ns - ((max_ns - min_ns)* .5)

nl = max_nl - ((max_nl - min_nl)* .5)

; 删除旧图像

FILE_DELETE, output_file,/ALLOW_NONEXISTENT

; 缩小原始图像

; 从 ENVI 任务目录中获取任务

DRR_Task=ENVITask('DimensionsResampleRaster')

; 定义输入

DRR_Task.INPUT_RASTER =ISORaster

DRR_Task.DIMENSIONS=[ns,nl]

; 运行任务

DRR_Task.Execute

ns = DRR_Task.Output_Raster.ns

nl = DRR_Task.Output_Raster.nl

; 从 ENVI 任务目录中获取任务

ERTP_Task = ENVITask('ExportRasterToPNG')

; 定义输入

ERTP_Task.INPUT_RASTER =DRR_Task.Output_Raster

; 定义输出

ERTP_Task.OUTPUT_URI =output_file

; 运行任务

ERTP_Task.Execute

; 关闭重采样后的栅格

DRR_Task.Output_Raster.close

; 关闭 PNG 栅格

ERTP_Task.OUTPUT_Raster.close

; 获取新文件的大小

file_size = ((file_info(output_file)).size)* 1.

; 将新尺寸记录为上限

max_ns = ns

max_nl = nl

end

'left' : begin ; 太小

; 确定图像的新尺寸(即上限值减去当前值的1.5倍)

ns = ((max_ns - min_ns)* 1.5) + max_ns

nl = ((max_nl - min_nl)* 1.5 )+ max_nl

; 删除旧图像

FILE_DELETE, output_file,/ALLOW_NONEXISTENT

; 缩小原始图像

; 从 ENVI 任务目录中获取任务

DRR_Task=ENVITask('DimensionsResampleRaster')

; 定义输入

DRR_Task.INPUT_RASTER =ISORaster

DRR_Task.DIMENSIONS=[ns,nl]

; 运行任务

DRR_Task.Execute

; 记录新图像的尺寸

dims = size(test_img,/DIMENSIONS)

ns = DRR_Task.OUTPUT_RASTER.ns

nl = DRR_Task.OUTPUT_RASTER.nl

; 保存新图像并测试大小

; 从 ENVI 任务目录中获取任务

ERTP_Task = ENVITask('ExportRasterToPNG')

; 定义输入

ERTP_Task.INPUT_RASTER =DRR_Task.Output_Raster

; 定义输出

ERTP_Task.OUTPUT_URI =output_file

; 运行任务

ERTP_Task.Execute

; 关闭重采样后的栅格

DRR_Task.Output_Raster.close

; 关闭 PNG 栅格

ERTP_Task.OUTPUT_Raster.close

; 记录新文件的大小

file_size = ((file_info(output_file)).size)* 1.

; 将旧尺寸记录为下限

min_ns = max_ns

min_nl = max_nl

; 将新尺寸记录为上限

max_ns = ns

max_nl = nl

end

endcase

endwhile

endif

;关闭初始栅格

ISORaster.close





 

IDL 关键字转发隐患 使用 Lanczos 核上采样图像