How to Split Image Into Multiple Pieces in Python

后端 未结 12 834
感动是毒
感动是毒 2020-12-01 00:27

I\'m trying to split a photo into multiple pieces using PIL.

def crop(Path,input,height,width,i,k,x,y,page):
    im = Image.open(input)
    imgwidth = im.siz         


        
相关标签:
12条回答
  • 2020-12-01 00:57

    Edit: I believe this answer missed the intent to cut an image into rectangles in columns and rows. This answer cuts only into rows. It looks like other answers cut in columns and rows.

    Simpler than all these is to use a wheel someone else invented :) It may be more involved to set up, but then it's a snap to use.

    These instructions are for Windows 7; they may need to be adapted for other OSs.

    Get and install pip from here.

    Download the install archive, and extract it to your root Python installation directory. Open a console and type (if I recall correctly):

    python get-pip.py install
    

    Then get and install the image_slicer module via pip, by entering the following command at the console:

    python -m pip install image_slicer
    

    Copy the image you want to slice into the Python root directory, open a python shell (not the "command line"), and enter these commands:

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

    The beauty of this module is that it

    1. Is installed in python
    2. Can invoke an image split with two lines of code
    3. Accepts any even number as an image slice parameter (e.g. 14 in this example)
    4. Takes that parameter and automagically splits the given image into so many slices, and auto-saves the resultant numbered tiles in the same directory, and finally
    5. Has a function to stitch the image tiles back together (which I haven't yet tested); files apparently must be named after the convention which you will see in the split files after testing the image_slicer.slice function.
    0 讨论(0)
  • 2020-12-01 00:59
    1. crop would be a more reusable function if you separate the cropping code from the image saving code. It would also make the call signature simpler.
    2. im.crop returns a Image._ImageCrop instance. Such instances do not have a save method. Instead, you must paste the Image._ImageCrop instance onto a new Image.Image
    3. Your ranges do not have the right step sizes. (Why height-2 and not height? for example. Why stop at imgheight-(height/2)?).

    So, you might try instead something like this:

    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)
    
    0 讨论(0)
  • 2020-12-01 01:01
    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
    
    0 讨论(0)
  • 2020-12-01 01:04

    Splitting image to tiles of MxN pixels (assuming im is 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)]
    

    In the case you want to split the image to four pieces:

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

    tiles[0] holds the upper left tile

    0 讨论(0)
  • 2020-12-01 01:07

    I tried the solutions above, but sometimes you just gotta do it yourself. Might be off by a pixel in some cases but works fine in general.

    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
    

    Hope it helps.

    0 讨论(0)
  • 2020-12-01 01:07
    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 讨论(0)
提交回复
热议问题