Pythonを使用してOpenCVで画像をトリミングする方法


234

以前にPILで行ったように、OpenCVを使用して画像をトリミングする方法を教えてください。

PILの作業例

im = Image.open('0.png').convert('L')
im = im.crop((1, 1, 98, 33))
im.save('_0.png')

しかし、どうすればOpenCVでそれを実行できますか?

これは私が試したものです:

im = cv.imread('0.png', cv.CV_LOAD_IMAGE_GRAYSCALE)
(thresh, im_bw) = cv.threshold(im, 128, 255, cv.THRESH_OTSU)
im = cv.getRectSubPix(im_bw, (98, 33), (1, 1))
cv.imshow('Img', im)
cv.waitKey(0)

しかし、それは機能しません。

私は間違って使用したと思いますgetRectSubPix。その場合は、この機能の使い方を教えてください。

回答:


528

とても簡単です。派手なスライスを使用します。

import cv2
img = cv2.imread("lenna.png")
crop_img = img[y:y+h, x:x+w]
cv2.imshow("cropped", crop_img)
cv2.waitKey(0)

9
うーん...しかし、作物の画像を変数に保存するにはどうすればよいですか?
Nolik

56
覚えているのxおよびyが反転しています。私はこれを逃した。
markroxor

10
または、作物マージンを定義している場合は、次のようにできますcrop_img = img[margin:-margin, margin:-margin]
Rufus

39
これは素晴らしいです。crop_imgを変更するとimgも変更されることに注意してください。それ以外の場合は、crop_img = img [y:y + h、x:x + w] .copy()
user1270710 '27 / 10/27

1
@javadba numpy実装の詳細。Numpyはcol、rowの代わりにrow、col表記を使用
Froyo

121

私はこの質問を持っていて、ここに別の答えを見つけました:関心領域をコピー

(0,0)を画像の左上隅と見なすとim、左から右にx方向、上から下にy方向で呼び出されます。そして、その画像内の長方形領域の左上頂点として(x1、y1)、右下頂点として(x2、y2)があり、次のようになります。

roi = im[y1:y2, x1:x2]

numpy配列のインデックス付けとスライスに関する包括的なリソースは、画像の一部のトリミングなどについて詳しく説明しています。画像はopencv2にnumpy配列として保存されます。

:)


こんにちは、あなたの状況では `roi = im [y1:y2 + 1、x1:x2 + 1]`にすべきではありませんか?numpyは除外された領域を使用してスライスするためです。
スコットヤン

@ samkhan13、この式を使用してトリミングすると、すべてのトリミングが形状(0、幅、チャネル)になります。すなわち。私はy次元をまったく取得していません
mLstudent33

@ mLstudent33画像imが正しく読み取られておらず、空である可能性があります。ブレークポイントを備えたIDEを使用して、コードを段階的に診断してください。あなたが使用することができ、Googleのコラボをコードブロックを作成し、上のjupytorのノートブックを共有することができstackoverflowのPythonのチャットルーム誰かの助けを得るために。
samkhan13

:@ samkhan13実際に私はGithubのOpenCVの問題に掲載することを奇妙な問題が持って github.com/opencv/opencv/issues/15406を、私はうまくとしてチャットをチェックアウトします。ありがとう!
mLstudent33

16

画像スライスは、のコピーを作成していない、なおcropped imageが、作成pointerしますroi。非常に多くの画像をロードし、スライスを使用して画像の関連部分をトリミングし、リストに追加する場合、これは巨大なメモリの浪費になる可能性があります。

それぞれがN個の画像をロードし、左上隅からの領域>1MPのみが必要であるとします100x100

Slicing

X = []
for i in range(N):
    im = imread('image_i')
    X.append(im[0:100,0:100]) # This will keep all N images in the memory. 
                              # Because they are still used.

または、関連パーツをでコピーして、.copy()ガベージコレクターが削除するようにすることもできますim

X = []
for i in range(N):
    im = imread('image_i')
    X.append(im[0:100,0:100].copy()) # This will keep only the crops in the memory. 
                                     # im's will be deleted by gc.

これを見つけた後、私はuser1270710によるコメントの1つにそれが言及されていることに気付きましたが、見つけるのにかなりの時間がかかりました(つまり、デバッグなど)。だから、言及する価値があると思います。


これを見てください:stackoverflow.com/q/60359398/7644562
Abdul Rehman

メモリ領域が占有されているという意味では、関心領域をコピーすることが最善の方法であると理解していますが、時間のかかるものはどうでしょうか?copy()ROIを行うと、スライスと比較して、結果はどうなりますか?また、tmpコンピューターから読み込んだ各画像を格納する変数がある場合、スライスによってメモリに悪影響が及ぶことはないはずですよね?あなたが説明する問題は、すべての画像を読み込んでから、元の画像とROIの両方を保持してROIを再度保存したときに起こることにのみ関連しています正しく理解できたかどうかをお知らせください。
カタリナSIRBU

