質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2627閲覧

【サムネイル画像作成用】フォルダ内の様々なサイズの画像を、縦横の短い辺を基準に、はみ出しても構わないから特定のサイズ枠いっぱいに収まるように一括でサイズ調整をしたい。

shakariki

総合スコア5

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/01/14 02:37

サムネイル画像用に800×600サイズの枠いっぱいに収まる画像をつくる必要があります。
フォルダ内にある様々なサイズの画像を、縦横比は変えずに枠に一括でサイズ変更をしたいです。
教本を参考に色々とコードを書いてみたのですが、上手く動かずで困っております。
下記のコードでなくても構わないのですが、どう修正すれば、解消出来ますでしょうか。

・枠に収める基準
画像縦横の、短い辺を基準に拡大または縮小したいです。

・サムネイルの内容
部屋や料理の写真を収めます。長い辺の部分が切れても構わないです。

from pathlib import Path from PIL import Image box_size_width = 800 box_size_height = 600 input_folder = Path('images') output_folder = Path('resize_fill_box') output_folder.mkdir(exist_ok=True) for f in input_folder.glob('*'): img = Image.open(f) width, height = img.size ratio_width = box_size_width / min(img.size) ratio_height =box_size_height / min(img.size) resized_img = img.resize((int(width * ratio_width), int(height * ratio_height))) if width > height: strip_size = resized_img.size[0] - box_size_width cropped_img = resized_img.crop(( strip_size / 2, 0, resized_img.size[0] - strip_size / 2, resized_img.size[1] )) elif width < height: strip_size = resized_img.size[0] - box_size_height cropped_img = resized_img.crop(( 0, strip_size / 2, resized_img.size[0], resized_img.size[1] - strip_size / 2 )) elif width == height: img.resize((800 , 600)) save_path = output_folder.joinpath(f.name) cropped_img.save(save_path) img.close()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2020/01/14 03:45

どのように「上手く動かず」なのでしょうか?
shakariki

2020/01/14 08:57

meg_さん ご確認ありがとうございます! 切り出した画像のサイズがバラバラになってしまったり、出力自体がされなかったりです。 全ての画像を800×600の枠に収めるというか、ピッタリになるまでアスペクト比を変えずに縦横を拡大or縮小したく。
guest

回答1

0

ベストアンサー

考え方

元の画像サイズ (w, h)
サムネイルサイズ (box_w, box_h)
とした場合、サムネイルの大きさ一杯に収まるようにアスペクト比を変えないでリサイズするという処理は

w * scale <= box_w
h * scale <= box_h

という制約条件を満たす scale の最大化問題になります。
変形すると、

scale <= box_w / w
scale <= box_h / h

となるので、これを満たす最大の scale は min(box_w / w, box_h / h) になります。

python

