繁体   English   中英

如何用图像的中值有效填充 RGB numpy 数组?

[英]How can I efficently pad an RGB numpy array with the median of the image?

我有已经重新缩放的 RGB 图像,因此较长的边缘变为 256 像素,现在我想用该图像的中值 RGB 值填充边框,因此生成的图像始终为 256x256 像素。

这段代码已经可以工作了,但我相信可以有一种更简单、更优雅的方法来做到这一点:

img = loadAndFitImage(filePath, maxSideLength=256, upscale=True)
shp = img.shape
#the shp in this case is typically (256,123,3) or (99,256,3)

leftPad = (256 - shp[0]) / 2
rightPad = 256 - shp[0] - leftPad
topPad = (256 - shp[1]) / 2
bottomPad = 256 - shp[1] - topPad

# this part looks like there might be a way to do it with one median call instead of 3:
median = (np.median(img[:, :, 0]),np.median(img[:, :, 1]),np.median(img[:, :, 2]))

img = np.lib.pad(img, ((leftPad,rightPad),(topPad,bottomPad),(0,0)),
 'constant',constant_values=0)

if leftPad > 0:
    img[:leftPad,:,0].fill(median[0])
    img[:leftPad,:,1].fill(median[1])
    img[:leftPad,:,2].fill(median[2])
if rightPad > 0:
    img[-rightPad:,:,0].fill(median[0])
    img[-rightPad:,:,1].fill(median[1])
    img[-rightPad:,:,2].fill(median[2])
if topPad > 0:
    img[:,:topPad,0].fill(median[0])
    img[:,:topPad,1].fill(median[1])
    img[:,:topPad,2].fill(median[2])
if bottomPad > 0:
    img[:,-bottomPad:,0].fill(median[0])
    img[:,-bottomPad:,1].fill(median[1])
    img[:,-bottomPad:,2].fill(median[2])

编辑(附加信息):

  • 这是最终结果的样子:

  • 期望:

  • 这是它不应该的样子(每列的中位数):

  • 不受欢迎的:

您可以通过以下方式轻松完成:

import numpy as np

a = np.asarray([[1,2,3,4,5,6],
     [8,4,5,6,7,7],
     [1,2,3,4,5,6],
     [1,2,3,4,5,6],
     [1,2,3,4,5,6],
     [1,2,3,4,5,6]])

b = a * 3
c = a * 4
d = (a,b,c)

im = np.asarray([np.pad(x, (2,), 'constant', constant_values=(np.median(x) ,)) for x in d])
print im

输出:

[[[ 4  4  4  4  4  4  4  4  4  4]
  [ 4  4  4  4  4  4  4  4  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  8  4  5  6  7  7  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  1  2  3  4  5  6  4  4]
  [ 4  4  4  4  4  4  4  4  4  4]
  [ 4  4  4  4  4  4  4  4  4  4]]

 [[12 12 12 12 12 12 12 12 12 12]
  [12 12 12 12 12 12 12 12 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12 24 12 15 18 21 21 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12  3  6  9 12 15 18 12 12]
  [12 12 12 12 12 12 12 12 12 12]
  [12 12 12 12 12 12 12 12 12 12]]

 [[16 16 16 16 16 16 16 16 16 16]
  [16 16 16 16 16 16 16 16 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16 32 16 20 24 28 28 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16  4  8 12 16 20 24 16 16]
  [16 16 16 16 16 16 16 16 16 16]
  [16 16 16 16 16 16 16 16 16 16]]]

或者在你的特殊情况下:

原始图像

import numpy as np
from PIL import Image

filePath = '/home/george/Desktop/img.jpg'

Img = Image.open(filePath)
img = np.asarray(Img, np.int)
shp = np.shape(img)
img = img.transpose(2,0,1).reshape(3,215,215)

leftPad = round(float((255 - shp[0])) / 2)
rightPad = round(float(255 - shp[0]) - leftPad)
topPad = round(float((255 - shp[1])) / 2)
bottomPad = round(float(255 - shp[1]) - topPad)
pads = ((leftPad,rightPad),(topPad,bottomPad))

img_arr = np.ndarray((3,255,255),np.int)
for i,x in enumerate(img):
    cons = np.int(np.median(x))
    x_p = np.pad(x,pads,
                'constant', 
                 constant_values=cons)
    img_arr[i,:,:] = x_p

im_shp = np.shape(img_arr)
ii = np.uint8(img_arr).transpose(1,2,0)

im = Image.fromarray(np.array( (ii) ))
im.show()
im.save((filePath), "JPEG")

输出:

中位填充图像

我也在努力解决这个问题,并找到了一个优雅的答案:

color = np.median(img, axis=(0,1)) img = np.stack([np.pad(img[:,:,c], pad, mode='constant', constant_values=color[c]) for c in range(3)], axis=2)

计算中位数可以使用median = np.median(img.reshape(-1, 3), axis=0)或类似的东西来完成,请参阅此答案

填充可能可以通过每边一行完成,类似于img[:leftPad,:,:] = median 看看广播规则

派对迟到了,但这里有另一个建议:

def pad_image(img, color, border_width=.1):
    """
    pads image img with given color. 
    Color must be in same color space as image (usually, RGB). 
    border_width is expected to be the fraction of padding you want to add,
    with respect to the shorter dimension of the image.
    """
    h, w, c = img.shape

    # compute the number of pixels you'll pad
    border = int(float(min(h, w) * border_width))  

    # compute the "new background"
    result = np.full((h+2*border, w+2*border, c), color, dtype=img.dtype)
    
    # now fill this "new background" with your original image in the center
    result[border:-border, border:-border] = img

    return result

使用示例:

img = np.zeros((11,21, 3), dtype=np.uint8)  # create simple black image

img = pad_image(img, (128,0,0), .25)

plt.imshow(img)

哪个输出:

输出图像:被深红色边框包围的黑色图像

对于这种特殊情况,正如其他人所说,您需要在填充之前计算中值颜色:

color = np.median(img, axis=(0,1))

我相信这可以使用单个np.pad()调用更简单地完成:

  value = np.median(image, axis=(0, 1))
  pad = 2
  cval = np.array([[value, value], [value, value], [0, 0]], dtype=object)  # Ragged.
  image2 = np.pad(image, ((pad, pad), (pad, pad), (0, 0)), constant_values=cval)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM