【问题标题】:Split and Join images in Python在 Python 中拆分和连接图像
【发布时间】:2017-09-19 18:55:10
【问题描述】:

我正在尝试使用 python 中的图像切片器分割图像,然后对它们中的每一个应用直方图均衡化并将它们组合回来。我能够将图像拆分成更小的块,并且可以看到它们正在更新,但是在将它们拼接在一起之后,我最终得到了与原始图像相同的图像。有人可以指出我做错了什么。文件名为 watch.png

import cv2
import numpy as np
from matplotlib import pyplot as plt
from scipy.misc import imsave
# import scipy
from scipy import ndimage
from scipy import misc
import scipy.misc
import scipy

import sys
import argparse
import image_slicer
from image_slicer import join


img = 'watch.png'
num_tiles = 64
tiles = image_slicer.slice(img, num_tiles)



file = "watch"
k = 0
filelist =[]
for i in range(1,9):
    for j in range(1,9):
        filelist.insert(k, file+"_"+str(i).zfill(2)+"_"+str(j).zfill(2)+".png")
        k=k+1

for i in range(0,num_tiles):
    img = scipy.misc.imread(filelist[i])
    hist,bins = np.histogram(img.flatten(),256,[0,256])
    cdf = hist.cumsum()
    cdf_normalized = cdf *hist.max()/ cdf.max()  
    plt.plot(cdf_normalized, color = 'g')
    plt.hist(img.flatten(),256,[0,256], color = 'g')
    plt.xlim([0,256])
    plt.legend(('cdf','histogram'), loc = 'upper left')
    cdf_m = np.ma.masked_equal(cdf,0)
    cdf_o = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
    cdf = np.ma.filled(cdf_o,0).astype('uint8')
    img3 = cdf[img]
    cv2.imwrite(filelist[i],img3)


image = join(tiles)
image.save('watch-join.png')

【问题讨论】:

  • 您的示例似乎不完整,因为您从未将切片存储在插入filelist 的文件中。但是,从代码中猜测我确实认为您会这样做,因为您似乎能够阅读不同的图像。但我的猜测是你忘记更新 tilesso 最后,你只是 join 原始的,未修改(因此,未更新)的图块,这当然会再次为您提供原始图像。
  • @JohanL 我正在将修改后的图像块写回相同的文件名,所以我认为它不应该有所作为。我尝试打印瓷砖,它给了我它引用的文件名列表,它们指向正确的文件名。在我缝合图像之前,您有什么其他方法可以建议更新图块
  • @user2808264-像您的问题一样,在完整图像上应用直方图均衡和在图像的每个部分上应用其他方面有什么区别吗?

标签: python image-processing scipy histogram


【解决方案1】:

这是image_slicer.join()的源代码:

def join(tiles):
    """
    @param ``tiles`` - Tuple of ``Image`` instances.
    @return ``Image`` instance.
    """
    im = Image.new('RGB', get_combined_size(tiles), None)
    columns, rows = calc_columns_rows(len(tiles))
    for tile in tiles:
        im.paste(tile.image, tile.coords)
    return im

如您所见,它使用存储在程序中的Tile 对象(在您的情况下,在列表tiles 中),这些对象没有改变。您需要更改内存中的对象而不是从文件加载并重写,或者将文件加载到tiles

我认为最简单的方法是修改你的 for 循环(我希望我的语法正确):

for i in range(0, num_tiles):
    img = tiles[i].image
    hist, bins = np.histogram(img.flatten(), 256, [0, 256])
    cdf = hist.cumsum()
    cdf_normalized = cdf * hist.max() / cdf.max()  
    plt.plot(cdf_normalized, color = 'g')
    plt.hist(img.flatten(), 256, [0, 256], color='g')
    plt.xlim([0, 256])
    plt.legend(('cdf', 'histogram'), loc='upper left')
    cdf_m = np.ma.masked_equal(cdf, 0)
    cdf_o = (cdf_m - cdf_m.min()) * 255 / (cdf_m.max() - cdf_m.min())
    cdf = np.ma.filled(cdf_o, 0).astype('uint8')
    img3 = cdf[img]
    tiles[i].image = img3

【讨论】:

  • 是否有其他方法可以做到这一点,因为使用上述方法无法应用展平功能我最终出现此错误 AttributeError: 'Image' object has no attribute 'flatten'
  • 如果将图像分割成片,如何合并回来?
【解决方案2】:

查看image_slicer 代码后,我可以看到混乱。主要问题是每个Tile 对象都包含图像数据和元数据,例如最终图像中的文件名和位置。但是,当指向的文件更新时,图像数据不会更新。

因此,在更新元数据指向的文件时,也需要更新图块的图像对象。我想最简单的方法是在磁盘上的文件发生更改时重新打开磁贴中的图像。这很可能会奏效:

import cv2
import numpy as np
from matplotlib import pyplot as plt
from scipy.misc import imsave
from scipy import ndimage
from scipy import misc
import scipy.misc
import scipy
import image_slicer
from image_slicer import join
from PIL import Image

img = 'watch.png'
num_tiles = 64
tiles = image_slicer.slice(img, num_tiles)

for tile in tiles:
    img = scipy.misc.imread(tile.filename)
    hist,bins = np.histogram(img.flatten(),256,[0,256])
    cdf = hist.cumsum()
    cdf_normalized = cdf *hist.max()/ cdf.max()  
    plt.plot(cdf_normalized, color = 'g')
    plt.hist(img.flatten(),256,[0,256], color = 'g')
    plt.xlim([0,256])
    plt.legend(('cdf','histogram'), loc = 'upper left')
    cdf_m = np.ma.masked_equal(cdf,0)
    cdf_o = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
    cdf = np.ma.filled(cdf_o,0).astype('uint8')
    img3 = cdf[img]
    cv2.imwrite(tile.filename,img3)
    tile.image = Image.open(tile.filename)

image = join(tiles)
image.save('watch-join.png')

因此,主要的变化是在循环末尾添加tile.image = Image.open(tile.filename)。另请注意,我已经稍微更新了您的代码,删除了生成文件名的第一个循环,而第二个循环直接在图块上,因为它们包含所有准备好的所需信息。

【讨论】:

  • 不幸的是,这会引发一个错误,指出 AttributeError: 'Image' object has no attribute 'open'
  • 我的错。 Image.open 是一个类方法,而不是一个对象方法。因此需要使用Image.open() 调用它。这也需要导入Image。我已经更新了代码。
  • @JohanL- 在完整图像上应用直方图均衡和在图像的每个部分上应用其他方面有什么区别吗?
猜你喜欢
  • 2023-03-11
  • 1970-01-01
  • 2012-09-05
  • 1970-01-01
  • 2016-08-19
  • 2011-08-01
  • 1970-01-01
  • 2013-02-09
  • 2021-01-27
相关资源
最近更新 更多