如何用Python实现图像拼接画(把一堆小图拼成大图)

诸神缄默不语-个人CSDN博文目录

在这里的图像拼接画指的是一张大图由很多小图组成,效果就像这样:
在这里插入图片描述

原理:将大图拆成很多小块,每一块计算平均颜色,用平均颜色最相近的小图来替代,就可以。
直接遍历就可以,也就跑几个小时。如果想要加速的话可以考虑研究一下用多线程或者多进程来实现。

注意本博文中涉及的实验都是在Windows平台上实现的,如果要转成其他系统需要尤其注意文件路径格式。

1. 预处理小图:计算每张图的平均颜色,并放到一个新的文件夹中

jupyter notebook格式的代码文件:https://github.com/PolarisRisingWar/all-notes-in-one/blob/main/小图拼大图1-计算小图平均RGB颜色.ipynb

我是直接用CIFAR10的图片来作为小图了。

CIFAR10我是之前做PyTorch 60分钟速成的时候就下载过。这个教程我写过笔记:60分钟闪击速成PyTorch(Deep Learning with PyTorch: A 60 Minute Blitz)学习笔记
下载的核心代码是:

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,  download=True, transform=transform)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,  download=True, transform=transform)

代码:
调包→设置参数和工具函数→展示示例图片

import pickle

import numpy as np
import matplotlib.pyplot as plt

def unpickle(file):
    """cifar10数据官方提供的导入代码"""
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict

#设置参数
cifar10_path=r'data\cifar-10-batches-py'
cifar10_file_name=[r'\data_batch_'+str(i) for i in range(1,6)]
cifar10_file_name.append(r'\test_batch')

cifa10_avgcolor_folder=r"data\cifar10-avgcolor"

#展示一张示例图
p='data\cifar-10-batches-py\data_batch_1'
d=unpickle(p)
 
e=d[b'data']
for i in range(100):
    image=e[i]
    red_image=image[:1024].reshape(32,32)
    green_image=image[1024:2048].reshape(32,32)
    blue_image=image[2048:].reshape(32,32)
    result_img=np.ones((32, 32, 3), dtype=np.uint8)
    result_img[:,:,0]=red_image
    result_img[:,:,1]=green_image
    result_img[:,:,2]=blue_image
    plt.imshow(result_img)
    break

在这里插入图片描述

%%time
#遍历所有图片,计算其平均RGB颜色,将其分别存储至对应文件中
for file_name in cifar10_file_name:  #遍历所有batch
    cifar10_batch=cifar10_path+file_name  #该batch对应的路径
    cifar10_batch_unpickle=unpickle(cifar10_batch)
    file_r=open(cifa10_avgcolor_folder+"\\"+file_name+'_r',mode='w')
    file_g=open(cifa10_avgcolor_folder+"\\"+file_name+'_g',mode='w')
    file_b=open(cifa10_avgcolor_folder+"\\"+file_name+'_b',mode='w')
    for picture in cifar10_batch_unpickle[b'data']:
        file_r.write(str(np.mean(picture[:1024]))+'\n')
        file_g.write(str(np.mean(picture[1024:2048]))+'\n')
        file_b.write(str(np.mean(picture[2048:]))+'\n')
    file_r.close()
    file_g.close()
    file_b.close()

2. 用小图拼大图

jupyter notebook格式的代码文件:https://github.com/PolarisRisingWar/all-notes-in-one/blob/main/小图拼大图2.ipynb

大图原始图像是我从网上随便找的一张刘亦菲的写真:
在这里插入图片描述
代码:
调包→设置参数和功能函数→展示大图原图

#导包
import pickle

from PIL import Image

import numpy as np
import matplotlib.pyplot as plt

def unpickle(file):
    """cifar10数据官方提供的导入代码"""
    with open(file, 'rb') as fo:
        dict = pickle.load(fo, encoding='bytes')
    return dict

#参数配置
portrait_path=r'liuyifei.jpeg'

