Numpyリサイズ/リスケール画像


95

それは派手な配列ですが、画像を取得して画像のスケールを変更したいと思います。

たとえば、コカ・コーラのボトルの画像があります: bottle-1

これは形状の派手な配列に変換され、(528, 203, 3)この2番目の画像のサイズを示すためにサイズを変更したいと思います: bottle-2

の形をしてい(140, 54, 3)ます。

元の画像を維持したまま、画像のサイズを特定の形に変更するにはどうすればよいですか?他の答えは、1行おきまたは3行目を取り除くことをお勧めしますが、私がしたいことは、基本的には画像エディターを介して、Pythonコードで行う方法と同じように画像を縮小することです。numpy / SciPyでこれを行うライブラリはありますか?


numpy配列のコードを表示できますか?
ShpielMeister 2018年


2
@saschaリンクしたページによると、非推奨です。
Paul Panzer、

@ShpielMeister IntelliJにnumpy配列を完全に出力させることができません。何らかの理由で出力が大きくなると、常に出力されます。そのため、コンソールの出力の一部しか表示されません
Brian Hamill

回答:


118

ええ、インストールしてopencv(これは画像処理とコンピュータービジョンに使用するライブラリです)、cv2.resize関数を使用できます。そして例えば使用:

import cv2
import numpy as np

img = cv2.imread('your_image.jpg')
res = cv2.resize(img, dsize=(54, 140), interpolation=cv2.INTER_CUBIC)

imgしたがって、ここでは元の画像resを含むnumpy配列が、サイズ変更された画像を含むnumpy配列です。重要な側面はinterpolationパラメータです。画像のサイズを変更する方法はいくつかあります。特に画像を縮小しているため、元の画像のサイズは、サイズ変更後の画像のサイズの倍数ではありません。可能な補間スキーマは次のとおりです。

  • INTER_NEAREST -最近傍内挿
  • INTER_LINEAR -バイリニア補間(デフォルトで使用)
  • INTER_AREA-ピクセルエリアリレーションを使用したリサンプリング。モアレのない結果が得られるため、画像の間引きには推奨される方法です。しかし、画像がズームされている場合、それはINTER_NEAREST方法に似てい ます。
  • INTER_CUBIC -4x4ピクセル近傍のバイキュービック補間
  • INTER_LANCZOS4 -8x8ピクセル近傍のLanczos補間

ほとんどのオプションと同様に、すべてのサイズ変更スキーマについて、1つの戦略が別の戦略よりも優先されるシナリオがあるという意味で、「最良の」オプションはありません。


5
私はこのコードを試したところ、うまくいきました!ただ1つの変更は、xとyを取るdsize必要があるdsize=(54, 140)ことです。numpy配列はyとxの形を示します(yは行数、xは列数です)
Brian Hamill

5
私はcv2を避けようとします、それはBGRチャネル形式で次元を交換してロードします。私は好むskimage.io.imread('image.jpg')skimage.transform.resize(img)scikit-image.org/docs/dev/install.html
Eduardo Pignatelli

1
@EduardoPignatelli使用する補間アルゴリズムを制御できないため、skimage.transform.resizeは使用しません。しかし、人々のユースケースによっては、それは重要ではないかもしれません。
Decker、

1
@Decker skimage.transform.resizeは、「order」パラメーターを介していくつかの制御を提供します。order = 0は最近傍、1 = bi-linear、2 = bi-quadratic、3 = bi-cubicなどです。ただし、面積平均やランチョス補間はありません。
Tapio Friberg、

1
@TapioFribergああ、はい、私は修正された状態です。skimage.transform.warpの 'order'パラメータのドキュメントで定義されているアルゴリズムが表示されます。ある時点で、ドキュメントを更新して、タイプの参照を含めると役立つ場合があります。たとえば、「Bi-quartic」はドキュメントの他の場所で定義されていません(2019年12月10日現在)-ワンライナー将来のユーザーにとって有益である。
Decker

64

これを行うためにnumpyを単独で使用することは可能かもしれませんが、操作は組み込みではありません。そうは言っても、scikit-image(numpyに基づいて構築された)を使用して、この種の画像操作を行うことができます。

Scikit-Imageの再スケーリングのドキュメントはこちらです。

たとえば、イメージを使用して次のことを行うことができます。

from skimage.transform import resize
bottle_resized = resize(bottle, (140, 54))

これにより、補間、アンチエイリアスなどが処理されます。


2
ありがとうございました!この答えも機能します!anti_aliasingフラグに関する問題が発生していますが、最新バージョン0.13.1
ブライアンハミル

8
これは、元の画像がuint8であっても、float ndarray として画像を返します
sziraqui

3
これは、任意の数のチャネルで機能するため、優れた手法です。私はこれを深度点群データと組み合わせたrgbデータで試してみたところ、希望通りの関係が維持されました。
Darth Egregious

@DarthEgregious、jakevdp->説明した方法のように(137,236,3)配列を(64,64)にサイズ変更すると、ランダムノイズデータが単色になりました。すべての情報が失われたように見えるため、これは正常ですか?
Deshwal

1
(64,64,3)である必要はありません
Darth Egregious

14

numpy機械学習アプリケーションで使用するために配列内の画像をダウンサンプリングする高速な方法を探しているGoogleからここに来る人々のために、ここに超高速の方法があります(ここから適応)。このメソッドは、入力ディメンションが出力ディメンションの倍数である場合にのみ機能します。

次の例では、128x128から64x64にダウンサンプリングします(これは簡単に変更できます)。

チャンネルの最後の注文

# large image is shape (128, 128, 3)
# small image is shape (64, 64, 3)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((output_size, bin_size, 
                                   output_size, bin_size, 3)).max(3).max(1)