私が言った場合、コピーは無視できる時間です。大きな画像を何度もコピーしない限り、時間差はありません。私のコードでは、効果はトリミングごとに1ミリ秒未満のようになります。問題は、大きな画像とポインター(ROIはほんの数バイト)を格納するか、小さな画像をメモリ(私の場合)に格納することです。これを数回行う場合は問題ありません。ただし、これを何千回も実行すると、スライスによってメモリ使用量が異常になります。あなたがスライスする場合、数千の画像をロードする場合、2、3の後にメモリ全体を埋めるように。一方、MBの場合、私のコードは引き続き注文されます
smttsp

12

このコードは、x = 0、y = 0の位置からh = 100、w = 200まで画像をトリミングします

import numpy as np
import cv2

image = cv2.imread('download.jpg')
y=0
x=0
h=100
w=200
crop = image[y:y+h, x:x+w]
cv2.imshow('Image', crop)
cv2.waitKey(0) 

@hatamiなので、高さは100ピクセル "下"ですy = 0でしょ?numpy配列の101行目ですか?そして幅はx = 0の右200ピクセルです正しいですか?
mLstudent33

4

以下は画像をトリミングする方法です。

image_path:編集する画像へのパス

coords: x / y座標のタプル(x1、y1、x2、y2)[mspaintで画像を開き、ビュータブの[ルーラー]をチェックして座標を確認します]

saved_location:トリミングされた画像を保存するためのパス

from PIL import Image
    def crop(image_path, coords, saved_location:
        image_obj = Image.open("Path of the image to be cropped")
            cropped_image = image_obj.crop(coords)
            cropped_image.save(saved_location)
            cropped_image.show()


if __name__ == '__main__':
    image = "image.jpg"
    crop(image, (100, 210, 710,380 ), 'cropped.jpg')

3

opencv copy border関数を使用した堅牢なクロップ:

def imcrop(img, bbox):
   x1, y1, x2, y2 = bbox
   if x1 < 0 or y1 < 0 or x2 > img.shape[1] or y2 > img.shape[0]:
        img, x1, x2, y1, y2 = pad_img_to_fit_bbox(img, x1, x2, y1, y2)
   return img[y1:y2, x1:x2, :]

def pad_img_to_fit_bbox(img, x1, x2, y1, y2):
    img = cv2.copyMakeBorder(img, - min(0, y1), max(y2 - img.shape[0], 0),
                            -min(0, x1), max(x2 - img.shape[1], 0),cv2.BORDER_REPLICATE)
   y2 += -min(0, y1)
   y1 += -min(0, y1)
   x2 += -min(0, x1)
   x1 += -min(0, x1)
   return img, x1, x2, y1, y2

あなたはBBOXがここには何か説明していただけますと、私は合格しようとしているどのような値私たちはその価値に与えることになっていること、それは私が上にエラー与えているので x1,y1,x2,y2 = bbox 言いながら:TypeError: 'int' object is not iterable
サバ

3

これはより堅牢なimcropのコードです(MATLABのように少し)

def imcrop(img, bbox): 
    x1,y1,x2,y2 = bbox
    if x1 < 0 or y1 < 0 or x2 > img.shape[1] or y2 > img.shape[0]:
        img, x1, x2, y1, y2 = pad_img_to_fit_bbox(img, x1, x2, y1, y2)
    return img[y1:y2, x1:x2, :]

def pad_img_to_fit_bbox(img, x1, x2, y1, y2):
    img = np.pad(img, ((np.abs(np.minimum(0, y1)), np.maximum(y2 - img.shape[0], 0)),
               (np.abs(np.minimum(0, x1)), np.maximum(x2 - img.shape[1], 0)), (0,0)), mode="constant")
    y1 += np.abs(np.minimum(0, y1))
    y2 += np.abs(np.minimum(0, y1))
    x1 += np.abs(np.minimum(0, x1))
    x2 += np.abs(np.minimum(0, x1))
    return img, x1, x2, y1, y2

1

または、トリミングにテンソルフローを使用し、画像から配列を作成するためにopenCVを使用することもできます。

import cv2
img = cv2.imread('YOURIMAGE.png')

これimgは(imageheight、imagewidth、3)形状配列です。tensorflowで配列をクロップします。

import tensorflow as tf
offset_height=0
offset_width=0
target_height=500
target_width=500
x = tf.image.crop_to_bounding_box(
    img, offset_height, offset_width, target_height, target_width
)

tf.kerasを使用してイメージを再構成し、うまくいったかどうかを確認できるようにします。

tf.keras.preprocessing.image.array_to_img(
    x, data_format=None, scale=True, dtype=None
)

これは写真をノートブックに印刷します(Google Colabでテスト済み)。


コード全体を一緒に:

import cv2
img = cv2.imread('YOURIMAGE.png')

import tensorflow as tf
offset_height=0
offset_width=0
target_height=500
target_width=500
x = tf.image.crop_to_bounding_box(
    img, offset_height, offset_width, target_height, target_width
)

tf.keras.preprocessing.image.array_to_img(
    x, data_format=None, scale=True, dtype=None
)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.