web-dev-qa-db-ja.com

Pythonで画像を複数の部分に分割する方法

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

しかし、機能していないようです。写真は分割されますが、正確な方法ではありません(試すことができます)。

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

編集:この回答は、画像を列と行の長方形にカットする意図を逃したと思います。この答えは行だけに切り分けます。他の回答が列と行にカットされているように見えます。

これらすべてより簡単なのは、他の誰かが発明したホイールを使用することです:)セットアップはより複雑になる可能性がありますが、使用するのは簡単です。

これらの手順はWindows 7用です。他のOSに適合させる必要がある場合があります。

ここ からpipを取得してインストールします。

インストールアーカイブをダウンロードし、ルートに抽出しますPythonインストールディレクトリ。コンソールを開いて、次のように入力します(正しく思い出せば):

python get-pip.py install

次に、コンソールで次のコマンドを入力して、pip経由でimage_slicerモジュールを取得してインストールします。

python -m pip install image_slicer

スライスする画像をPythonルートディレクトリにコピーし、pythonシェル(「コマンドライン」ではなく))を開いて、次のコマンドを入力します。

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

このモジュールの美しさは、

  1. Pythonにインストールされています
  2. 2行のコードで分割された画像を呼び出すことができます
  3. 画像スライスパラメータとして任意の偶数を受け入れます(例:この例では14)
  4. そのパラメーターを受け取り、指定された画像を非常に多くのスライスに自動的に分割し、結果として得られた番号付きタイルを同じディレクトリに自動保存し、最後に
  5. 画像タイルをつなぎ合わせる機能があります(まだテストしていません)。ファイルは明らかにimage_slicer.slice関数をテストした後に分割ファイルに表示される規則に基づいて名前を付ける必要があります。
28
Alex Hall

画像をMxNピクセルのタイルに分割する(imが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)]

画像を4つに分割したい場合:

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

tiles [0]は左上のタイルを保持します

17
Nir
  1. cropは、画像保存コードからクロッピングコードを分離すると、より再利用可能な関数になります。また、呼び出しの署名も簡単になります。
  2. _im.crop_は_Image._ImageCrop_インスタンスを返します。このようなインスタンスには、saveメソッドがありません。代わりに、_Image._ImageCrop_インスタンスを新しい_Image.Image_に貼り付ける必要があります
  3. 範囲に適切なステップサイズがありません。 (たとえば、なぜheight?ではなく_height-2_なのか。なぜimgheight-(height/2)?で停止するのか)。

したがって、代わりに次のようなものを試すことができます。

_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

python 3と2の両方で機能する、簡潔で純粋なPythonのソリューションを次に示します。

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

ノート:

  • 元の画像の右と下を超えるトリミングは、元の画像の制限に調整され、元のピクセルのみが含まれます。
    • 2つのchopsize変数を使用し、上のコードで適切にchopsizeを置き換えることにより、wとhに異なるchopsizeを選択するのは簡単です。
  • 2
    RubinMac

    これが最も効率的な答えかどうかはわかりませんが、私にとってはうまくいきます:

    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
    

    これは主にDataScienceGuyの回答に基づいています here

    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

    これは私のスクリプトツールです。css-sprit画像をアイコンに分割するサンプルです。

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

    コードを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

    私は上記の解決策を試しましたが、時々あなたは自分でそれをしなければなりません。場合によっては1ピクセルずれる可能性がありますが、通常は問題なく動作します。

    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
    

    それが役に立てば幸い。

    0
    Baabda

    skimage.util.view_as_windowsまたは `skimage.util.view_as_blocks。これにより、ステップを構成することもできます

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

    0
    Uwais Iqbal