您的位置:首页 > 健康 > 美食 > 【Python 项目】照片马赛克 - 3

【Python 项目】照片马赛克 - 3

2024/10/6 6:05:33 来源:https://blog.csdn.net/htb61888/article/details/140478917  浏览:    关键词:【Python 项目】照片马赛克 - 3

照片马赛克 - 3

  • 完整代码
    • 运行程序

完整代码

import sys, os, random, argparse
from PIL import Image
import imghdr
import numpy as npdef getAverageRGB(image):"""return the average color value as (r, g, b) for each input image"""# 用 numpy 将每个 Image 对象转换为数据数组。返回的 numpy 数组形为(w, h, d)im = np.array(image)# 保存 shape 元组,然后计算平均 RGB值,将这个数组变形为更方便的形状(w*h, d)w,h,d = im.shape# 用 numpy.average()计算出使用平均值return tuple(np.average(im.reshape(w*h, d), axis=0))def splitImage(image, size):"""given the image and dimensions (rows, cols), return an m*n list of images"""W, H = image.size[0], image.size[1] # 得到目标图像的维度m, n = size # 得到尺寸w, h = int(W/n), int(H/m) # 用基本除法计算目标图像中每一小块的尺寸# image listimgs = []# generate a list of dimensionsfor j in range(m):for i in range(n):# append cropped imageimgs.append(image.crop((i*w, j*h, (i+1)*w, (j+1)*h)))return imgsdef getImages(imageDir):"""用 os.listdir()将 imageDir 目录中的文件放入一个列表"""files = os.listdir(imageDir)images = []for file in files:# os.path.abspath()和 os.path.join()来获取图像的完整文件名filePath = os.path.abspath(os.path.join(imageDir, file))try:# 用 open()打开图像文件。在随后的几行中,将文件句柄传入 Image.open(),将得到的图像 im 存入一个数组fp = open(filePath, "rb")im = Image.open(fp)images.append(im)# 调用 Image.load(),强制加载 im 中的图像数据im.load()# 关闭文件句柄,释放系统资源fp.close()except:# skipprint("Invalid image: %s" % (filePath,))return imagesdef getImageFilenames(imageDir):files = os.listdir(imageDir)filenames = []for file in files:filePath = os.path.abspath(os.path.join(imageDir, file))try:imgType = imghdr.what(filePath)if imgType:filenames.append(filePath)except:print("Invalid image: %s" % (filePath,))return filenamesdef getBestMatchIndex(input_avg, avgs):"""return index of the best image match based on average RGB value distance"""# input image averageavg = input_avg# get the closest RGB value to input, based on RGB distanceindex = 0 # 将最接近的匹配下标初始化为 0,最小距离初始化为无穷大min_index = 0 min_dist = float("inf")for val in avgs: # 遍历平均值列表中的值# 用标准公式计算距离dist = ((val[0] - avg[0])*(val[0] - avg[0]) + (val[1] - avg[1])*(val[1] - avg[1]) + (val[2] - avg[2])*(val[2] - avg[2]))if dist < min_dist: #如果计算的距离小于保存的最小距离 min_dist,它就被替换为新的最小距离min_dist = distmin_index = indexindex += 1 return min_indexdef createImageGrid(images, dims):"""given a list of images and a grid size (m, n), create a grid of images"""m, n = dims # 取得网格的尺寸,然后用 assert 检查,提供给 createImageGrid()的图像数量是否符合网格的大小# sanity checkassert m*n == len(images)# 计算小块图像的最大宽度和高度# don't assume they're all equalwidth = max([img.size[0] for img in images])height = max([img.size[1] for img in images])# 创建一个空的 Image,大小符合网格中的所有图像grid_img = Image.new('RGB', (n*width, m*height))# paste the tile images into the image gridfor index in range(len(images)):row = int(index/n)col = index - n*rowgrid_img.paste(images[index], (col*width, row*height)) # 循环遍历选定的图像,利用 Image.paste()方法,将它们粘贴到相应的网格中return grid_imgdef createPhotomosaic(target_image, input_images, grid_size, reuse_images=True):"""creates a photomosaic given target and input images"""print('splitting input image...')# split the target image into tilestarget_images = splitImage(target_image, grid_size)print('finding image matches...')# for each tile, pick one matching input imageoutput_images = []# for user feedbackcount = 0 batch_size = int(len(target_images)/10)# calculate the average of the input imageavgs = []for img in input_images:avgs.append(getAverageRGB(img))for img in target_images:# compute the average RGB value of the imageavg = getAverageRGB(img)# find the matching index of closest RGB value# from a list of average RGB valuesmatch_index = getBestMatchIndex(avg, avgs)output_images.append(input_images[match_index])# user feedbackif count > 0 and batch_size > 10 and count % batch_size is 0:print('processed %d of %d...' %(count, len(target_images)))count += 1 # remove the selected image from input if flag setif not reuse_images:input_images.remove(match)print('creating mosaic...')# create photomosaic image from tilesmosaic_image = createImageGrid(output_images, grid_size)# display the mosaicreturn mosaic_imagedef main():# parse argumentsparser = argparse.ArgumentParser(description='Creates a photomosaic frominput images')# add argumentsparser.add_argument('--target-image', dest='target_image', required=True)parser.add_argument('--input-folder', dest='input_folder', required=True)parser.add_argument('--grid-size', nargs=2, dest='grid_size', required=True)parser.add_argument('--output-file', dest='outfile', required=False)args = parser.parse_args()target_image = Image.open(args.target_image)print('reading input folder...')input_images = getImages(args.input_folder)if input_images == []:print('No input images found in %s. Exiting.' % (args.input_folder, ))exit()random.shuffle(input_images)grid_size = (int(args.grid_size[0]), int(args.grid_size[1]))output_filename = 'mosaic.png'if args.outfile:output_filename = args.outfilereuse_images =Trueresize_input = Trueprint('starting photomosaic creation...')if not reuse_images:if grid_size[0]*grid_size[1] > len(input_images):print('grid size less than number of images')exit()if resize_input:print('resizing images...')# for given grid size, compute the maximum width and height of tilesdims = (int(target_image.size[0]/grid_size[1]),int(target_image.size[1]/grid_size[0]))print("max tile dims: %s" % (dims,))# resizefor img in input_images:img.thumbnail(dims)mosaic_image = createPhotomosaic(target_image, input_images, grid_size, reuse_images)mosaic_image.save(output_filename, 'PNG')print("saved output to %s" % (output_filename,))print('done.')if __name__ == '__main__':main()

运行程序

在本文件所在目录打开终端,输入:

python photomosaic.py --target-image cherai.jpg --input-folder test-data/set6/ --grid-size 128 128

其中 photomosaic.py是本文件名,cherai.jpg是输入图像的名称,**test-data/set6/**是输入图像所在的文件夹,128 128是网格尺寸,可根据需要自行更改。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com