之前看到一个说法,如果一个变焦用户,想要买定焦镜头,但是不知道买哪个焦段,可以统计自己的拍摄照片,辅助判断。
然后看到一个博文,用 Python3 写代码进行的统计,于是我针对 RX100 黑卡相机做了调整,去掉了内置绘图,输出了 CSV,可以用在线工具导入展示,另外针对常用焦段,让近邻的焦段按比例汇总到常用焦段,图表上看的会更清晰。
示例图像
可以用于测试以下代码
焦距统计(Python 实现)
import exifread
import os
# 常用焦距
usual_focals = [16, 24, 28, 35, 50, 85, 105, 200, 300, 400]
def approximate_focal(focal):
for usual in usual_focals:
aggregation_range = int(usual / 8)
if focal > usual - aggregation_range and focal < usual + aggregation_range:
return usual
return focal
def save_csv_format(dic):
header = ','.join([str(item) for item in dic.keys()])
content = ','.join([str(item) for item in dic.values()])
with open("focal.csv", 'w', encoding='utf-8') as file:
file.write(header + "\n")
file.write(content)
def run():
dic = {}
for root, dirs, files in os.walk(".", topdown=False):
for name in files:
fname = os.path.join(root, name)
if '.jpg' not in fname.lower():
continue
file = open(fname, "rb")
tags = (exifread.process_file(file))
file.close()
# tags['EXIF FocalLength'] tags['Image Make'] tags['Image Model']
if 'EXIF FocalLengthIn35mmFilm' in tags.keys():
realfocal = int(str(tags['EXIF FocalLengthIn35mmFilm']))
nearfocal = approximate_focal(realfocal)
else:
continue
if nearfocal in dic.keys():
dic[nearfocal] += 1
else:
dic[nearfocal] = 1
dic = dict(sorted(dic.items(), key=lambda x:x[0]))
print(dic)
save_csv_format(dic)
if __name__ == "__main__":
run()
我测试的图像大概有 3300 张照片,16G 大小,运行需要 33 秒
31.75s user 0.39s system 97% cpu 33.128 total
接下来使用 Golang 重构代码
焦距统计(Golang 实现)
package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/dsoprea/go-exif/v3"
)
var usualFocal = []int{16, 24, 28, 35, 50, 85, 105, 200, 300, 400}
func approximateFocal(focal int) int {
for _, usual := range usualFocal {
aggregationRange := usual / 8
if focal > usual-aggregationRange && focal < usual+aggregationRange {
return usual
}
}
return focal
}
func saveCsvFormat(dic map[int]int) {
// 获取键,并按从小到大进行排序
keys := make([]int, 0, len(dic))
for key := range dic {
keys = append(keys, key)
}
sort.Ints(keys)
// 生成表头
header := make([]string, 0, len(dic))
for _, key := range keys {
header = append(header, strconv.Itoa(key))
}
headerLine := strings.Join(header, ",")
// 生成内容
content := make([]string, 0, len(dic))
for _, key := range keys {
content = append(content, strconv.Itoa(dic[key]))
}
contentLine := strings.Join(content, ",")
file, err := os.Create("focal.csv")
if err != nil {
fmt.Println(err)
}
defer file.Close()
_, err = file.WriteString(headerLine + "\n" + contentLine)
if err != nil {
fmt.Println(err)
}
}
func main() {
folderPath := "."
var dic = make(map[int]int)
_ = filepath.Walk(folderPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !(info.Mode().IsRegular() && strings.ToLower(filepath.Ext(path)) == ".jpg") {
return nil
}
exifData, err := exif.SearchFileAndExtractExif(path)
if err != nil {
return err
}
exifTags, _, err := exif.GetFlatExifData(exifData, nil)
for _, item := range exifTags {
if strings.Contains(item.TagName, "FocalLengthIn35mmFilm") {
focalLength := int(item.Value.([]uint16)[0])
focalLength = approximateFocal(focalLength)
_, ok := dic[focalLength]
if ok {
dic[focalLength] += 1
} else {
dic[focalLength] = 1
}
}
}
return nil
})
fmt.Println(dic)
saveCsvFormat(dic)
}
编译运行
11.19s user 5.45s system 92% cpu 17.889 total
时间相比 Python 版本节省了一半,观察磁盘吞吐速率,Golang 基本上将磁盘的读取速度吃满了
使用工具展示图表
我使用的是这个在线网页:https://charts.livegap.com/app.php?lan=zh&gallery=line
没什么特别的原因,它支持导入 csv 数据同时不需要登录,就用它用来测试了。
从折线图可以看到我在使用 RX100M1(等效 35 MM 格式焦距 28-100 mm) 时,广角 28mm 使用的最多,其次是长焦 100mm 最多,35mm 和 50mm 差不多,85mm 略少于两者。
那么问题来了,我第一颗定焦镜头买什么焦段呢? 🤔