使用文件名作为位置将图像粘贴在一起

时间:2019-05-09 11:54:41

标签: python image image-processing python-imaging-library

我有一堆jpeg图像,我想在其文件名后的特定位置加入这些图像。文件名的示例是:

7_1.jpeg->此图片应粘贴到第七行第一列

15_5.jpeg->此图像应粘贴到第15行第5列

在这种情况下,文件名的范围从1_1.jpeg40_20.jpeg,但是我想加入任意数量的图像。

最终图像将具有空单元格,因为并非所有位置都具有图像。

我发现最适合我的目的的帖子是:https://stackoverflow.com/a/42853439/8252488

更新: 我尝试了其他选项,现在可以使用以下方法将不同的图像粘贴到特定位置:

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)

来自here

现在,我正在尝试使用文件名指定位置,如下所示:

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)

有什么想法吗? 谢谢!

UPDATE2 如果将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)

Badly arranged image

2 个答案:

答案 0 :(得分:0)

经过一番挣扎,我终于找到了想要的东西。我只是放上对我有用的代码,以防万一有人需要类似的东西。我知道代码不干净,但是可以正常工作:-P

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+280,width_tot+280,3))
#Locate images
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)*280
    width = re.sub(".*_", "", position)
    width2 = int(width)*280
    output[width2:width2+280,height2:height2+280] = image

cv2.imwrite("test_processed.jpg", output)

您将看到与先前代码的唯一区别是,由于外部贴片不合适,我在每个轴上添加了280。我还交换了轴以更好地显示。

答案 1 :(得分:0)

libvips可以在命令行上执行此操作,也可以通过Python使用pyvips来完成。

在命令行上,尝试:

vips arrayjoin "$(ls *.jpeg | sort -t_ -k2g -k1g)" x.jpg --across 20

这是如何工作的:

  • ls列出所有jpg文件,每行列出一个。
  • 但是它们将按字母顺序!例如,如果将它们命名为x_y.jpeg,则10_0.jpeg将位于1_0.jpeg之前。
  • sort命令将每一行分成_字符上的字段,然后按第二个数字,然后是第一个数字进行数字排序。
  • 这会将文件从左到右,然后从上到下进行排序。
  • arrayjoin将图块列表合并为一个正方形图像。
  • 您只需要给它提供(across参数)中的切片数即可。

在Python中,您可以执行以下操作:

import pyvips

tiles_across = 37
tiles_down = 37

tiles = [pyvips.Image.new_from_file(f"{x}_{y}.jpeg", access="sequential"))
         for y in range(tiles_down) for x in range(tiles_across)]
im = pyvips.Image.arrayjoin(tiles, across=tiles_across)

im.write_to_file("x.jpg")

这是一个更完整的解释,包括示例和提示:

how to convert dzi files to multi-tile pyramidal tiff format