How to Split Image Into Multiple Pieces in Python

2019-01-13 14:57发布

问题:

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

but it doesn't seem to be working. It splits the photo but not in an exact way (you can try it).

回答1:

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


回答2:

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.


回答3:

  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)


回答4:

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



回答5:

This is my script tools, it is very sample to splite css-sprit image into icons:

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

Save code into 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)


回答6:

I find it easier to skimage.util.view_as_windows or `skimage.util.view_as_blocks which also allows you to configure the step

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