web-dev-qa-db-fra.com

Comment diviser l'image en plusieurs pièces en Python

J'essaie de diviser une photo en plusieurs morceaux en utilisant PIL.

def crop(Path,input,height,width,i,k,x,y,page):
    im = Image.open(input)
    imgwidth = im.size[0]
    imgheight = im.size[1]
    for i in range(0,imgheight-height/2,height-2):
        print i
        for j in range(0,imgwidth-width/2,width-2):
            print j
            box = (j, i, j+width, i+height)
            a = im.crop(box)
            a.save(os.path.join(Path,"PNG","%s" % page,"IMG-%s.png" % k))
            k +=1

mais cela ne semble pas fonctionner. Il divise la photo mais pas de manière exacte (vous pouvez l'essayer).

23
Elteroooo
from PIL import Image

def crop(path, input, height, width, k, page, area):
    im = Image.open(input)
    imgwidth, imgheight = im.size
    for i in range(0,imgheight,height):
        for j in range(0,imgwidth,width):
            box = (j, i, j+width, i+height)
            a = im.crop(box)
            try:
                o = a.crop(area)
                o.save(os.path.join(path,"PNG","%s" % page,"IMG-%s.png" % k))
            except:
                pass
            k +=1
29
Elteroooo

Edit: Je crois que cette réponse a manqué l'intention de couper une image en rectangles dans des colonnes et des lignes. Cette réponse ne coupe qu'en lignes. Il ressemble à d'autres réponses découpées en colonnes et en lignes.

Plus simple que tout cela, c'est d'utiliser une roue inventée par quelqu'un d'autre :) Il peut être plus compliqué à configurer, mais c'est un jeu d'enfant à utiliser.

Ces instructions concernent Windows 7; ils devront peut-être être adaptés à d'autres systèmes d'exploitation.

Obtenez et installez pip depuis ici .

Téléchargez l'archive d'installation et extrayez-la dans votre répertoire racine Python. Ouvrez une console et tapez (si je me souviens bien):

python get-pip.py install

Ensuite, récupérez et installez le module image_slicer via pip, en entrant la commande suivante sur la console:

python -m pip install image_slicer

Copiez l'image que vous souhaitez découper dans le répertoire racine Python, ouvrez un shell python (pas la "ligne de commande")) et entrez ces commandes:

import image_slicer
image_slicer.slice('huge_test_image.png', 14)

La beauté de ce module est qu'il

  1. Est installé en python
  2. Peut invoquer une image divisée avec deux lignes de code
  3. Accepte tout nombre pair comme paramètre de tranche d'image (par exemple 14 dans cet exemple)
  4. Prend ce paramètre et divise automatiquement l'image donnée en autant de tranches, et enregistre automatiquement les tuiles numérotées résultantes dans le même répertoire, et enfin
  5. A une fonction pour assembler les tuiles d'image ensemble (que je n'ai pas encore testé); les fichiers doivent apparemment être nommés d'après la convention que vous verrez dans les fichiers fractionnés après avoir testé la fonction image_slicer.slice.
28
Alex Hall

Division de l'image en mosaïques de pixels MxN (en supposant que im est numpy.ndarray):

tiles = [im[x:x+M,y:y+N] for x in range(0,im.shape[0],M) for y in range(0,im.shape[1],N)]

Dans le cas où vous souhaitez diviser l'image en quatre parties:

M = im.shape[0]//2
N = im.shape[1]//2

tuiles [0] contient la tuile supérieure gauche

17
Nir
  1. crop serait une fonction plus réutilisable si vous séparez le code de recadrage du code d'enregistrement d'image. Cela rendrait également la signature d'appel plus simple.
  2. im.crop Renvoie une instance de Image._ImageCrop. De telles instances n'ont pas de méthode de sauvegarde. Au lieu de cela, vous devez coller l'instance Image._ImageCrop Sur un nouveau Image.Image
  3. Vos gammes n'ont pas les bonnes tailles de pas. (Pourquoi height-2 Et non height? Par exemple. Pourquoi s'arrêter à imgheight-(height/2)?).

Donc, vous pouvez essayer quelque chose comme ceci:

import Image
import os