チャネルの最初の注文

# large image is shape (3, 128, 128)
# small image is shape (3, 64, 64)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((3, output_size, bin_size, 
                                      output_size, bin_size)).max(4).max(2)

グレースケール画像の場合3、次の1ようにをaに変更します。

チャネルの最初の注文

# large image is shape (1, 128, 128)
# small image is shape (1, 64, 64)
input_size = 128
output_size = 64
bin_size = input_size // output_size
small_image = large_image.reshape((1, output_size, bin_size,
                                      output_size, bin_size)).max(4).max(2)

このメソッドは、最大プーリングと同等のものを使用します。私が見つけたのは、これを行う最も速い方法です。


4
large_image [:, :: 2、:: 2]は、半分の解像度で画像を返します。
L.Kärkkäinen19年

1
@LasseKärkkäinenですが、ダウンサンプリングは行われず、他のすべてのピクセルが選択されるだけです。違いは、最終的な関数 'max'を変更して、ピクセルを選択または計算する方法を少し改善した点です(たとえば、 'min'または 'mean'を使用)。あなたの方法はそれが問題ではない場合、便利です(そしてより高速です)。
Waylon Flinn

@L.Kärkkäinen解像度を倍にするためにこれの反対は何ですか?
rayzinnz

2
@rayzinnznp.repeat(np.repeat(a, 2, axis=0), 2, axis=1)
L.Kärkkäinen

8

追加のライブラリを使用せずに、Pythonで画像を拡大/縮小する簡単な方法を探している人がいる場合は、非常に簡単な画像サイズ変更関数を次に示します。

#simple image scaling to (nR x nC) size
def scale(im, nR, nC):
  nR0 = len(im)     # source number of rows 
  nC0 = len(im[0])  # source number of columns 
  return [[ im[int(nR0 * r / nR)][int(nC0 * c / nC)]  
             for c in range(nC)] for r in range(nR)]

使用例:(30 x 30)画像のサイズを(100 x 200)に変更:

import matplotlib.pyplot as plt

def sqr(x):
  return x*x

def f(r, c, nR, nC):
  return 1.0 if sqr(c - nC/2) + sqr(r - nR/2) < sqr(nC/4) else 0.0

# a red circle on a canvas of size (nR x nC)
def circ(nR, nC):
  return [[ [f(r, c, nR, nC), 0, 0] 
             for c in range(nC)] for r in range(nR)]

plt.imshow(scale(circ(30, 30), 100, 200))

出力: スケーリングされた画像

これは画像を縮小/拡大するために機能し、numpy配列でうまく機能します。


4

SciPyのimresize()メソッドは別のサイズ変更メソッドでしたが、SciPy v 1.3.0以降では削除される予定です。SciPyはPIL画像のサイズ変更方法を指します:Image.resize(size, resample=0)

size –要求されたピクセル単位のサイズ。2タプル(幅、高さ)。
resample –オプションのリサンプリングフィルター。これは、PIL.Image.NEAREST(最近傍を使用)、PIL.Image.BILINEAR(線形補間)、PIL.Image.BICUBIC(3次スプライン補間)、またはPIL.Image.LANCZOS(高品質のダウンサンプリングフィルター)のいずれかになります。 )。省略した場合、または画像のモードが「1」または「P」の場合は、PIL.Image.NEARESTが設定されます。

ここにリンク:https : //pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.resize


3
残念ながら、imresize()は非推奨です。SciPy1.3.0で削除されます
MiniQuark

1

numpy / SciPyにこれを行うためのライブラリはありますか

承知しました。これは、OpenCV、scikit-image、またはPILなしで実行できます。

画像のサイズ変更は、基本的に各ピクセルの座標を元の画像からそのサイズ変更された位置にマッピングします。

画像の座標は整数である必要があるため(マトリックスと考えると)、マップされた座標に小数値がある場合は、ピクセル値を補間して整数位置に近似する必要があります(たとえば、その位置に最も近いピクセルを取得することは既知です)最近傍補間として)。

必要なのは、この補間を行う関数だけです。SciPyは持っていinterpolate.interp2dます。

これを使用してarr、次のようにnumpy配列の画像のサイズを変更できます。

W, H = arr.shape[:2]
new_W, new_H = (600,300)
xrange = lambda x: np.linspace(0, 1, x)

f = interp2d(xrange(W), xrange(H), arr, kind="linear")
new_arr = f(xrange(new_W), xrange(new_H))

もちろん、画像がRGBの場合は、チャネルごとに補間を実行する必要があります。

詳細を知りたい場合は、「画像のサイズ変更-コンピュータファン」をご覧になることをお勧めします。


この回答に基づいて動作しない場合がありますstackoverflow.com/questions/37872171/...
random_dsp_guy

0
import cv2
import numpy as np

image_read = cv2.imread('filename.jpg',0) 
original_image = np.asarray(image_read)
width , height = 452,452
resize_image = np.zeros(shape=(width,height))

for W in range(width):
    for H in range(height):
        new_width = int( W * original_image.shape[0] / width )
        new_height = int( H * original_image.shape[1] / height )
        resize_image[W][H] = original_image[new_width][new_height]

print("Resized image size : " , resize_image.shape)

cv2.imshow(resize_image)
cv2.waitKey(0)

4
StackOverflowへようこそ。質問に答えて他の人を助けたいと思います。ただし、cv2最近の内挿よりも劣る「次善の」サイズ変更関数を再実装する代わりに、適切なサイズ変更関数をすでに使用および使用している既存の回答と比較して、あなたの回答がどのように価値を追加するかはわかりません。
NOhs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.