在 Python 中缩小部分图像

Downscaling part of image in Python

我正在尝试从 (x,y) 坐标开始缩小图像的一部分,并将宽度和高度 500 调整为 40x40。通过这样做,我将周围的像素平均化为一个。 (我能找到的最简单的方法)但是结果很奇怪。

原图为 512x512 png

原图:

预期结果:

实际结果:

下面是代码片段:

from PIL import Image
import numpy as np


defined_size = 40
img = Image.open("lena.png")
pix = np.array(img)
changed_img = shrink(pix, 0, 0, 500)
changed_img = np.array(changed_img)
resized = Image.fromarray(changed_img, 'RGB')

def shrink(img, x, y, size):
     result = [[0 for width in xrange(defined_size)] for height in xrange(defined_size)] 

     scale_factor = size/defined_size    
     for i in xrange(defined_size):
        for j in xrange(defined_size):
            temp = np.array([0,0,0])
            for t in xrange(scale_factor):
                print img[i*scale_factor+x, j*scale_factor+y]
                temp = np.add(temp, img[i*scale_factor+x, j*scale_factor+y])
            result[i][j] = np.divide(temp, scale_factor)
            print result[i][j]

     return result

为什么不用库函数? Python 图书馆很棒。

import PIL.Image
import scipy.misc

lena = scipy.misc.lena()
resized = scipy.misc.imresize(lena, (40, 40), interp='bilinear')
image = PIL.Image.fromarray(resized)

您的代码有几个问题。让我们一次解决一个问题:

问题 #1 - (x,y) 在您的 shrink 定义中毫无用处

我知道你要去哪里 (x,y)。您正在使用它来遍历每个较大的块,将所有像素相加并除以条目总数以获得平均 RGB 像素。您将图像中的每个块都设置为 (0,0),因此您实际上并没有获得块中的所有像素。您需要使用一对 for 循环来遍历每个块。我还冒昧地删除了 (x,y) 输入,并将所需的大小作为输入放入您的函数中。

问题 #2 - 输出不是三通道

您初始化了一个二维列表,但图像具有三个通道。因为您正在使用 numpy 为您进行计算...您为什么不先通过 np.zeros 声明一个 zeros 的数组?这样,您不必在完成后转换回 numpy 数组。我已经更改了输出图像的声明,使其成为 uint8 类型的 numpy 数组。这次选角很重要!

问题 #3 - 没有正确迭代每个子采样块

正如我们在问题 #1 中所讨论的,您没有正确收集每个子采样块的像素。我插入了另一对 for 循环来为您执行此操作...枚举为 xy。我还删除了 np.add 并使用 + 为您完成操作,因为它更容易阅读。

问题 #4 - 除以错误的因数

因为它是您要计算的子样本的平均值,所以您必须除以每个块中值的总数。那等于 scale_factor*scale_factor。您只除以 scale_factor.


我还冒昧地展示了调整大小的图像并将其保存到文件中。事不宜迟,这里是更正后的代码。我还将您的测试代码放在 __main__ 块中,以便于测试:

from PIL import Image
import numpy as np

def shrink(img, size, defined_size): # Change - Issue #1
     result = np.zeros((defined_size, defined_size, 3), dtype=np.uint8) # Change - Issue #2

     scale_factor = size/defined_size    
     for i in xrange(defined_size):
        for j in xrange(defined_size):
            temp = np.array([0,0,0])
            for x in xrange(scale_factor): # Change - Issue #3
                for y in xrange(scale_factor): # Change - Issue #3    
                    temp += img[i*scale_factor + x, j*scale_factor + y] # Change - Issue #3

            result[i,j] = temp / (scale_factor*scale_factor) # Change          

     return result

if __name__ == '__main__':
    img = Image.open("lena.png")
    pix = np.array(img)
    changed_img = shrink(pix, 512, 40) # Change - Issue #1
    resized = Image.fromarray(changed_img, 'RGB')
    resized.show() # Change
    resized.save("lena_resize.png")

...我们得到这张调整大小的图像:

我已经调整了代码 ,它现在将通过平均周围像素将任何尺寸的输入图像调整为四分之一大小。早期版本仅适用于方形图像。

import numpy as np
import cv2

def quarter_res_avg(im):

    original_width = im.shape[1]
    original_height = im.shape[0]
    width = original_width / 4
    height = original_height / 4

    resized_image = np.zeros(shape=(height, width, 3), dtype=np.uint8)
    scale = 4

    for i in range(height):
        for j in range(width):
            temp = np.array([0, 0, 0])
            for x in range(scale):
                for y in range(scale):
                    temp += im[i*scale + x, j*scale + y]
            resized_image[i, j] = temp/(scale*scale)

    return resized_image

im = cv2.imread('Lenna_test_image.png', 1)
cv2.imwrite('Lenna_test_image_resized.png', quarter_res_avg(im))  

另一种方法:

import numpy as np
import cv2

def quarter_res_avg(im):

    original_width = im.shape[1]
    original_height = im.shape[0]

    width = original_width / 4
    height = original_height / 4

    resized_image = np.zeros(shape=(height, width, 3), dtype=np.uint8)

    scale = 4

    for i in range(0, original_height, scale):
        for j in range(0, original_width, scale):
           resized_image[i/scale, j/scale] = np.mean(im[i:i + scale, j:j+scale], axis=(0, 1))

    return resized_image