使用Python拼合多张图像

Python的PIL库提供了操作图像文件的接口。通过该接口提供的函数,可以实现多张分散图像的拼合。

该算法总体流程如下:

  1. 构建需要拼合的图像文件路径列表。
  2. 计算拼合后图像的尺寸,并调用PIL.Image.new()函数构建拼合后的目标图像对象。
  3. 初始化定位指针等辅助变量。
  4. 遍历待拼合的图像文件路径列表,并:
    1. 调用PIL.Image.open()函数,打开源图像。
    2. 使用PIL.Image.crop()PIL.Image.resize()等函数,对源图像进行预处理。
    3. 在目标图像对象上调用PIL.Image.paste()方法,将源图像粘贴到目标图像上。该方法的im参数为源图像对象,box参数为一个四元组或二元组,描述了源图像粘贴到目标图像时左上角相对于目标图像左上角的坐标位置。
    4. 在源图像上调用PIL.Image.close()方法,关闭源图像并释放资源。
    5. 更新定位指针等辅助变量。
  5. 在完成拼合的目标图像上调用PIL.Image.save()方法,将拼合后的图像保存到文件中。
  6. 关闭目标图像以释放资源,或传递目标图像给上层调用者。

示例代码:该代码以平铺方式拼合具有相同尺寸的图像:

import PIL
 
