You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于文件名指定行列拼接JPEG图片的代码报错排查

按文件名指定行列拼接JPEG图片的问题排查与解决

需求背景

我有一批JPEG图片,希望根据文件名指定的行列位置进行拼接。文件名规则是行_列.jpeg(例如7_1.jpeg对应第7行第1列,15_5.jpeg对应第15行第5列),文件名范围覆盖1_1.jpeg至40_20.jpeg,需支持任意数量图片拼接,最终允许存在空白单元格。

已尝试的代码与问题

基础拼接实现(已成功)

首先实现了纵向拼接的基础代码:

import cv2
import numpy
import glob
import os
dir = "." # current directory
ext = ".jpg" # whatever extension you want
pathname = os.path.join(dir, "*" + ext)
images = [cv2.imread(img) for img in glob.glob(pathname)]
height = sum(image.shape[0] for image in images)
width = max(image.shape[1] for image in images)
output = numpy.zeros((height,width,3))
y = 0
for image in images:
    h,w,d = image.shape
    output[y:y+h,0:w] = image
    y += h
cv2.imwrite("test.jpg", output)

尝试按行列定位拼接(出现错误)

接着尝试根据文件名提取行列位置来拼接,代码如下:

import cv2
import numpy
import glob
import os
import re # 补充原代码缺失的导入

dir = "."
ext = ".jpeg"
pathname = os.path.join(dir, "*" + ext)
images = [cv2.imread(img) for img in glob.glob(pathname)]
names = [img for img in glob.glob(pathname)]
#Get filenames from paths
files = [re.sub("/.*/", "", x) for x in names]
#Get positions
position = [re.sub(".jpeg", "", x) for x in files]
#Get hight position and tranform to int
height = [re.sub("_.*", "", x) for x in position]
height2 = [int(i) for i in height]
#Get width position and tranform to int
width = [re.sub(".*_", "", x) for x in position]
width2 = [int(i) for i in width]
#Generate background image
height_tot = 280*max(height2) #All images are 280*280
width_tot = 280*max(width2)
output = numpy.zeros((height_tot,width_tot,3))
#Locate images
for name, image in zip(names,images):
    files = re.sub("/.*/", "", name)
    position = re.sub(".jpeg", "", files)
    height = re.sub("_.*", "", position)
    height2 = int(height)*280
    width = re.sub(".*_", "", position)
    width2 = int(width)*280
    output[height2:height2+280,width2:width2+280] = image
cv2.imwrite("test.jpg", output)

运行时抛出错误:

ValueError                                Traceback (most recent call last)
<ipython-input-70-529c37a03571> in <module>()
      6     width = re.sub(".*_", "", position)
      7     width2 = int(width)*280
----> 8     output[height2:height2+280,width2:width2+280] = image
      9     # print(height2)
     10 cv2.imwrite("test.jpg", output)
ValueError: could not broadcast input array from shape (280,280,3) into shape (0,280,3)

修改后仍有问题

将280改为图片实际高度262后无报错,但图片排列混乱且存在重复粘贴,修改后的循环代码:

for name, image in zip(names,images):
    h,w,d = image.shape
    files = re.sub("/.*/", "", name)
    position = re.sub(".jpeg", "", files)
    height = re.sub("_.*", "", position)
    height2 = int(height)*262
    width = re.sub(".*_", "", position)
    width2 = int(width)*262
    output[height2:height2+h,width2:width2+w,:] = image
cv2.imwrite("test.jpg", output)

问题原因分析

  1. 初始错误的核心原因:索引越界与行列起始值错误

    • 文件名中的行号是从1开始的(比如1_1.jpeg是第1行),但你直接用int(height)*280作为起始位置,会导致第1行的起始位置是280而非0。当行号等于max(height2)时,height2+280就会超过output的高度(因为output高度是280*max(height2)),从而出现切片起始位置大于等于结束位置的shape (0,280,3)错误。
  2. 排列混乱与重复的原因

    • 列号同样从1开始,直接乘以图片宽度会导致第一列起始位置偏移,后续列的位置全部错位;
    • glob.glob返回的文件顺序不确定,可能导致图片被乱序处理;
    • 循环内重复处理文件名的逻辑冗余,且未做位置映射校验,可能导致同一区域被多次赋值。

修正后的完整代码

import cv2
import numpy as np
import glob
import os

def main():
    dir_path = "."  # 当前目录
    ext = ".jpeg"   # 图片扩展名
    path_pattern = os.path.join(dir_path, f"*{ext}")
    
    # 获取所有图片路径并按文件名排序,保证处理顺序稳定
    image_paths = sorted(glob.glob(path_pattern))
    
    # 提取图片行列信息、记录尺寸,同时更新最大行/列数
    img_info = []
    max_row = 0
    max_col = 0
    img_h, img_w = None, None
    
    for path in image_paths:
        # 提取纯文件名(去掉路径和扩展名)
        filename = os.path.basename(path)
        row_str, col_str = os.path.splitext(filename)[0].split("_")
        row = int(row_str)
        col = int(col_str)
        
        # 读取图片并校验
        img = cv2.imread(path)
        if img is None:
            print(f"警告:无法读取图片 {path}")
            continue
        # 记录图片尺寸(默认所有图片尺寸一致)
        if img_h is None:
            img_h, img_w = img.shape[:2]
        
        img_info.append((row, col, img))
        # 更新最大行/列数
        max_row = max(max_row, row)
        max_col = max(max_col, col)
    
    # 创建输出画布(匹配图片的uint8数据类型)
    canvas_h = max_row * img_h
    canvas_w = max_col * img_w
    output = np.zeros((canvas_h, canvas_w, 3), dtype=np.uint8)
    
    # 将图片放到对应位置
    for row, col, img in img_info:
        # 转换为画布的起始坐标:行/列号从1→0偏移
        start_y = (row - 1) * img_h
        start_x = (col - 1) * img_w
        output[start_y:start_y+img_h, start_x:start_x+img_w] = img
    
    # 保存结果
    cv2.imwrite("final拼接图.jpg", output)
    print("拼接完成,结果已保存为final拼接图.jpg")

if __name__ == "__main__":
    main()

关键修正点说明

  • 行列索引转换:将文件名中从1开始的行/列号,转换为画布上从0开始的起始坐标((row-1)*img_h),彻底解决越界和位置偏移问题;
  • 稳定排序:使用sorted()对图片路径排序,确保处理顺序稳定;
  • 类型匹配:创建output时指定dtype=np.uint8,和OpenCV读取的图片格式一致,避免潜在类型错误;
  • 简化逻辑:统一提取图片信息到列表,避免循环内重复处理文件名,代码更清晰易维护;
  • 错误处理:增加图片读取失败的警告,提升代码健壮性。

内容的提问来源于stack exchange,提问作者Tato14

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:02:48