使用PIL调整图片分辨率
需求:
因项目需求中有对照片分辨率的具体要求,需要进行已有照片的批量分辨率处理。已有照片统一为1024*768分辨率,要求处理成320*240 / 240*200两种分辨率形式。
难点:
对方要求中的240*200分辨率大小与我们已有照片分辨率不是同一个比例的。
解决方案:
如果直接resize(240,200)后,结果必要会存在变形的情况,那么需要考虑对目标进行裁剪。方法是先按较大的边进行等比例压缩,压缩后再根据目标比例选取中间区域进行裁剪。
# -*- coding:utf-8 -*- """批量调整照片大小 """ __author__ = fatway __email__ = fatway#gmail.com VERSION = "Photo Resizer v1.0 build 2010-8-25" import os import sys import time import glob import Image class PicResizer: """根据指定的目录,对该目录下的所有照片进行大小调整 """ def __init__(self, picpath, bakpath): '''初始化参数''' self.picpath = picpath self.bakpath = bakpath logfile = bakpath + "/log" + time.strftime("%Y%m%d%H%M") + ".txt" self.log = open(logfile, "a") def pic_walker(self, path): '''获取指定目录下的所有JPG照片,不递归深入查找''' target = [] for files in glob.glob(path + "/*.jpg"): filepath,filename = os.path.split(files) # todo: mark target.append(filename) return target def check_folder(self, subFolderName): '''检查目标文件夹是否存在,不存在则创建之''' foldername = self.bakpath + '/' + subFolderName print foldername if not os.path.isdir(foldername): os.mkdir(foldername) #return 0 return foldername def pic_info(self, img): '''获取照片的尺寸''' w, h = img.size if w>h: return w, h, 0 # 横版照片 else: return w, h, 1 # 竖版照片 def comp_num(self, x, y): '''比较两个实数 如果是用直接比较话会出现经典的整数除得0问题 ''' x = float(x) y = float(y) return float(x/y) def pic_resize(self, picname, p_w, p_h): '''根据设定的尺寸,对指定照片进行像素调整''' # 获取指定照片的规格,一般是1024,768 img = Image.open(picname) w, h, isVertical = self.pic_info(img) # 判断照片横竖,为竖版的话对调w,h if isVertical: p_w, p_h = p_h, p_w # 如果照片调整比例合适,直接输出 if self.comp_num(p_h, p_w) == self.comp_num(h, w): target = img.resize( (int(p_w), int(p_h)), Image.ANTIALIAS # hack: 参数呐!高保真必备! ) # ANTIALIAS: a high-quality downsampling filter # BILINEAR: linear interpolation in a 2x2 environment # BICUBIC: cubic spline interpolation in a 4x4 environment return target # 比例不合适就需要对照片进行计算,保证输出照片的正中位置 # 算法灵感来源于ColorStrom if self.comp_num(p_h, p_w) > self.comp_num(h, w): # 240/320 > 360/576 偏高照片的处理 # 以高为基准先调整照片大小 p_w_n = p_h * self.comp_num(w,h) # 根据新高按比例设置新宽 temp_img = img.resize( (int(p_w_n), int(p_h)), Image.ANTIALIAS ) # 获取中间选定大小区域 c = (p_w_n - p_w)/2 # 边条大小 box = (c, 0, c+p_w, p_h) # 选定容器 box = tuple(map(int, box)) # 转换成crop需要的int形参数 target = temp_img.crop(box) return target else: # 偏宽的照片 # 以宽为基准先调整照片大小 p_h_n = p_w * self.comp_num(h, w) # 根据新宽按比例设置新高 temp_img = img.resize( (int(p_w), int(p_h_n)), Image.ANTIALIAS ) # 获取新图像 c = (p_h_n - p_h)/2 box = (0, c, p_w, c+p_h) box = tuple(map(int, box)) target = temp_img.crop(box) return target def run_auto(self, *args): '''运行调整照片尺寸进程 接纳规格列表,每个规格为一个tuple ''' # 获取所有图片列表 imglist = self.pic_walker(self.picpath) # 处理照片 for img in imglist: imgfile = self.picpath + "/" + img # 完整照片名称 try: for std in args: w, h = std[0], std[1] # 获取目标照片规格 # 定义目标文件 opfile = self.check_folder(str(w)+"x"+str(h)) + "/" + img tempimg = self.pic_resize(imgfile, int(w), int(h)) tempimg.save(opfile, 'jpeg') #self.log.write(str(img) + "\tOK\n") except: self.log.write(str(img) + "\tErr\n") print '-->' + img print "Done." def main(): '''主函数''' # picpath = bakpath = raw_input("type your photo's path:") # 修改源照片文件夹路径 picpath = "E:/BB_Exchange" # 修改为你的目标路径 bakpath = "E:/BB_Exchange" # 实例一个进程并运行 resizer = PicResizer(picpath, bakpath) resizer.run_auto((320, 240),(240,200)) if __name__ == "__main__": sys.exit(main())