ラベル カメラ の投稿を表示しています。 すべての投稿を表示
ラベル カメラ の投稿を表示しています。 すべての投稿を表示

2023-10-23

被写体が決まっているときの焦点距離ごとの適正距離を求める

やりたいこと

「○cmのものを撮りたいけど、○mの距離だとどれくらいのレンズが必要だろう」というときに試算したい。

計算式

それっぽい値が出るので多分合っているはず。
レンズの製品情報に画角が掲載されているものもあるが、画角はセンサーサイズによって変化するため目安である。
センサーサイズは同じメーカーのフォーマットでも機種により若干サイズが異なることがあるので注意。

d:適正距離[mm]、t:被写体の長さ[mm]、w:センサーの辺の長さ[mm]、l:焦点距離[mm]

例

180cmの人物を全体の90%のサイズで写るよう(=被写体の長さt=2,000[mm])、縦位置で撮影する際の適正距離を調べる。
フルサイズのD850の場合、20mの距離だと300~400mmのレンズが必要だと分かる。
(TDSのミキ広ステージから立ち見中央最前までの距離が約20m)
センサーサイズに比例して適正距離が伸びるため、APS-CのD500だと200~300mmとなる。
逆に14mmのレンズを使うと(最短撮影距離が許せば)78cmの距離まで寄っても全身が余裕で写る、という計算らしい。ほんとか?

焦点距離
[mm]
フルサイズ(D850)APS-C(D500)フルサイズ(D850)
水平画角
[rad]
垂直画角
[rad]
水平画角
[rad]
垂直画角
[rad]
180cm 90%
適正距離[m]
102.131.751.731.330.56
141.821.411.401.020.78
201.461.081.060.751.11
241.280.920.910.631.34
350.950.660.650.441.95
500.690.470.460.312.79
700.500.340.330.223.90
850.420.280.270.184.74
1050.340.230.220.155.85
1350.260.180.170.127.52
2000.180.120.120.0811.14
3000.120.080.080.0516.71
4000.090.060.060.0422.28
5000.070.050.050.0327.86
6000.060.040.040.0333.43

2023-10-22

写真を正方形化して余白にExif情報を載せる

 やりたいこと

インスタに写真をアップロードするにあたり正方形にしたい。
アスペクト比を維持したまま正方形にすると余白が生じるが、なんか寂しいのでExif情報(カメラやレンズ、撮影時の設定など)を入れてそれっぽくしたい。

処理のイメージ

方針

0.NEF(NikonのRAWファイル)を現像してTIFFで保存する。
1.インスタは長辺1024pxが良いらしいので、バカでかい画像を縮小する。
2.1024pxの正方形になるよう短辺に黒い余白を付ける。
3.TIFFからExif情報を取得して余白に文字を挿入する。
4.JPEGで保存する。

TIFFをドラッグアンドドロップすると1~4を処理して同じフォルダにインスタにアップできるJPEGが生成されるようにしたい。
1~4の処理はpythonにやらせるが、ドラッグアンドドロップでpythonを呼び出すためにWindowsのバッチファイルを中継させる。
これだと単ファイルしか対応できないので複数ファイルを処理するためには小細工が必要。

@echo off
python exif.py %~f1

準備

ローカルでpythonを動かせる環境を構築する。
ソースと同じフォルダにExif情報取得用のexiftool.exeをダウンロードして置いておく。
(piexifだとレンズ情報が取得できなかった)

処理

ファイルパス準備

args = sys.argv
fn_dir = os.path.dirname(args[1])
fn_without_ext = os.path.splitext(os.path.basename(args[1]))[0]

ドラッグアンドドロップされたファイルのフルパスはargs[1]に読み込まれる。
フォルダ(フルパス)とファイル名(拡張子なし)に分離しておく。

画像読み込み

im_tif = Image.open(args[1])
w, h = im_tif.size

TIFFを読み込み、元の画像サイズを取得しておく。

画像描画

im_sq = Image.new(im_tif.mode, (1024, 1024), (0, 0, 0))
resize_rate = 1024 / (w if w > h else h)
im_tif_resize = im_tif.resize(size=(round(w * resize_rate), round(h * resize_rate)), resample=Image.BICUBIC)
w, h = im_tif_resize.size
im_sq.paste(im_tif_resize, (int((1024 - w) / 2), int((1024 - h) / 2)))
if w < h:
    im_sq = im_sq.rotate(270)

1024pxの黒い正方形を作成する。
アスペクト比を維持したまま縮小するため、長辺が1024pxになるような縮小率を計算し、resize()で縮小する。resampleにはPhotoshopで縮小するときと同じバイキュービック法を指定する。
リサイズ後の画像サイズを取得し、黒い正方形の上下中央に配置する。
縦写真の場合、右側の余白に首を左に90度傾けて読めるように文字を配置するため、画像を時計回りに90度回転しておく。