# Concatenating images into one large image
def ConcatenateImages(arrImagePaths : array, nRowCount : int = 1, nColCount : int = 1,
    UseVerticalArrangement : bool = False, sOriginPoint : str = "TopLeft",
    SaveConcatenatedImage : bool = False, sSaveDirectory : str = "./", sFileNamePrefix : str = "",
    CloseConcatenatedImagesWhenReturning : bool = False) -> array :
 
    # Calculate count of concatenated images
    nImagesPerFrame = nRowCount * nColCount
    nConcatenatedImage = math.ceil(len(arrImagePaths) / nImagesPerFrame)
 
    # Create result buffer
    arrConcatenatedImages = []
 
    # Creating concatenated images
    for ImgID in range(0, nConcatenatedImage) :
        # Create image buffer
        imgCurrentImage = PIL.Image.new("RGBA", (100,100))
        if sOriginPoint.upper() == "TOPRIGHT" :
            iCurrentRowPointer = 0
            iCurrentColPointer = nColCount - 1
        elif sOriginPoint.upper() == "BOTTOMLEFT" :
            iCurrentRowPointer = nRowCount - 1
            iCurrentColPointer = 0
        elif sOriginPoint.upper() == "BOTTOMRIGHT" :
            iCurrentRowPointer = nRowCount - 1
            iCurrentColPointer = nColCount - 1
        else :
            iCurrentRowPointer = 0
            iCurrentColPointer = 0
        #End If
 
        # Size information
        tplSourceSize = (0,0)
        tplTargetSize = (0,0)
        sSourceMode = "Unknown"
 
        # Concatenating images
        for ChildImgID in range(ImgID * nImagesPerFrame, (ImgID + 1) * nImagesPerFrame) :
            # Check if image is listed
            if ChildImgID >= len(arrImagePaths) :
                # If current index is out of range, create a dummy image
                imgChildImageToAdd = PIL.Image.new(sSourceMode, tplSourceSize)
            else :
                # Open image
                imgChildImageToAdd = PIL.Image.open(arrImagePaths[ChildImgID])
            #End If
 
            # Update size info or resize image
            if tplSourceSize == (0,0) :
                # If size is not set, use the first image's attribute as base size
                tplSourceSize = imgChildImageToAdd.size
                tplTargetSize = (tplSourceSize[0] * nColCount, tplSourceSize[1] * nRowCount)
                sSourceMode = imgChildImageToAdd.mode
                print(f"Source size is {tplSourceSize[0]} x {tplSourceSize[1]}, target size is {tplTargetSize[0]} x {tplTargetSize[1]}, using {sSourceMode} mode.")
 
                # Re-create target image
                imgCurrentImage.close()
                imgCurrentImage = PIL.Image.new(sSourceMode, tplTargetSize)
            else :
                # Resize image if needed
                if imgChildImageToAdd.size != tplSourceSize :
                    imgChildImageToAdd = imgChildImageToAdd.resize(size=tplSourceSize)
                #End If
            #End if
 
            # Paste current image to target
            tplPastePos = (iCurrentColPointer * tplSourceSize[0], iCurrentRowPointer * tplSourceSize[1])
            imgCurrentImage.paste(imgChildImageToAdd, tplPastePos)
 
            # Close opened source image
            imgChildImageToAdd.close()
 
            # Update pointers
            if sOriginPoint.upper() == "TOPRIGHT" :
                if UseVerticalArrangement :
                    iCurrentRowPointer = iCurrentRowPointer + 1
                    if iCurrentRowPointer >= nRowCount :
                        iCurrentRowPointer = 0
                        iCurrentColPointer = iCurrentColPointer - 1
                else :
                    iCurrentColPointer = iCurrentColPointer - 1
                    if iCurrentColPointer < 0 :
                        iCurrentRowPointer = iCurrentRowPointer + 1
                        iCurrentColPointer = nColCount - 1
                    #End If
                #End If
            elif sOriginPoint.upper() == "BOTTOMLEFT" :
                if UseVerticalArrangement :
                    iCurrentRowPointer = iCurrentRowPointer - 1
                    if iCurrentRowPointer < 0 :
                        iCurrentRowPointer = nRowCount - 1
                        iCurrentColPointer = iCurrentColPointer + 1
                else :
                    iCurrentColPointer = iCurrentColPointer + 1
                    if iCurrentColPointer >= nColCount :
                        iCurrentRowPointer = iCurrentRowPointer - 1
                        iCurrentColPointer = 0
                    #End If
                #End If
            elif sOriginPoint.upper() == "BOTTOMRIGHT" :
                if UseVerticalArrangement :
                    iCurrentRowPointer = iCurrentRowPointer - 1
                    if iCurrentRowPointer < 0 :
                        iCurrentRowPointer = nRowCount - 1
                        iCurrentColPointer = iCurrentColPointer - 1
                else :
                    iCurrentColPointer = iCurrentColPointer - 1
                    if iCurrentColPointer < 0 :
                        iCurrentRowPointer = iCurrentRowPointer - 1
                        iCurrentColPointer = nColCount - 1
                    #End If
                #End If
            else :
                if UseVerticalArrangement :
                    iCurrentRowPointer = iCurrentRowPointer + 1
                    if iCurrentRowPointer >= nRowCount :
                        iCurrentRowPointer = 0
                        iCurrentColPointer = iCurrentColPointer + 1
                else :
                    iCurrentColPointer = iCurrentColPointer + 1
                    if iCurrentColPointer >= nColCount :
                        iCurrentRowPointer = iCurrentRowPointer + 1
                        iCurrentColPointer = 0
                    #End If
                #End If
            #End If
        #Next
 
        # Save concatenated image if necessary
        if SaveConcatenatedImage :
            sSavePath = f"{sSaveDirectory}{sFileNamePrefix}{ImgID}.png"
            print(f"Exporting concatenated image to {sSavePath}...")
            imgCurrentImage.save(sSavePath)
        #End If
 
        # Buffer concatenated image for caller if necessary
        if CloseConcatenatedImagesWhenReturning :
            imgCurrentImage.close()
        else :
            arrConcatenatedImages.append(imgCurrentImage)
        #End If
    #Next
 
    return arrConcatenatedImages
#End Function

参考资料:

https://zhuanlan.zhihu.com/p/270669498

https://blog.csdn.net/weixin_43789195/article/details/105783414

it
除非特别注明,本页内容采用以下授权方式: Creative Commons Attribution-ShareAlike 3.0 License