デスクトップ上で「正方形さん」を使いたい
「一眼レフで撮影した縦画像をInstagramに投稿する際、上下がトリミングされてしまう…」
「写真に余白をつけてすっきり見せたい…」
そんな時に重宝していたのが「正方形さん」というアプリ。
このアプリは画像が正方形になるように白埋めしてくれます。
しかし、わざわざスマホ上で一枚一枚変換するのも面倒なので、PC上で一括でできると良いな~と思っていました。
「Ralpha」などのデスクトップ向けフリーソフトもあるようですが、機能としては「写真に余白をつける」程度のものなので、さっと自分で作ってみようと思った次第です。
自作「正方形さん」の使い方
前置きが長くなってしまいました。
環境とソースを見ていきます。
(2022/10/15 Githubにもアップしました。https://github.com/f18c052f/PhotoSquaringApp)
スクリプトを動かすにはディレクトリを下記の通りにしてください。
[作業ディレクトリ]/
├ MrSquare.ipynb
├ img/
│ └ [変換したい画像]
└ output/
あらかじめ、imgフォルダ内に変換したい画像を配置しておき、スクリプト(MrSquare.ipynb)を実行します。
すると、一括で画像が変換され、outputフォルダ内に変換後画像が保存されます。
筆者はJupyter NoteBookで動かしていたため.ipynbとなっていますが、ご自分の環境に合わせて変更してください。
スクリプトはこちら。
# import modules
import cv2
import os
import glob
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# 正方形さん
class MrSquare:
def __init__(self,
path_load='./img/', path_out='./output/',
fill_value=255,
resol_width = 1080, resol_height = 1080):
"""
画像が正方形になるように白埋めする。
【Parameters】
----------
path_load : str
読み込み対象ファイルが入っているディレクトリ
path_out : str
画像の出力先ディレクトリ
fill_value : uint8
余白を埋める色(グレースケール)
Example)255:白, 0:黒
resol_width : uint
出力画像の幅
resol_height : uint
出力画像の高さ
【Functions】
----------
Test :
指定インデックスの変換後画像を表示して確認
※画像は出力されない
Run :
ファイルを一括変換して保存
"""
self.path_load = path_load
self.path_out = path_out
self.fill_value = fill_value
self.resol_width = 1080
self.resol_height = 1080
self.run_flag = False
self.img_lst = glob.glob(self.path_load + '*')
print('Target files are as follows.\n')
for name in self.img_lst:
print(name + '\n')
def Test(self, index=0):
print('-- Test Mode --\n')
self.run_flag = False
try:
self.__squaring(self.img_lst[index])
except:
print('※※※ 指定できるインデックスの範囲を超えています ※※※')
def Run(self):
print('-- Run Mr.Square --\n')
self.run_flag = True
for file in self.img_lst:
self.__squaring(file)
print('-- All Completed!!! --\n')
def __squaring(self, file):
try:
img = cv2.imread(file)
except:
print('※※※ LOAD ERROR ※※※')
img_w = img.shape[1]
img_h = img.shape[0]
img_cannel = img.shape[2]
# キャンバスの生成
canvas = np.full([self.resol_width, self.resol_height, img_cannel],
fill_value=self.fill_value,
dtype='uint8')
if img_w >= img_h:
# 画像が横長の場合
dst_w = self.resol_width
dst_h = round(img_h* (self.resol_width / img_w))
top_edge = abs(round(self.resol_height/2 - dst_h))
left_edge = 0
else:
# 画像が縦長の場合
dst_w = round(img_w* (self.resol_height / img_h))
dst_h = self.resol_height
top_edge = 0
left_edge = abs(round(self.resol_width/2 - dst_w))
dst = cv2.resize(img, dsize=(dst_w, dst_h))
out = canvas.copy()
out[top_edge:top_edge + dst_h , left_edge:left_edge + dst_w] = dst
filename = os.path.split(file)[-1]
if self.run_flag:
# Run Mode
self.__saveImage(out, filename)
else:
# Test Mode
self.__plotImage(img, out, filename)
def __saveImage(self, output_img, filename):
# 画像を保存
cv2.imwrite(os.path.join(self.path_out, 'Resize_'+filename), output_img)
print('Conversion Completed : ' + filename + '\n')
def __plotImage(self, input_img, output_img, filename):
# 画像をプロット
fig, ax = plt.subplots()
ax.imshow(cv2.cvtColor(input_img, cv2.COLOR_BGR2RGB))
ax.set_title('Original')
fig, ax = plt.subplots()
ax.imshow(cv2.cvtColor(output_img, cv2.COLOR_BGR2RGB))
ax.set_title('Converted')
print('Image Name : ' + filename)
plt.show()
# 実行
engine = MrSquare()
engine.Run()
MrSquareクラスの各パラメータ・メソッドについては__init__下のコメントに記載されている通りドキュメント化してあるので、中身を知りたい方はご参考に。
ちなみにですが、Instagramの対応・推奨画像サイズは1080[px]×1080[px]らしいので、その値を出力画像解像度のデフォルト値としています。
上記スクリプトの通り、
# 実行
engine = MrSquare()
engine.Run()
とすれば、一括で画像を変換してくれます。
Target files are as follows.
./img\DSC01164.jpg
./img\DSC01207.jpg
./img\DSC02419 (1).jpg
./img\IMGP9401.jpeg
-- Run Mr.Square --
Conversion Completed : DSC01164.jpg
Conversion Completed : DSC01207.jpg
Conversion Completed : DSC02419 (1).jpg
Conversion Completed : IMGP9401.jpeg
-- All Completed!!! --
imgフォルダ内あった画像が変換されてoutputフォルダ内に画像が保存されています。
「正方形さん」の機能としては以上ですが、他にもいくつか実装した細かい部分について以下でご紹介しておきます。
余白色の設定
通常、余白を白で埋める設定になっていますが、グレースケール範囲で設定できるようにしてあります。
MrSquareクラスのfill_valueパラメータでいじれます。
例えば、
# 実行
engine = MrSquare(fill_value=0)
engine.Run()
テストモード
一括変換する前に個別の写真のビフォーアフターを確認しておきたい、となったときに使用します。
Testメソッドにインデックス番号を渡してあげることで確認できます。
# 実行
engine = MrSquare()
engine.Test(2)