1from pathlib import Path 2 3from PIL import Image 4 5 6def get_img_paths(img_dir): 7 """画像のパスを取得する。 8 """ 9 IMG_EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp") 10 img_paths = [p for p in img_dir.iterdir() if p.suffix in IMG_EXTENSIONS] 11 12 return img_paths 13 14 15def resize(img, box_size, border=True): 16 """ 17 """ 18 box_width, box_height = box_size 19 scale_x = box_width / img.width 20 scale_y = box_height / img.height 21 scale = min(scale_x, scale_y) 22 23 # リサイズ後の大きさを計算する。 24 new_width = int(img.width * scale) 25 new_height = int(img.height * scale) 26 27 # リサイズする。 28 resized = img.resize((new_width, new_height)) 29 30 if border: 31 # 画枠をつける場合 32 new_img = Image.new("RGB", box_size) 33 34 paste_x = (box_width - new_width) // 2 35 paste_y = (box_height - new_height) // 2 36 new_img.paste(resized, (paste_x, paste_y)) 37 38 return new_img 39 else: 40 return resized 41 42 43box_size = (400, 400) # サムネイルの大きさ 44input_dir = Path("samples") 45output_dir = Path("resized") 46output_dir.mkdir(exist_ok=True) 47 48for path in get_img_paths(input_dir): 49 # 画像を読み込む。 50 img = Image.open(path) 51 52 # リサイズする。 53 resized = resize(img, box_size) 54 print(f"{path.name}: {img.size} --> {resized.size}") 55 56 # 保存する。 57 resized.save(output_dir / path.name)

イメージ説明

イメージ説明

追記

  1. アスペクト比を固定して、短辺をサムネイル枠に合わせてリサイズする。
  2. リサイズした画像を、画像の中心を基準にして、サムネイル枠に合わせてクロップする。

イメージ説明

python

1from pathlib import Path 2 3from PIL import Image 4 5 6def get_img_paths(img_dir): 7 """画像のパスを取得する。 8 """ 9 IMG_EXTENSIONS = (".jpg", ".jpeg", ".png", ".bmp") 10 img_paths = [p for p in img_dir.iterdir() if p.suffix in IMG_EXTENSIONS] 11 12 return img_paths 13 14 15def resize(img, box_size): 16 box_width, box_height = box_size 17 scale_x = box_width / img.width 18 scale_y = box_height / img.height 19 scale = max(scale_x, scale_y) 20 21 # リサイズ後の大きさを計算する。 22 if scale_x > scale_y: 23 new_width = box_width 24 new_height = int(img.height * scale) 25 else: 26 new_width = int(img.width * scale) 27 new_height = box_height 28 29 # リサイズする。 30 resized = img.resize((new_width, new_height)) 31 32 # 中心で切り抜く 33 left = (new_width - box_width) // 2 34 top = (new_height - box_height) // 2 35 right = (new_width + box_width) // 2 36 bottom = (new_height + box_height) // 2 37 cropped = resized.crop((left, top, right, bottom)) 38 return cropped 39 40 41box_size = (800, 400) # サムネイルの大きさ 42input_dir = Path("samples") 43output_dir = Path("resized") 44output_dir.mkdir(exist_ok=True) 45 46for path in get_img_paths(input_dir): 47 # 画像を読み込む。 48 img = Image.open(path) 49 50 # リサイズする。 51 resized = resize(img, box_size) 52 print(f"{path.name}: {img.size} --> {resized.size}") 53 54 # 保存する。 55 resized.save(output_dir / path.name)

イメージ説明

イメージ説明

投稿2020/01/14 06:25

編集2020/01/14 09:36
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shakariki

2020/01/14 09:01

tiitoiさん ありがとうございます!イメージに非常に近いです! イルカの例でいきますと、黒枠の部分になるまでアスペクト比を変えずに縦幅を上げるにはどのようにすればよいでしょうか。もしくは横に黒枠がある場合に、横幅を枠ピッタリになるまで拡大をしたいです。 全ての画像を800×600の枠にピッタリになるまでアスペクト比を変えずに縦横を拡大or縮小したく。
tiitoi

2020/01/14 09:04

回答のコードでそうなっていないでしょうか? アスペクト比を変えないでリサイズした場合、縦または横に余りが出てくるので、そこを黒にしたのはおまけです。 回答のコードで border=False にした場合は黒枠をつけないようになります。
tiitoi

2020/01/14 09:08

すいません。質問の意図を勘違いしていました。 長い辺は切り捨てるようにするのですね。修正するので、少々お待ち下さい
shakariki

2020/01/14 09:17

こちらこそ、言葉足らずでご面倒をお掛けして申し訳ありません。 どうしても解決できず困っていたので非常に感謝しております。
tiitoi

2020/01/14 09:38

追記しました。 余りが出てくるので、中心で切り抜くようにしています。 中心でない部分で切り抜きたい場合は、 resized.crop((left, top, right, bottom)) の切り抜く範囲を適宜変更してください。
shakariki

2020/01/15 04:54

tiitoiさん イメージ通りに抽出することができました!迅速にご対応頂きまして非常に助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問