block=5  #5*5为一个色块

#小图
cifar10_path=r'data\cifar-10-batches-py'
cifar10_file_names=[r'\data_batch_'+str(i) for i in range(1,6)]
cifar10_file_names.append(r'\test_batch')

cifa10_avgcolor_folder=r"data\cifar10-avgcolor"

#展示原图
portrait_picture=Image.open(portrait_path)
plt.imshow(portrait_picture)

在这里插入图片描述

将图片加载到内存中→设置图像拼接的功能函数

#将图片转换为np.ndarray
portrait_matrix=portrait_picture.convert("RGB")
portrait_ndarray = np.array(portrait_matrix)

#将小图的RGB加载到内存中
little_rgbs={}
for file_name in cifar10_file_names:
    with open(cifa10_avgcolor_folder+"\\"+file_name+'_r') as f:
        little_rgbs[file_name+'_r']=f.readlines()
    with open(cifa10_avgcolor_folder+"\\"+file_name+'_g') as f:
        little_rgbs[file_name+'_g']=f.readlines()
    with open(cifa10_avgcolor_folder+"\\"+file_name+'_b') as f:
        little_rgbs[file_name+'_b']=f.readlines()

#将小图的batch加载到内存中
cifar10_batches=[]
for file_name in cifar10_file_names:  #遍历所有batch
    cifar10_batch=cifar10_path+file_name  #该batch对应的路径
    cifar10_batches.append(unpickle(cifar10_batch)[b'data'])

def convert_smalls_to_big(block_dim:int):
    """
    将一堆小图转换为大图,入参为大图色块的维度,返回新图
    """
    old_shape=portrait_ndarray.shape
    heng_dim=int(old_shape[0]/block_dim)
    zong_dim=int(old_shape[1]/block_dim)
    new_picture=np.ndarray(shape=(heng_dim*32,zong_dim*32,3),dtype=np.int16)
    for i in range(heng_dim):
        for j in range(zong_dim):
            old_matrix=portrait_ndarray[i*block_dim:(i+1)*block_dim,j*block_dim:(j+1)*block_dim,:]
            r=np.mean(old_matrix[:,:,0])
            g=np.mean(old_matrix[:,:,1])
            b=np.mean(old_matrix[:,:,2])
            
            least_distance=450  #理论最大值应该是np.sqrt(255*255+255*255+255*255)≈442
            least_distance_batch_index=0
            least_distance_picture_index=0
            
            for index in range(6):
                #遍历每一个batch
                for picture_index in range(len(cifar10_batches[index])):
                    #遍历每一张小图,找到平均RGB跟色块RGB最相近的小图,用这个小图来顶替大图的对应色块
                    little_r=float(little_rgbs[cifar10_file_names[index]+'_r'][picture_index])
                    little_g=float(little_rgbs[cifar10_file_names[index]+'_g'][picture_index])
                    little_b=float(little_rgbs[cifar10_file_names[index]+'_b'][picture_index])
                    distance=np.sqrt((little_r-r)**2+(little_g-g)**2+(little_b-b)**2)
                    if distance<least_distance:
                        least_distance=distance
                        least_distance_batch_index=index
                        least_distance_picture_index=picture_index
            little_picture=cifar10_batches[least_distance_batch_index][least_distance_picture_index]
            new_picture[i*32:(i+1)*32,j*32:(j+1)*32,0]=np.reshape(little_picture[:1024],(32,32)).copy()
            new_picture[i*32:(i+1)*32,j*32:(j+1)*32,1]=little_picture[1024:2048].reshape(32,32)
            new_picture[i*32:(i+1)*32,j*32:(j+1)*32,2]=little_picture[2048:].reshape(32,32)
    plt.imshow(new_picture)
    plt.savefig("picture1.png")

拼接图像:

%%time
convert_smalls_to_big(block)

Wall time: 1h 23min 27s
在这里插入图片描述

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸神缄默不语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值