【问题标题】:Adding borders to an image using python使用python为图像添加边框
【发布时间】:2012-06-23 23:09:08
【问题描述】:

我有大量固定尺寸的图像(比如 500*500)。我想编写一个python脚本,将它们调整为固定大小(比如800 * 800),但会将原始图像保持在中心并用固定颜色(比如黑色)填充多余的区域。

我正在使用 PIL。我现在可以使用resize 函数调整图像大小,但这会改变纵横比。有没有办法做到这一点?

【问题讨论】:

    标签: python image image-processing


    【解决方案1】:

    您可以创建具有所需新尺寸的新图像,并将旧图像粘贴到中心,然后保存。如果你愿意,你可以覆盖原始图像(你确定吗?;o)

    import Image
    
    old_im = Image.open('someimage.jpg')
    old_size = old_im.size
    
    new_size = (800, 800)
    new_im = Image.new("RGB", new_size)   ## luckily, this is already black!
    new_im.paste(old_im, ((new_size[0]-old_size[0])//2,
                          (new_size[1]-old_size[1])//2))
    
    new_im.show()
    # new_im.save('someimage.jpg')
    

    【讨论】:

    • 嗨@heltonbiker,你能给我解释一下这段代码吗:((new_size[0]-old_size[0])/2, (new_size[1]-old_size[1])/2))
    • new_size[0]-old_size[0] 是两种尺寸的区别。如果您将其设置为两个,则您将获得左侧填充(并且您会在右侧获得等效的填充)。
    【解决方案2】:

    是的,有。

    制作这样的东西:

    from PIL import Image, ImageOps
    ImageOps.expand(Image.open('original-image.png'),border=300,fill='black').save('imaged-with-border.png')
    

    你可以在几行写相同的:

    from PIL import Image, ImageOps
    img = Image.open('original-image.png')
    img_with_border = ImageOps.expand(img,border=300,fill='black')
    img_with_border.save('imaged-with-border.png')
    

    你说你有一个图像列表。然后你必须使用一个循环来处理所有这些:

    from PIL import Image, ImageOps
    for i in list-of-images:
      img = Image.open(i)
      img_with_border = ImageOps.expand(img,border=300,fill='black')
      img_with_border.save('bordered-%s' % i)
    

    【讨论】:

    • 有趣。是否可以为上下左右选择不同的边框,所以新的图像尺寸可以作为参数,而不是边框​​尺寸?
    • 谢谢,我可以让边框的 x 和 y 值不同...比如说 (100,50)?
    • 好的,找到了解决办法,ImageOps.expand(Image.open('original-image.png'),border=(300,500),fill='black').save('imaged-with-border.png')
    • ImageOps.expand 似乎在大多数情况下都有效,尽管它在处理大图像(5500x5500 像素)时给我带来了麻烦。出于某种原因,图像出现灰度,而在较小图像上运行的完全相同的代码可以完美运行。鉴于此,我在下面发布了一个关于使用 Image.crop 的答案,它似乎没有相同的限制/错误。
    【解决方案3】:

    或者,如果您使用OpenCV,它们有一个名为copyMakeBorder 的函数,允许您在图像的任何一侧添加填充。除了纯色之外,它们还为花哨的边框提供了一些很酷的选项,例如反射或扩展图像。

    import cv2
    
    img = cv2.imread('image.jpg')
    
    color = [101, 52, 152] # 'cause purple!
    
    # border widths; I set them all to 150
    top, bottom, left, right = [150]*4
    
    img_with_border = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)
    

    来源:OpenCV border tutorialOpenCV 3.1.0 Docs for copyMakeBorder

    【讨论】:

    • 我认为您应该在定义value=color 之前添加cv2.BORDER_CONSTANT,如docs.opencv.org/3.1.0/d3/df2/tutorial_py_basic_ops.html 中一样
    • 为了重现最后一张图片,图片的边框像素被复制,你可以使用cv2.BORDER_REPLICATE作为边框类型,你不需要指定颜色值,比如这个:img_with_border = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_REPLICATE)
    【解决方案4】:

    PIL 的crop 方法实际上可以通过使用原始图像边界框之外的数字为您处理这个问题,尽管the documentation 中没有明确说明。 left 和 top 的负数会将黑色像素添加到这些边缘,而大于原始宽度和高度的 right 和 bottom 会将黑色像素添加到这些边缘。

    这段代码解释了奇怪的像素大小:

    from PIL import Image
    
    with Image.open('/path/to/image.gif') as im:
        old_size = im.size
        new_size = (800, 800)
    
        if new_size > old_size:
            # Set number of pixels to expand to the left, top, right,
            # and bottom, making sure to account for even or odd numbers
            if old_size[0] % 2 == 0:
                add_left = add_right = (new_size[0] - old_size[0]) // 2
            else:
                add_left = (new_size[0] - old_size[0]) // 2
                add_right = ((new_size[0] - old_size[0]) // 2) + 1
    
            if old_size[1] % 2 == 0:
                add_top = add_bottom = (new_size[1] - old_size[1]) // 2
            else:
                add_top = (new_size[1] - old_size[1]) // 2
                add_bottom = ((new_size[1] - old_size[1]) // 2) + 1
    
            left = 0 - add_left
            top = 0 - add_top
            right = old_size[0] + add_right
            bottom = old_size[1] + add_bottom
    
            # By default, the added pixels are black
            im = im.crop((left, top, right, bottom))
    

    除了 4 元组,您可以改为使用 2 元组在左/右和上/下添加相同数量的像素,或者使用 1 元组向所有边添加相同数量的像素.

    【讨论】:

      【解决方案5】:

      在这里考虑旧维度、新维度及其区别很重要。如果差异是奇数(不是偶数),则需要为 left、top、rightbottom 边框指定稍微不同的值。

      假设旧维度是 ow,oh,新维度是 nw,nh。 所以,这就是答案:

      import Image, ImageOps
      img = Image.open('original-image.png')
      deltaw=nw-ow
      deltah=nh-oh
      ltrb_border=(deltaw/2,deltah/2,deltaw-(deltaw/2),deltah-(deltah/2))
      img_with_border = ImageOps.expand(img,border=ltrb_border,fill='black')
      img_with_border.save('imaged-with-border.png')
      

      【讨论】:

        【解决方案6】:

        您可以将带有 scipy.misc.imread 的图像加载为 numpy 数组。然后使用numpy.zeros((height, width, channels)) 创建一个具有所需背景的数组并将图像粘贴到所需位置:

        import numpy as np
        import scipy.misc
        
        im = scipy.misc.imread('foo.jpg', mode='RGB')
        height, width, channels = im.shape
        
        # make canvas
        im_bg = np.zeros((height, width, channels))
        im_bg = (im_bg + 1) * 255  # e.g., make it white
        
        # Your work: Compute where it should be
        pad_left = ...
        pad_top = ...
        
        im_bg[pad_top:pad_top + height,
              pad_left:pad_left + width,
              :] = im
        # im_bg is now the image with the background.
        

        【讨论】:

        • im_bg 不应该是 (height+(2*pad_top), width+(2*pad_left), channels) 之类的东西,否则目标图像与源图像大小相同,因此边框没有空间?
        【解决方案7】:
        ximg = Image.open(qpath)
        xwid,xhgt = func_ResizeImage(ximg)
        qpanel_3 = tk.Frame(Body,width=xwid+10,height=xhgt+10,bg='white',bd=5)
        ximg = ximg.resize((xwid,xhgt),Image.ANTIALIAS) 
        ximg = ImageTk.PhotoImage(ximg) 
        panel = tk.Label(qpanel_3,image=ximg)     
        panel.image = ximg 
        panel.grid(row = 2)
        

        【讨论】:

        • 请为您的代码添加解释,而不是个人信息。
        猜你喜欢
        • 2013-01-22
        • 1970-01-01
        • 1970-01-01
        • 2014-04-11
        • 2015-01-29
        • 2013-02-27
        • 2021-12-30
        • 1970-01-01
        • 2020-02-26
        相关资源
        最近更新 更多