web-dev-qa-db-fra.com

Ajouter des bordures à une image en utilisant python

J'ai un grand nombre d'images de taille fixe (disons 500 * 500). Je veux écrire un script python qui les redimensionnera à une taille fixe (disons 800 * 800) mais gardera l'image d'origine au centre et remplira la zone excédentaire avec une couleur fixe (disons noir).

J'utilise PIL. Je peux maintenant redimensionner l'image en utilisant la fonction resize maintenant, mais cela change le rapport d'aspect. Est-ce qu'il y a un moyen de faire ça?

31
Nihar Sarangi

Vous pouvez créer une nouvelle image avec la nouvelle taille souhaitée, coller l'ancienne image au centre, puis l'enregistrer. Si vous le souhaitez, vous pouvez remplacer l'image d'origine (êtes-vous sûr?; 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')
44
heltonbiker

Oui il y a.

Faites quelque chose comme ça:

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

Vous pouvez écrire la même chose sur plusieurs lignes:

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')

Et vous dites que vous avez une liste d'images. Ensuite, vous devez utiliser un cycle pour les traiter tous:

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)
35
Igor Chubin

Alternativement, si vous utilisez OpenCV , ils ont une fonction appelée copyMakeBorder qui vous permet d'ajouter un remplissage à l'un des côtés d'une image. Au-delà des couleurs unies, ils ont également des options intéressantes pour les bordures fantaisie comme la réflexion ou l'extension de l'image.

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)

Example results of cv2.copyMakeBorder function

Sources: Tutoriel sur les bordures OpenCV et Documents OpenCV 3.1.0 pour copyMakeBorder

9
pirt

La méthode crop de PIL peut réellement gérer cela pour vous en utilisant des nombres qui se trouvent en dehors du cadre de délimitation de l'image d'origine, bien qu'elle ne soit pas explicitement indiquée dans la documentation . Les nombres négatifs pour la gauche et le haut ajouteront des pixels noirs à ces bords, tandis que les nombres supérieurs à la largeur et la hauteur d'origine pour la droite et le bas ajouteront des pixels noirs à ces bords.

Ce code tient compte des tailles de pixels impaires:

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))

Au lieu du 4-Tuple, vous pouvez utiliser à la place un 2-Tuple pour ajouter le même nombre de pixels à gauche/à droite et en haut/en bas, ou un 1-Tuple pour ajouter le même nombre de pixels à tous les côtés.

2
kevinmicke

Vous pouvez charger l'image avec scipy.misc.imread comme un tableau numpy. Ensuite, créez un tableau avec l'arrière-plan souhaité avec numpy.zeros((height, width, channels)) et collez l'image à l'emplacement souhaité:

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.
2
Martin Thoma

Il est important de considérer l'ancienne dimension, la nouvelle dimension et leur différence ici. Si la différence est impaire (pas même), vous devrez spécifier des valeurs légèrement différentes pour les bordures gauche, haut, droite et bas.

Supposons que l'ancienne dimension est ow, oh et la nouvelle est nw, nh. Donc, ce serait la réponse:

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')
2
RF Vision