Exif情報取得

cmd = 'exiftool -j -s -LensID -Model -DateTimeOriginal -ExposureTime -FNumber -ISO -FocalLength ' + args[1]
json = json.loads(subprocess.check_output(cmd, shell=True).decode())
pattern = re.compile(r'^(\d+):(\d+):(\d+) ')
result = pattern.search(json[0]['DateTimeOriginal'])

exiftool.exeを実行するコマンドを準備する。
jオプションでJSONで返すよう指定し、取得したいタグを書いていく。タグ一覧はオプション無し(exiftool ファイル名)で実行したら確認できるが、それで表示されるタグ名はオプションと異なることがあるため注意(jオプションで返ってくるタグ名が使用できる)。
subprocessでコマンドを実行し、結果をデコード、さらにjsonとして変数に格納する。
撮影日時はなぜか「YYYY:MM:DD」形式なので、「YYYY/MM/DD」形式にするためにそれぞれの数字を分解しておく。

Exif情報描画

def add_text(left, top, text):
    draw = ImageDraw.Draw(im_sq)
    draw.text((left, top), text, (64, 64, 64), font=ImageFont.truetype(【フォントのフルパス】, 15))

add_text(21, 954, result.group(1) + '/' + result.group(2) + '/' + result.group(3))
add_text(21, 971, json[0]['Model'] + ', ' + json[0]['LensID'].replace('Zoom-', '').replace('Nikkor', 'NIKKOR'))
add_text(21, 988, json[0]['ExposureTime'] + ', F' + str(json[0]['FNumber']) + ', ISO ' + str(json[0]['ISO']) + ', ' + json[0]['FocalLength'])

テキストを描画するための関数を用意する。フォントのフルパスはWindowsの場合「\」を使用するが、エスケープとして認識されるため「\\」とする。
1段目に日付を入れる。さっきキャプチャした数字を使う。
2段目にカメラ、レンズの情報を入れる。一部のレンズで「Zoom-」が付加されていたが、公式HPの製品名には入っていないため取り除く。「Nikkor」の表記も同様。
3行目にSS、絞り、ISO感度、焦点距離を入れる。

保存

if w < h:
    im_sq = im_sq.rotate(90)
im_sq.save(fn_dir + '\\' + fn_without_ext + '_exif.jpg', quality=95)

縦写真の場合元の向きに戻し、元ファイル名に「_exif」を付加して最高品質のJPEGで保存する。

ソース

# -*- coding: utf-8 -*-
from PIL import Image, ImageDraw, ImageFont
import sys
import os
import re
import subprocess
import json

def add_text(left, top, text):
    draw = ImageDraw.Draw(im_sq)
    draw.text((left, top), text, (64, 64, 64), font=ImageFont.truetype(【フォントのフルパス】, 15))

args = sys.argv

#ファイルパス取得
fn_dir = os.path.dirname(args[1])
fn_without_ext = os.path.splitext(os.path.basename(args[1]))[0]

# 画像サイズ取得
im_tif = Image.open(args[1])
w, h = im_tif.size

# キャンバス準備
im_sq = Image.new(im_tif.mode, (1024, 1024), (0, 0, 0))
resize_rate = 1024 / (w if w > h else h)
im_tif_resize = im_tif.resize(size=(round(w * resize_rate), round(h * resize_rate)), resample=Image.BICUBIC)
w, h = im_tif_resize.size
im_sq.paste(im_tif_resize, (int((1024 - w) / 2), int((1024 - h) / 2)))
if w < h:
    im_sq = im_sq.rotate(270)

# Exif情報描画
cmd = 'exiftool -j -s -LensID -Model -DateTimeOriginal -ExposureTime -FNumber -ISO -FocalLength ' + args[1]
json = json.loads(subprocess.check_output(cmd, shell=True).decode())
pattern = re.compile(r'^(\d+):(\d+):(\d+) ')
result = pattern.search(json[0]['DateTimeOriginal'])
add_text(21, 954, result.group(1) + '/' + result.group(2) + '/' + result.group(3))
add_text(21, 971, json[0]['Model'] + ', ' + json[0]['LensID'].replace('Zoom-', '').replace('Nikkor', 'NIKKOR'))
add_text(21, 988, json[0]['ExposureTime'] + ', F' + str(json[0]['FNumber']) + ', ISO ' + str(json[0]['ISO']) + ', ' + json[0]['FocalLength'])

if w < h:
    im_sq = im_sq.rotate(90)
im_sq.save(fn_dir + '\\' + fn_without_ext + '_exif.jpg', quality=95)