def crop(infile,height,width):
    im = Image.open(infile)
    imgwidth, imgheight = im.size
    for i in range(imgheight//height):
        for j in range(imgwidth//width):
            box = (j*width, i*height, (j+1)*width, (i+1)*height)
            yield im.crop(box)

if __name__=='__main__':
    infile=...
    height=...
    width=...
    start_num=...
    for k,piece in enumerate(crop(infile,height,width),start_num):
        img=Image.new('RGB', (height,width), 255)
        img.paste(piece)
        path=os.path.join('/tmp',"IMG-%s.png" % k)
        img.save(path)
12
unutbu

Voici une solution concise en python pur qui fonctionne dans les deux python 3 et 2:

from PIL import Image

infile = '20190206-135938.1273.Easy8thRunnersHopefully.jpg'
chopsize = 300

img = Image.open(infile)
width, height = img.size

# Save Chops of original image
for x0 in range(0, width, chopsize):
   for y0 in range(0, height, chopsize):
      box = (x0, y0,
             x0+chopsize if x0+chopsize <  width else  width - 1,
             y0+chopsize if y0+chopsize < height else height - 1)
      print('%s %s' % (infile, box))
      img.crop(box).save('zchop.%s.x%03d.y%03d.jpg' % (infile.replace('.jpg',''), x0, y0))

Remarques:

  • Les rognages qui dépassent à droite et en bas de l'image d'origine sont ajustés à la limite de l'image d'origine et ne contiennent que les pixels d'origine.
    • Il est facile de choisir un chopsize différent pour w et h en utilisant deux vars de chopsize et en remplaçant chopsize comme approprié dans le code ci-dessus.
  • 2
    RubinMac

    Je ne sais pas si c'est la réponse la plus efficace, mais cela fonctionne pour moi:

    import os
    import glob
    from PIL import Image
    Image.MAX_IMAGE_PIXELS = None # to avoid image size warning
    
    imgdir = "/path/to/image/folder"
    # if you want file of a specific extension (.png):
    filelist = [f for f in glob.glob(imgdir + "**/*.png", recursive=True)]
    savedir = "/path/to/image/folder/output"
    
    start_pos = start_x, start_y = (0, 0)
    cropped_image_size = w, h = (500, 500)
    
    for file in filelist:
        img = Image.open(file)
        width, height = img.size
    
        frame_num = 1
        for col_i in range(0, width, w):
            for row_i in range(0, height, h):
                crop = img.crop((col_i, row_i, col_i + w, row_i + h))
                name = os.path.basename(file)
                name = os.path.splitext(name)[0]
                save_to= os.path.join(savedir, name+"_{:03}.png")
                crop.save(save_to.format(frame_num))
                frame_num += 1
    

    Ceci est principalement basé sur la réponse DataScienceGuy ici

    1
    Bento
    import cv2
    
    def crop_image(image_path, output_path):
        im =  cv2.imread(os.listdir()[2])
        imgheight=im.shape[0]
        imgwidth=im.shape[1]
    
        y1 = 0
        M = 2000
        N = 2000
        for y in range(0,imgheight,M):
            for x in range(0, imgwidth, N):
                y1 = y + M
                x1 = x + N
                tiles = im[y:y+M,x:x+N]
                if tiles.shape[0] < 100 or  tiles.shape[1]<100:
                    continue
    
                cv2.rectangle(im, (x, y), (x1, y1), (0, 255, 0))
                cv2.imwrite(output_path +  str(x) + '_' + str(y)+"{}.png".format(image_path),tiles)
    crop_image(os.listdir()[2], './cutted/')
    
    0
    Rocketq

    Ceci est mes outils de script, il est très simple de diviser l'image divisée en CSS en icônes:

    Usage: split_icons.py img dst_path width height
    Example: python split_icons.py icon-48.png gtliu 48 48
    

    Enregistrez le code dans split_icons.py:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import os
    import sys
    import glob
    from PIL import Image
    
    def Usage():
        print '%s img dst_path width height' % (sys.argv[0])
        sys.exit(1)
    
    if len(sys.argv) != 5:
        Usage()
    
    src_img = sys.argv[1]
    dst_path = sys.argv[2]
    
    if not os.path.exists(sys.argv[2]) or not os.path.isfile(sys.argv[1]):
        print 'Not exists', sys.argv[2], sys.argv[1]
        sys.exit(1)
    
    w, h = int(sys.argv[3]), int(sys.argv[4])
    im = Image.open(src_img)
    im_w, im_h = im.size
    print 'Image width:%d height:%d  will split into (%d %d) ' % (im_w, im_h, w, h)
    w_num, h_num = int(im_w/w), int(im_h/h)
    
    for wi in range(0, w_num):
        for hi in range(0, h_num):
            box = (wi*w, hi*h, (wi+1)*w, (hi+1)*h)
            piece = im.crop(box)
            tmp_img = Image.new('L', (w, h), 255)
            tmp_img.paste(piece)
            img_path = os.path.join(dst_path, "%d_%d.png" % (wi, hi))
            tmp_img.save(img_path)
    
    0
    winlin

    J'ai essayé les solutions ci-dessus, mais parfois tu dois le faire toi-même. Peut être décalé d'un pixel dans certains cas, mais fonctionne très bien en général.

    import matplotlib.pyplot as plt
    import numpy as np
    def image_to_tiles(im, number_of_tiles = 4, plot=False):
        """
        Function that splits SINGLE channel images into tiles
        :param im: image: single channel image (NxN matrix)
        :param number_of_tiles: squared number
        :param plot:
        :return tiles:
        """
        n_slices = np.sqrt(number_of_tiles)
        assert int(n_slices + 0.5) ** 2 == number_of_tiles, "Number of tiles is not a perfect square"
    
        n_slices = n_slices.astype(np.int)
        [w, h] = cropped_npy.shape
    
        r = np.linspace(0, w, n_slices+1)
        r_tuples = [(np.int(r[i]), np.int(r[i+1])) for i in range(0, len(r)-1)]
        q = np.linspace(0, h, n_slices+1)
        q_tuples = [(np.int(q[i]), np.int(q[i+1])) for i in range(0, len(q)-1)]
    
        tiles = []
        for row in range(n_slices):
            for column in range(n_slices):
                [x1, y1, x2, y2] = *r_tuples[row], *q_tuples[column] 
                tiles.append(im[x1:y1, x2:y2])
    
        if plot:
            fig, axes = plt.subplots(n_slices, n_slices, figsize=(10,10))
            c = 0
            for row in range(n_slices):
                for column in range(n_slices):
                    axes[row,column].imshow(tiles[c])
                    axes[row,column].axis('off')
                    c+=1
    
        return tiles
    

    J'espère que ça aide.

    0
    Baabda

    Je trouve plus facile de skimage.util.view_as_windows ou `skimage.util.view_as_blocks qui vous permet également de configurer l'étape

    http://scikit-image.org/docs/dev/api/skimage.util.html?highlight=view_as_windows#skimage.util.view_as_windows

    0
    Uwais Iqbal