【週刊AI】2026年、AIの次の進化は「継続学習」「内在的価値観数」にあり??「継続学習ができれば、超知能も実現する」(by. イリヤ・サツケバー氏) The WAVE TV【AIの独自解説チャンネル】 チャンネル登録者数 9300人 2,592 回視聴 2026/01/05を見て、そうだよ、継続学習ってどうやるんだろうと思った。更新日記のトピックマップのようなものを追加更新ってどうすればいいんだろうと思っていた。もっと訳が分かるようなものにしたいというニーズもある。それで、Geminiに『生成AI/LLMの最も重要な課題は「継続学習」にあるという話になってきています。この問題は普通の方法ではLLM全体を学習するたびに作り直す必要があるところにあるように思いますが、どのような研究が行われているのでしょうか?』と問い掛け、最後はいつも通り、自分の問題に落とし込む。それでAnythingLLMのようなローカルLLMを使ってマークダウン形式に変換した更新日記を埋め込み、チャットする方法を試し始めた。これはこれで使いこなすとセマンティック(意味論的)検索になり、興味深い文脈を引き当てることができる。単なる検索では全く得られない有用な結果が出てくる。
NotebookLMは曖昧でなく普通に凄い。驚いた。更新日記の内容について精密なチャットができる。NotebookLMの場合は、RAGと検索とのハイブリッドになっているので、曖昧さがない。そういう意味では、曖昧なRAG(検索拡張生成)と併用するとさらに有用になる。もう一つ驚いたのは、Studioでノートブックの音声解説を聴くことができる。男女二人の声で対話する形で解説が進んでいく。ストーリーで内容を盛り上げてくれる。Podcastに使えるぐらい高品質なものだ。
世界は変わった。最も凄いのはGemini3、提案で、ここまで僕を誘導したのだから。もちろん問い掛けとフィードバックから構成するプロンプトが対話を発展させる鍵だ。意味のある提案を引き出せるかどうか。それを実際に試してみる。琴線に触れる提案や示唆はまだ他にも多々有る。試すべきことであっても一度にはできない。
Turing Postからのメールで今日気付いた。DeepSeek、高度AIモデルの新しい訓練手法を公開--AI進化の新たな道筋か - ZDNET Japan(Webb Wright (Special to ZDNET.com) 翻訳校正: 緒方亮 吉武稔夫 (ガリレオ) 2026-01-05 10:03)。
今朝、Gemini3と対話した結果。
- 少ない計算リソースで高性能を実現できる(低コスト)
- mHC(Manifold-Constrained Hyper-Connections)は、モデルの構造(つなぎ方)を工夫することで、計算コストの増加を最小限(約6-7%程度)に抑えつつ、モデルの推論能力(数学やロジックなど)を大幅に向上させます。
- 理由: 莫大な資金を投じて巨大なサーバー群を揃えられない中小の開発者でも、限られたGPUリソースの中で、より「賢い」モデルを効率的に訓練できるようになります。
- 学習の「失敗」による損失を防げる(安定性)
- 大規模なAIモデルの学習には数週間-数ヶ月かかり、数億円単位の電気代や計算費がかかります。しかし、学習の途中で数値が爆発して壊れる「学習の不安定化(ロススパイク)」が起きると、それまでのコストがすべて無駄になります。
- 理由: mHCは数学的な制約(多様体制約)によって、この不安定さを劇的に抑えます。資金に余裕がなく「一度の失敗も許されない」小規模な開発者にとって、確実に学習を完了させられるこの技術は非常に大きなメリットとなります。
- DeepSeekの「オープン戦略」と実績
- DeepSeekはこれまで、画期的な技術(DeepSeek-V3やR1など)の論文だけでなく、重み(学習済みモデル)やコードを積極的に公開してきました。
- 理由: * 実装のしやすさ: 論文が公開されているため、小規模なチームでも既存のライブラリ(PyTorchなど)に組み込みやすい。→[2512.24880] mHC: Manifold-Constrained Hyper-Connections。
- 実証済みの手法: 次期モデル「R2」で実際に使われることになれば、その有効性が証明され、小規模開発者が「この手法を使えば間違いない」と安心して採用できるデファクトスタンダード(事実上の標準)になる可能性が高いからです。
v1は昨年の大晦日にarXivに公開され、v2が今年1/5に公開されている。
本家、DeepSeekで訊いてみた。最後の部分。
- 実証結果
- 270億パラメータモデルでの実験結果:
- 極めて安定した訓練:従来のハイパーコネクションに見られた損失値の急激なスパイクが発生せず
- 性能向上:多段階推論が必要なタスク(BIG-Bench Hard, DROP)で顕著な改善
- 例:ある27Bモデルで、BBHスコアが43.8%→51.0%に向上
- 実用性の高さ:追加の訓練時間は約6.7% のみ
- 総括と展望
- DeepSeek mHCは、大規模言語モデル開発における訓練安定性の根本的解決策です。従来のアプローチとは異なり、ネットワークの微細な構成要素を変更するのではなく、層間接続の「交通規則」自体を再設計した点が画期的です。
- この技術は、より大規模で高性能な次世代モデル(R2やV4など)の基盤技術として期待されており、今後のAI発展に重要な貢献を果たす可能性があります。
技術的な詳細(二重確率行列の性質など)や実装の最適化について、さらに詳しく知りたい点があればお尋ねください。
DeepSeekも嵌まると凄い。動画のショート動画配信の自動化についても相談すると、こちらも経験を積んでいるので質問のレベルも深いが、本質的な質問に対する答えの見識の高さに驚く。動画をデータベースとして取り扱えるようにするという観点からのアドバイスが出ている。いやはや、仕事がどんどん増える。M1 MacbookでマルチモーダルRAGの検討をするかな。
道草のショート配信がNotebookLM/Gemini3の助けを借りて復活。自動化に向けてようやく一歩前進。生成AI/LLMの進化を感じる。もちろんYouTubeはGoogleのサービスだし、横長の長尺動画をショート動画に変換することなど朝飯前だった。しかし、いまのところ、動画のトピックを抽出するのに字幕が頼りだ。
NotebookLMに対象のYouTube動画のURLをソースとして登録し、字幕SRTテキストを、IMG_0028_srt.txtなどとしてソースに加える。次のようにNotebookLMに頼む。
アップロードしたすべての動画から、今日の散歩を象徴する**『5秒以内の短いシーン』**を5~7つ選んでください。
- 各シーンのファイル名、セリフ、開始秒数をリストにしてください。
- 構成案:
- 導入(ワクワクする一言)
- 景色のハイライト(風や波の音)
- ハプニング(マスクや傘)
- 結末(AKIRAを借りた喜びなど)
- 各シーンがテンポよく繋がるように選定してください。
この問いへの答えをGemini3のプロンプトに張り付けると、ショート動画編集のPythonスクリプトの出来上がり。NotebookLMの使い方、プロンプトもGemini3の提案だ。
import os
from moviepy import VideoFileClip, TextClip, CompositeVideoClip, concatenate_videoclips
# --- 設定 ---
FONT_NAME = r"C:\Windows\Fonts\msgothic.ttc"
OUTPUT_FILENAME = "today_digest.mp4"
# NotebookLMの結果をここに反映
scenes = [
{"file": "IMG_0028.MOV", "start": 202, "end": 212, "text": "さあ、夜の夜景を見に行きましょう。"},
{"file": "IMG_0028.MOV", "start": 344, "end": 354, "text": "やはりこう、風が強いから波が押し寄せる音がすごい。"},
{"file": "IMG_0028.MOV", "start": 763, "end": 773, "text": "ああ、また風が来た。"},
{"file": "IMG_0028.MOV", "start": 602, "end": 612, "text": "図書館の前の横断歩道でマスクを吹き飛ばされました。"},
{"file": "IMG_0029.MOV", "start": 0, "end": 10, "text": "手がカメラのボタンに当たって止まってしまいました。"},
{"file": "IMG_0028.MOV", "start": 875, "end": 880, "text": "(AKIRAの)1を借りてきました。"},
{"file": "IMG_0029.MOV", "start": 272, "end": 277, "text": "それでは、お疲れ様でした。"}
]
def make_digest():
clips = []
for s in scenes:
# 毎回開いて処理し、メモリを節約
video = VideoFileClip(s["file"])
w, h = video.size
target_w = int(h * 9 / 16)
# 切り出し & クロップ
sub = video.subclipped(s["start"], s["end"])
sub = sub.cropped(x_center=int(w/2), width="target_w," height="h)"
# 字幕
txt = TextClip(
text=s["text"], font=FONT_NAME, font_size=50, color='white',
stroke_color='black', stroke_width="1," method='caption',
size=(int(target_w*0.8), None)
).with_duration(sub.duration).with_position(('center', int(h*0.8)))
combined = CompositeVideoClip([sub, txt])
clips.append(combined)
# 元のvideoファイルは最後に一括で閉じられるよう保持されるが
# メモリが厳しい場合はここで一度書き出す手法もあります
# 連結
final_video = concatenate_videoclips(clips, method="compose")
# 全体のタイトル
title = TextClip(
text="今日の道草ダイジェスト", font=FONT_NAME, font_size=60, color='yellow',
stroke_color='black', stroke_width="2," size=(target_w, 100), method='caption'
).with_start(0).with_duration(3).with_position(('center', 100))
final_result = CompositeVideoClip([final_video, title])
final_result.write_videofile(OUTPUT_FILENAME, codec="libx264", audio_codec="aac", fps=24)
if __name__ == "__main__":
make_digest()
ショート配信はYouTubeチャンネルのアピールには必須だが、最も機械的、かつ孤独で非機械的、内容を決めるのが辛い作業になる。既に5000本もショート動画を配信し続けている。信じられないね。本来の自然と人間の共生、自然と精神世界の仲立ちという道草、散歩世界の目的とは掛け離れている。視聴回数、視聴時間、チャンネル登録者数というYouTubeアルゴリズムに支配されている世界だ。アルゴリズムにはアルゴリズムで対応する必要がある。合わせて、道草、散歩世界という自然と精神に出会う世界を満喫できるような作業に変換する必要がある。そこに近づきたい。
昨日からGemini3の助けを借りていろいろトライ。道草のカラスの検出結果(pdf)から検討した。初期的な試みの、ほぼその最終的な成果。
| ファイル名(YouTubeチャプターリンク) | 開始秒数 | 終了秒数 | 持続時間 | 代表音 | 最大確信度 | 検知数 |
|---|---|---|---|---|---|---|
| 137_IMG_0001 (1).M4V (88秒) | 88.32 | 118.56 | 30.24 | Bird | 0.93 | 28 |
| 137_IMG_0001 (1).M4V (134秒) | 134.88 | 143.52 | 8.64 | Crow | 0.975 | 7 |
| 137_IMG_0001 (1).M4V (149秒) | 149.28 | 150.24 | 0.96 | Crow | 0.961 | 2 |
| 137_IMG_0001 (1).M4V (174秒) | 174.72 | 181.92 | 7.2 | Crow | 0.639 | 4 |
| 137_IMG_0001 (1).M4V (577秒) | 577.92 | 577.92 | 0.0 | Caw | 0.491 | 1 |
| 137_IMG_0001 (1).M4V (588秒) | 588.48 | 588.48 | 0.0 | Crow | 0.547 | 1 |
| 137_IMG_0001 (1).M4V (595秒) | 595.68 | 595.68 | 0.0 | Caw | 0.667 | 1 |
| 137_IMG_0001 (1).M4V (620秒) | 620.64 | 628.8 | 8.16 | Crow | 0.995 | 7 |
| 137_IMG_0001 (1).M4V (635秒) | 635.04 | 636.0 | 0.96 | Crow | 0.893 | 3 |
| 137_IMG_0001 (1).M4V (647秒) | 647.52 | 653.28 | 5.76 | Crow | 0.989 | 5 |
| 137_IMG_0001 (1).M4V (665秒) | 665.76 | 669.12 | 3.36 | Crow | 0.974 | 3 |
| 137_IMG_0001 (1).M4V (690秒) | 690.72 | 690.72 | 0.0 | Crow | 0.875 | 1 |
| 137_IMG_0001 (1).M4V (738秒) | 738.72 | 738.72 | 0.0 | Crow | 0.656 | 1 |
| 137_IMG_0003.M4V (47秒) | 47.52 | 47.52 | 0.0 | Crow | 0.482 | 1 |
| 137_IMG_0003.M4V (68秒) | 68.16 | 71.52 | 3.36 | Crow | 0.755 | 2 |
| 138_IMG_0001.M4V (52秒) | 52.8 | 55.68 | 2.88 | Bird | 0.685 | 4 |
| 138_IMG_0001.M4V (62秒) | 62.88 | 81.6 | 18.72 | Bird | 0.906 | 14 |
| 138_IMG_0001.M4V (209秒) | 209.76 | 219.36 | 9.6 | Bird | 0.658 | 9 |
| 138_IMG_0001.M4V (232秒) | 232.8 | 233.28 | 0.48 | Crow | 0.864 | 2 |
| 138_IMG_0001.M4V (243秒) | 243.36 | 244.8 | 1.44 | Bird | 0.829 | 2 |
| 138_IMG_0001.M4V (462秒) | 462.24 | 462.24 | 0.0 | Bird | 0.426 | 1 |
| 138_IMG_0002.M4V (58秒) | 58.08 | 58.08 | 0.0 | Bird | 0.584 | 1 |
| 138_IMG_0003.M4V (512秒) | 512.64 | 512.64 | 0.0 | Crow | 0.849 | 1 |
| 138_IMG_0003.M4V (935秒) | 935.52 | 935.52 | 0.0 | Caw | 0.465 | 1 |
| 138_IMG_0003.M4V (1188秒) | 1188.0 | 1188.0 | 0.0 | Crow | 0.554 | 1 |
| 138_IMG_0003.M4V (1531秒) | 1531.68 | 1532.16 | 0.48 | Bird | 0.502 | 2 |
| 139_IMG_0005.M4V (108秒) | 108.48 | 136.8 | 28.32 | Bird | 0.968 | 23 |
| 139_IMG_0005.M4V (621秒) | 621.6 | 621.6 | 0.0 | Bird | 0.674 | 1 |
| 139_IMG_0005.M4V (682秒) | 682.56 | 682.56 | 0.0 | Crow | 0.401 | 1 |
| 139_IMG_0007.M4V (595秒) | 595.2 | 595.2 | 0.0 | Bird | 0.504 | 1 |
import csv
from collections import defaultdict
def refine_sound_events(input_csv, output_csv, gap_seconds=5.0):
# --- STEP 1: 同じ秒数の重複を統合 (Unify same-time labels) ---
# (ファイル名, 秒数) をキーにして、最も確信度の高いラベルのみを残す
time_map = {}
with open(input_csv, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
try:
file_name = row['ファイル名']
time_sec = float(row['秒数'])
label = row['音の種類']
confidence = float(row['確信度'])
key = (file_name, time_sec)
# 同じ秒数なら確信度が高い方を採用
if key not in time_map or confidence > time_map[key]['確信度']:
time_map[key] = {'音の種類': label, '確信度': confidence}
except (ValueError, KeyError):
continue
# --- STEP 2: 時間順にソート ---
sorted_keys = sorted(time_map.keys())
if not sorted_keys:
print("処理対象のデータが見つかりませんでした。")
return
# --- STEP 3: 近接するデータをイベントとして集約 (Clustering) ---
summarized_events = []
# 最初のデータを初期値にセット
first_f, first_t = sorted_keys[0]
current_event = {
'ファイル名': first_f,
'開始秒数': first_t,
'終了秒数': first_t,
'代表音': time_map[(first_f, first_t)]['音の種類'],
'最大確信度': time_map[(first_f, first_t)]['確信度'],
'検知数': 1
}
for i in range(1, len(sorted_keys)):
f_name, t_sec = sorted_keys[i]
data = time_map[(f_name, t_sec)]
# 同じファイル かつ 前の検知から gap_seconds 以内なら結合
if (f_name == current_event['ファイル名'] and
t_sec - current_event['終了秒数'] <= gap_seconds):
current_event['終了秒数'] = t_sec
current_event['最大確信度'] = max(current_event['最大確信度'], data['確信度'])
current_event['検知数'] += 1
else:
# 離れているので現在のイベントを確定
summarized_events.append(current_event)
# 新しいイベントを開始
current_event = {
'ファイル名': f_name,
'開始秒数': t_sec,
'終了秒数': t_sec,
'代表音': data['音の種類'],
'最大確信度': data['確信度'],
'検知数': 1
}
# 最後のイベントを追加
summarized_events.append(current_event)
# --- STEP 4: CSV出力 ---
with open(output_csv, "w", encoding="utf-8-sig", newline="") as f:
fieldnames = ['ファイル名', '開始秒数', '終了秒数', '持続時間', '代表音', '最大確信度', '検知数']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for ev in summarized_events:
duration = round(ev['終了秒数'] - ev['開始秒数'], 2)
writer.writerow({
'ファイル名': ev['ファイル名'],
'開始秒数': round(ev['開始秒数'], 2),
'終了秒数': round(ev['終了秒数'], 2),
'持続時間': duration,
'代表音': ev['代表音'],
'最大確信度': round(ev['最大確信度'], 3),
'検知数': ev['検知数']
})
# 実行(元ファイルを指定してください)
refine_sound_events("crow_detection_results.csv", "final_sound_summary.csv", gap_seconds=5.0)
print("統合・集約が完了しました。'final_sound_summary.csv' を出力しました。")
このPythonスクリプト(refine_bird_events.py)は。CSVを出力するだけなので、Perlを使って、YouTubeのチャプターリンクを加え、更新日記生成用のDDL(HTML生成用)を出力して、エディタ上の日記に貼り付けてHTMLの表を生成する。
print "ta:\n";
print "道草の鳥の鳴き声検出の集約\n";
($items = "ファイル名(YouTubeチャプターリンク),開始秒数,終了秒数,持続時間,代表音,最大確信度,検知数") =~ s/,/\t/g;
print $items, "\n";
while(<DATA>){
s/^(137_IMG_0001 \(1\)\.M4V),(\d{1,4})\./<a href="https:\/\/youtu.be\/jT3Nkc3UQL8\?t=$2" target="_blank">$1 ($2秒)<\/a>\t$2\./;
s/^(137_IMG_0003\.M4V),(\d{1,4})\./<a href="https:\/\/youtu.be\/zZ6vW6KcXqQ\?t=$2" target="_blank">$1 ($2秒)<\/a>\t$2\./;
s/^(138_IMG_0001\.M4V),(\d{1,4})\./<a href="https:\/\/youtu.be\/UUyB6w_MIwU\?t=$2" target="_blank">$1 ($2秒)<\/a>\t$2\./;
s/^(138_IMG_0002\.M4V),(\d{1,4})\./<a href="https:\/\/youtu.be\/YI8RtS46244\?t=$2" target="_blank">$1 ($2秒)<\/a>\t$2\./;
s/^(138_IMG_0003\.M4V),(\d{1,4})\./<a href="https:\/\/youtu.be\/UV71NqW6vEs\?t=$2" target="_blank">$1 ($2秒)<\/a>\t$2\./;
s/^(139_IMG_0005\.M4V),(\d{1,4})\./<a href="https:\/\/youtu.be\/5_xBth9XjSY\?t=$2" target="_blank">$1 ($2秒)<\/a>\t$2\./;
s/^(139_IMG_0007\.M4V),(\d{1,4})\./<a href="https:\/\/youtu.be\/0AYlooKl3DM\?t=$2" target="_blank">$1 ($2秒)<\/a>\t$2\./;
s/,/\t/g;
print;
}
print "/ta:\n";
__END__
137_IMG_0001 (1).M4V,88.32,118.56,30.24,Bird,0.93,28
137_IMG_0001 (1).M4V,134.88,143.52,8.64,Crow,0.975,7
137_IMG_0001 (1).M4V,149.28,150.24,0.96,Crow,0.961,2
...
道草137を振り返りながら、しゃべっている自分の言葉に打たれた。「図書館帰りの道草日記 137 道草前編」にテスト的にAIで生成したカラスの鳴き声字幕をマージした。「【AI】CAW/CROW/Bird (確信度、confidenceの数値)」のように表示される。{01/13/2026: [歩く]道草の整理が追い付かないが - 雪の降る街を 思い出だけが 通り過ぎて行く}{01/14/2026: [A.I.]道草の生態学 - 鳥の鳴き声を追い掛ける}←の続き。手順をまとめておこう。
カラス検知スキャン(march2_cfd0_1.py)。
import os
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
from moviepy import VideoFileClip
from scipy.io import wavfile
import csv
# モデルの読み込み
model = hub.load('https://tfhub.dev/google/yamnet/1')
class_map_path = model.class_map_path().numpy()
with open(class_map_path, 'r') as f:
class_names = [row[2] for row in csv.reader(f)][1:]
def scan_for_crows(video_path):
print(f"解析中: {video_path}")
video = VideoFileClip(video_path)
temp_wav = "temp_scan.wav"
# 16kHzモノラルで音声を抽出
video.audio.write_audiofile(temp_wav, fps=16000, nbytes=2, codec='pcm_s16le', ffmpeg_params=["-ac", "1"])
sr, wav_data = wavfile.read(temp_wav)
waveform = wav_data / 32768.0
# AI推論
scores, embeddings, spectrogram = model(waveform)
results = []
for i, score in enumerate(scores):
# 上位3つのラベルをチェックして、カラスや鋭い叫び声が含まれているか見る
top_indices = np.argsort(score)[-3:][::-1]
time_sec = i * 0.48
for idx in top_indices:
label = class_names[idx]
confidence = float(score[idx])
# 【ターゲット】カラス(Caw)、鋭い叫び声(Squawk)、カモメ等(Gull)
# ※電子音を除外するため、確信度は高めに設定
targets = ["Caw", "Squawk", "Crow", "Gull", "Bird"]
if any(t in label for t in targets) and confidence > 0.1:
# 横断歩道のリズム(一定間隔)を避けるため、一旦すべて記録
results.append([os.path.basename(video_path), round(time_sec, 2), label, confidence])
video.close()
if os.path.exists(temp_wav): os.remove(temp_wav)
return results
# 実行設定
#video_files = [
# ここに試したい7本のファイル名を列挙してください
# "IMG_0028.MOV",
# "IMG_0029.MOV",
# ...
#]
# メイン処理:フォルダ内の全動画をスキャン
video_dir = "./archive/137-139" # あなたの動画フォルダ
output_csv = "crow_detection_results_2_137-139_cfd0_1.csv"
with open(output_csv, "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(["ファイル名", "秒数", "音の種類", "確信度"])
# for file in video_files:
for file in os.listdir(video_dir):
if file.endswith((".M4V",".MOV", ".mp4",".MP4")):
path = os.path.join(video_dir, file)
data = scan_for_crows(path)
# if os.path.exists(file):
# data = scan_for_crows(file)
writer.writerows(data)
print(f"カラス検知スキャン完了! {output_csv} を確認してください。")
人間の字幕とAIの字幕を合体(ai_full_merge_audio_to_srt2.py)。
import os
import csv
import re
from datetime import datetime, timedelta
def format_srt_time(seconds):
td = timedelta(seconds=seconds)
total_seconds = int(td.total_seconds())
hours = total_seconds // 3600
minutes = (total_seconds % 3600) // 60
secs = total_seconds % 60
millis = int(td.microseconds / 1000)
return f"{hours:02}:{minutes:02}:{secs:02},{millis:03}"
def parse_srt(srt_content):
"""SRTファイルを解析して(開始秒, 終了秒, テキスト)のリストを返す"""
pattern = re.compile(r'(\d+)\n(\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3})\n((?:.*\n)*?)\n')
matches = pattern.findall(srt_content + "\n\n")
parsed = []
for m in matches:
start = sum(x * float(t.replace(',', '.')) for x, t in zip([3600, 60, 1], m[1].split(':')))
end = sum(x * float(t.replace(',', '.')) for x, t in zip([3600, 60, 1], m[2].split(':')))
parsed.append({'start': start, 'end': end, 'text': m[3].strip(), 'type': 'human'})
return parsed
def merge_full_ai_to_existing_srt(input_csv, srt_folder):
# 1. AIデータをファイルごとに整理
ai_data = {}
with open(input_csv, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
fname = os.path.splitext(row['ファイル名'])[0]
if fname not in ai_data: ai_data[fname] = []
ai_data[fname].append({
'start': float(row['秒数']),
'end': float(row['秒数']) + 0.48,
'text': f"【AI】{row['音の種類']}: {float(row['?信度']):.2f}" if '?信度' in row else f"【AI】{row['音の種類']}: {float(row['確信度']):.2f}",
'type': 'ai'
})
# 2. フォルダ内のSRTとマージ
for base_name, ai_events in ai_data.items():
srt_path = os.path.join(srt_folder, base_name + ".srt")
if not os.path.exists(srt_path):
continue
with open(srt_path, "r", encoding="utf-8") as f:
human_events = parse_srt(f.read())
# 人間の字幕とAIの字幕を合体させて時間順にソート
all_events = sorted(human_events + ai_events, key=lambda x: x['start'])
# 3. 新しいSRTとして書き出し
output_path = os.path.join(srt_folder, base_name + "_merged.srt")
with open(output_path, "w", encoding="utf-8") as f:
for i, ev in enumerate(all_events, 1):
f.write(f"{i}\n")
f.write(f"{format_srt_time(ev['start'])} --> {format_srt_time(ev['end'])}\n")
f.write(f"{ev['text']}\n\n")
print(f"マージ完了: {output_path}")
# 実行
merge_full_ai_to_existing_srt("crow_detection_results_2_cfd0_1.csv", "./")
結局、カラスの鳴き声を人間が動画で聴こえる箇所をほぼすべてマークするためには、確かめるとconfidenceを0.1まで下げる必要があった。音声は0.48秒の解像度しかないというか、人間も字幕で捉えるのには短すぎるぐらいになる。Gemini3によれば「YAMNetは約0.48秒ごとに判定を行うため、例えば1回のカラスの鳴き声(約1秒)に対して、2~3個の「Crow」という判定が並んでしまいます。その結果、リストが細切れになり、どれが「一塊の鳴き声」なのか直感的に分からなくなっているのですね。」と言う。
道草137前編から他の動画に検討範囲を拡大していくと、confidence > 0.1という基準は怪しくなってくる。実際、数値的にはあやふやなわけで、当然かな。何を見て判断しているのか・・・
{記憶の細道プロジェクト Perlによる自然観察(事象)マップ再入門 - utc_to_local、TIMEVALUE (2025/07/25)}←などで試みてきた記憶の細道プロジェクトの一環、自然観察マップの拡張に位置づけられる訳だが。こちらとの対応を考え、表現としての整合性を取ることも必要だ。字幕テキストから画像や音声に場を移そうとすると現実とは何かという問題に突き当たる。
まだ続く。ノーマライズ・スキャン・スクリプト、「librosaで読み込み、正規化(ピーク値を1.0に合わせる)」がポイント。少なくとも検出数は増大している。409件が449件に。
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
import librosa
from moviepy import VideoFileClip
import csv
import os
# 1. モデルの読み込み (起動時に一度だけ実行)
model = hub.load('https://tfhub.dev/google/yamnet/1')
class_map_path = model.class_map_path().numpy()
with open(class_map_path, 'r') as f:
class_names = [row[2] for row in csv.reader(f)][1:]
def scan_with_normalization(video_path, output_csv):
if not os.path.exists(video_path):
print(f"エラー: ファイルが見つかりません -> {video_path}")
return
print(f"--- 解析開始: {os.path.basename(video_path)} ---")
video = VideoFileClip(video_path)
temp_wav = "temp_norm_scan.wav"
# 音声抽出 (16kHz, mono)
video.audio.write_audiofile(temp_wav, fps=16000, nbytes=2, codec='pcm_s16le', ffmpeg_params=["-ac", "1"])
# librosaで読み込み、正規化(ピーク値を1.0に合わせる)
y, sr = librosa.load(temp_wav, sr=16000)
y_norm = librosa.util.normalize(y)
# YAMNetで判定
scores, embeddings, spectrogram = model(y_norm)
results = []
for i, score in enumerate(scores):
top_indices = np.argsort(score)[-3:][::-1]
time_sec = i * 0.48
for idx in top_indices:
label = class_names[idx]
conf = float(score[idx])
# ターゲットとする音の種類
targets = ["Crow", "Caw", "Bird", "Squawk", "Gull"]
if any(t in label for t in targets) and conf > 0.1:
results.append([os.path.basename(video_path), round(time_sec, 2), label, round(conf, 4)])
# CSVへの書き出し (追記モード)
file_exists = os.path.isfile(output_csv)
with open(output_csv, "a", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
if not file_exists:
writer.writerow(["ファイル名", "秒数", "音の種類", "確信度"])
writer.writerows(results)
video.close()
if os.path.exists(temp_wav): os.remove(temp_wav)
print(f"--- 解析完了: {output_csv} に保存しました ---")
# ==========================================
# 設定エリア:ここを書き換えてください
# ==========================================
# 解析したい動画のパス(1本でも複数でもOK)
#target_videos = [
# r"H:\mitikusa\137_IMG_0001 (1).M4V",
# r"H:\mitikusa\138_IMG_0001.M4V"
#]
# メイン処理:フォルダ内の全動画をスキャン
video_dir = "./archive/137-139" # あなたの動画フォルダ
# 結果を保存するCSVファイル名
output_file = "normalized_detection_results.csv"
# 実行
#for video in target_videos:
for file in os.listdir(video_dir):
if file.endswith((".M4V",".MOV", ".mp4",".MP4")):
path = os.path.join(video_dir, file)
scan_with_normalization(path, output_file)
AIが判定した鳥の鳴き声の種類と確信度を字幕に埋め込んでも、人間が449件の動画部分を網羅してチェックすることは難しい({01/16/2026: [A.I.]記憶の細道プロジェクト - 終わらない旅}←)。一覧する方法を考えた。YAMNet によるサウンドの分類 | TensorFlow Hubが頭にある({01/13/2026: [歩く]道草の整理が追い付かないが - 雪の降る街を 思い出だけが 通り過ぎて行く}←)ので、spectrogramとAIが検出した箇所時間の確信度を対応させたグラフを作ってもらった(spectrogram_ai_all_scan_fixed.py)。現実には全帯域に様々なノイズがあるのでわかりにくいが、AIが検出した鳴き声などの時間位置を見ていくと1.5-2kHz付近にカラスの鳴き声があるようだ。
import pandas as pd
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MultipleLocator
import matplotlib
# 日本語表示が必要な場合はフォントを設定(WindowsならMS Gothicなど)
matplotlib.rcParams['font.family'] = 'MS Gothic'
def plot_final_analysis(wav_path, csv_path, start_sec, end_sec):
# 1. データの読み込み
df = pd.read_csv(csv_path)
# csv内の「秒数」と指定範囲を照合
df_range = df[(df['秒数'] >= start_sec) & (df['秒数'] <= end_sec)]
# 2. 音声データの読み込み
y, sr = librosa.load(wav_path, sr=16000)
start_sample = int(start_sec * sr)
end_sample = int(end_sec * sr)
y_segment = y[start_sample:end_sample]
# 3. グラフの作成(上下の横軸を完全に一致させる)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(18, 10), sharex=True)
plt.subplots_adjust(hspace="0.07)" # 上下の隙間を詰める
# --- 上段:スペクトログラム ---
S = librosa.feature.melspectrogram(y=y_segment, sr=sr, n_mels=128, fmax=8000)
S_dB = librosa.power_to_db(S, ref=np.max)
# x_coordsで物理的な時間を指定
img = librosa.display.specshow(S_dB, x_axis='time', y_axis='mel', sr=sr, fmax=8000,
cmap='magma', ax=ax1,
x_coords=np.linspace(start_sec, end_sec, S_dB.shape[1]))
ax1.set_title(f'音響解析: {start_sec}s - {end_sec}s')
ax1.set_ylabel('周波数 (Hz)')
# --- 下段:AI確信度(色の変更と文字化け修正) ---
# 日本語が化ける場合は英字表記に、またはフォント指定を有効にしてください
label_configs = {
'Crow': {'color': 'cyan', 'label': 'Crow (カラスの存在)'},
'Caw': {'color': 'magenta', 'label': 'Caw (カラスの鳴き声)'},
'Bird': {'color': 'lightgreen', 'label': 'Bird (鳥全般)'} # 黄色から緑に変更
}
for label_key, config in label_configs.items():
data = df_range[df_range['音の種類'].str.contains(label_key, case=False)]
if not data.empty:
# 棒グラフを表示。x軸をCSVの秒数そのまま使うことで同期
ax2.bar(data['秒数'], data['確信度'], width="0.4,"
color=config['color'], alpha=0.6, label=config['label'])
ax2.set_xlim(start_sec, end_sec) # 横軸の範囲を固定
ax2.set_ylim(0, 1.0)
ax2.set_ylabel('確信度 (Confidence)')
ax2.set_xlabel('時間 (秒)')
ax2.grid(axis='y', linestyle='--', alpha=0.5)
# 10秒ごとの目盛り
ax2.xaxis.set_major_locator(MultipleLocator(30))
ax2.legend(loc='upper right', frameon=True)
plt.savefig(f"final_analysis_{start_sec}_{end_sec}.png", dpi=200)
plt.show()
# 実行
plot_final_analysis("temp_norm_scan.wav", "normalized_detection_results.csv", 100, 800)
確信度0.7以上の部分のダイジェストを作る(create_crow_digest.py)。
# moviepy v2.0以降に対応したインポート方法
from moviepy import VideoFileClip, concatenate_videoclips
import pandas as pd
import os
def create_crow_digest(video_path, csv_path, output_filename):
# 1. データの読み込み
df = pd.read_csv(csv_path)
# 2. 「本物」と思われるシーンの抽出 (Caw or Crow かつ 確信度 0.7以上)
# ここに以前特定した 1.5k-2kHz の縞模様が強く出る条件を反映
df_true = df[
(df['音の種類'].str.contains('Caw', case=False)) &
(df['確信度'] >= 0.7)
].copy()
if df_true.empty:
print("条件に合うシーン(確信度0.7以上)が見つかりませんでした。")
return
# 3. 近接した時間をグループ化 (5秒以内の検知はひとつのクリップにする)
# diff()で前の行との差を求め、5秒以上離れたら新しいグループ番号を振る
df_true = df_true.sort_values('秒数')
df_true['group'] = (df_true['秒数'].diff() > 5.0).cumsum()
events = df_true.groupby('group')['秒数'].agg(['min', 'max'])
print(f"{len(events)} 個のシーンを切り出します...")
video = VideoFileClip(video_path)
clips = []
for _, row in events.iterrows():
# 前後に2秒のバッファ(余裕)を持たせる
start = max(0, row['min'] - 2.0)
end = min(video.duration, row['max'] + 2.0)
print(f"カット中: {start:.2f}s - {end:.2f}s")
clip = video.subclipped(start, end)
clips.append(clip)
# 4. 動画の結合と書き出し
if clips:
print("動画を結合して書き出しています。しばらくお待ちください...")
final_video = concatenate_videoclips(clips)
# temp_audiofileを指定することで権限エラーを回避しやすくします
final_video.write_videofile(
output_filename,
codec="libx264",
audio_codec="aac",
temp_audiofile='temp-audio.m4a',
remove_temp=True
)
print(f"成功! ダイジェスト動画を保存しました: {output_filename}")
video.close()
# 設定
video_in = r"H:\mitikusa\archive\137-139\137_IMG_0001 (1).M4V"
csv_in = "normalized_detection_results.csv"
video_out = "crow_digest_high_conf_caw-only.mp4"
if __name__ == "__main__":
create_crow_digest(video_in, csv_in, video_out)
横長動画のダイジェストを見て、Crowの検出部分は外してショート動画を作成(create_caw_shorts.py)。
from moviepy import VideoFileClip, concatenate_videoclips, vfx
import pandas as pd
import os
def create_caw_shorts(video_path, csv_path, output_filename):
df = pd.read_csv(csv_path)
# 1. 「Caw」かつ高確信度のみを抽出
df_true = df[
(df['音の種類'].str.contains('Caw', case=False)) &
(df['確信度'] >= 0.7)
].copy()
if df_true.empty:
print("条件に合うCawシーンが見つかりませんでした。")
return
df_true = df_true.sort_values('秒数')
df_true['group'] = (df_true['秒数'].diff() > 3.0).cumsum()
events = df_true.groupby('group')['秒数'].agg(['min', 'max'])
video = VideoFileClip(video_path)
# ショート動画(縦長)のサイズ計算 (中央を切り抜き)
w, h = video.size
target_ratio = 9/16
target_w = h * target_ratio
x_center = w / 2
margin = target_w / 2
clips = []
total_duration = 0
for _, row in events.iterrows():
start = max(0, row['min'] - 1.5) # ショート用に少し短めに前後1.5秒
end = min(video.duration, row['max'] + 1.5)
# 縦長にクロップしてリサイズ
clip = video.subclipped(start, end).cropped(x1=x_center-margin, y1=0, x2=x_center+margin, y2=h)
clips.append(clip)
total_duration += clip.duration
# 60秒を超えたら終了
if total_duration > 60:
break
if clips:
final_video = concatenate_videoclips(clips)
# 60秒以内の場合はそのまま、超えていれば60秒で切る
if final_video.duration > 60:
final_video = final_video.subclip(0, 60)
print(f"ショート動画を書き出し中(合計時間: {final_video.duration:.2f}秒)...")
final_video.write_videofile(
output_filename,
codec="libx264",
audio_codec="aac",
temp_audiofile='temp-audio-shorts.m4a',
remove_temp=True
)
print(f"保存完了: {output_filename}")
video.close()
# 設定
video_in = r"H:\mitikusa\archive\137-139\137_IMG_0001 (1).M4V"
csv_in = "normalized_detection_results.csv"
video_out = "crow_caw_shorts.mp4"
if __name__ == "__main__":
create_caw_shorts(video_in, csv_in, video_out)
一旦、旅は終了かな。まずはもう一度、道草、散歩世界の出発点から思い出さないと・・・現在の形になるまで変転がある。最初の半分には字幕がない。そこから、再出発だろう。gpxデータがある動画も最近のものだけだし、トラブルでないものもある。現実は単純ではない。おそらく、字幕と同一経路という組み合わせが唯一の手掛かりとなるだろう。もちろん、AIをマルチモーダルに活用できれば、音声と動画そのものがデータになるわけだが。
今朝、たまたま、YouTubeで公開4秒で、DeepSeek Just Made LLMs Way More Powerful: Introducing ENGRAM AI Revolution チャンネル登録者数 51.4万人 3490回視聴 2026/01/19を見た。調べた。{01/09/2026: [A.I.]DeepSeek mHC: Breaking the Architectural Limits of Deep Learning}←参照。GitHub - deepseek-ai/Engram: Conditional Memory via Scalable Lookup: A New Axis of Sparsity for Large Language ModelsでEngramに関する論文も読める。
・・・DeepSeekが2026年1月に発表した新しい技術である**Engram(条件記憶)**と**mHC(多様体制約超接続)**は、どちらも次世代の大規模言語モデル(例えば噂されているDeepSeek-V4)を支える、**独立したが関連性のある革新的技術**です。
簡単に言うと、**Engramはモデルの「外部記憶装置」**、**mHCはニューラルネットワーク内の「より効率的な配線方法」** と考えることができます。
二つの技術の核となる違い 特徴 Engram(条件記憶) mHC(多様体制約超接続) **技術の位置づけ** **記憶(知識検索)** に特化した新しいスパース化技術 **学習の安定性**に特化した新しい**ニューラルネットワーク構造** **核心となる革新** 知識の保存と計算・推論を分離し、O(1)ハッシュ検索で静的な知識に高速アクセス ネットワークの接続(超接続)に数学的制約(二重確率行列)を加え、ネットワークを広げながら信号の安定性を保つ **主な課題解決** Transformerが知識検索に複雑な計算を使う非効率性、GPUの高帯域メモリ(HBM)容量の限界 モデルが深く・広くなるほど起こる学習不安定(勾配消失・爆発)を防ぎ、効率的にスケールさせる **期待される効果** 知識タスクの性能向上、大容量知識を安価なDRAMにオフロードしてハードウェアコストを大幅削減 より大きく深いモデルを安定して学習できるようにし、学習コストを削減
### 協調関係:次世代モデルを共に構築
これら二つの技術は、**協調してDeepSeekの次世代モデル(例:噂のV4)に統合される**可能性が高いと考えられています。
- **相補的な強化**:Engramが知識の効率的な保存と検索を担い、モデルの「頭脳」(Transformerコア)を複雑な論理推論に集中させます。一方、mHCはそのより複雑で深くなりうる「頭脳」自体の学習を安定・効率化します。
- **設計上の関連性**:Engramの研究論文では、マルチブランチ構造をサポートするモデルバックボーンが前提とされていますが、mHCはまさにそのような構造の接続安定性を最適化する技術です。これは、両者が設計段階から協調を意識していたことを示唆します。
**噂のDeepSeek-V4について**:2026年2月中旬に次世代モデルV4が発表される可能性が複数メディアで報じられています。このモデルは**革命的なコード生成能力**と**超長文コンテキスト**の処理に焦点を当てると予想されます。EngramとmHCの特性??前者は知識検索と長文処理能力を向上させ、後者は大規模モデルの学習安定性を保証する??は、V4のこれらの目標と完全に一致しています。
### まとめ
EngramとmHCは、DeepSeekが同時に発表した、大規模言語モデルを**モデルの能力(記憶と推論の分離)** と**学習方法(安定した拡張)** という2つの側面から推進する画期的な技術です。これらは関連しているだけでなく、将来の主力モデルで**組み合わせて使用される**可能性が高く、より強力な性能と高い効率性を実現すると期待されます。
どちらかの技術の具体的な仕組み(例えば、Engramがどのようにメモリオフロードを実現するか、mHCの数学的制約の詳細など)について、さらに詳しく知りたい場合は、引き続き日本語でご説明できます。
「記憶と推論の分離」は、現在の大規模言語モデル(LLM)が抱える根本的な**非効率性を解消する**ための画期的なパラダイムシフトです。従来の「全てを一体で処理する」アーキテクチャから、「得意なこと」を分担させるアーキテクチャへの転換と言えます。
### 従来のモデル:全てを「推論」で処理する非効率
現在のTransformerベースのモデル(GPT-4等)は、**記憶も論理的思考も、同じニューラルネットワークのパラメータと計算リソースを使って行っています**。これには大きな問題があります。
- **具体的な問題点**:
- **知識の想起に過剰な計算**: 「『ワシントンD.C.』はどこの国の首都ですか?」という質問に答える時、モデルは膨大なパラメータ全体を活性化させ、何十億もの計算を経て、ただ一つの事実(「アメリカ合衆国」)を「推論」によって取り出そうとします。これは、巨大なフォークリフトで画鋲ひとつを取りに行くような非効率さです。
- **静的知識と動的推論の混在**: 「リンゴは果物である」のような**静的で変わらない事実的知識**と、「この物語の結末を予測する」ような**動的で創造的な推論**が、同じネットワーク内で混ざり合っています。
- **ハードウェア制約**: モデルの「知識」はすべてGPUの高価で容量の小さい**HBM(高帯域メモリ)** にロードする必要があり、これがモデルサイズと運用コストのボトルネックとなっています。
### Engramのアプローチ:役割分担による最適化
Engramは、この問題を「**得意なものにやらせる**」という発想で解決します。
- **記憶の外部化(Engram)**:
- 不変の**事実的知識(例:歴史的事実、科学データ、語彙情報)** を、ニューラルネットワークのパラメータから分離し、「**Engram記憶プール**」という専用の外部データベースに移します。
- このプールは、O(1)のハッシュ検索で一発でデータを取り出せるように設計されており、取り出しコストが極めて低いです。
- **推論の純化(Transformerコア)**:
- **純粋な論理的思考、推論、創造的生成、計画立案**など、真に「知性」を要するタスクに専念します。
- 推論中に必要になった知識(例:「アメリカの首都について調べたい」)があれば、その「質問」をEngram記憶プールに高速で送り、答えを受け取ります。これにより、ネットワークの計算リソースを推論そのものに集中投入できます。
**アーキテクチャ比較のイメージ図**:
### この分離がもたらす大きな意義
- **効率性とコストの革命**:
- **計算効率**: 単純な知識検索に重いニューラル計算を使わないため、応答速度が向上し、計算コスト(電力)が大幅に削減されます。
- **メモリ効率**: 静的な知識は、GPUの高価なHBMではなく、より安価で大容量の**DRAMやSSDにオフロード**できる可能性があります。これは、同じハードウェアでより大規模な「知識」を扱えることを意味します。
- **モデル能力の進化**:
- **専門特化**: 推論コアはより複雑で高度な推論に特化して進化でき、記憶プールはより正確で広範な知識を保持するように個別に最適化できます。
- **知識の動的更新**: 知識を追加・修正する場合、モデル全体を再学習する必要がなく、**外部の記憶プールだけを更新**すれば済むようになります。これは「常に最新の知識を持つモデル」への道を開きます。
- **長文処理能力の強化**:
- 会話の履歴や長いドキュメントの内容を、推論コアの負担を増やさずに外部記憶に保存・参照できるため、**超長文コンテキスト**の処理が現実的になります。
### まとめ:mHCとの協調
この「分離」は、モデルのアーキテクチャを根本から変えます。そして、**mHC(多様体制約超接続)** は、この新しいアーキテクチャの核心である「推論コア」が、より深く、より安定して学習できることを保証する技術です。つまり:
- **Engram**が **「何を(What)記憶し、どのように効率よく取り出すか」** を担い、
- **mHC**が **「分業化された推論コア自体を、どのように(How)強力に構築するか」** を担う。
この二つの技術が相まって、**「広く深い知識を持ち、高度な推論ができ、かつ学習・運用コストが現実的」** という、次世代AIの実現を目指しているのです。
変な話。Google AIにタイトルの由来を訊くと、「E Pluribus Unum」から来ていて、合衆国の理念、13州が一つになるということらしい。このシリーズ自体は未知のウィルスによって人間が一つの意識になるという話。それに抗うことになるのが、世界で13人?だけ。
最初、「Pull lives」じゃないかと下手な英語で考えたんだがと問うと、それは直感的な解釈で、Pluribusがラテン語と知らなければ発音的にもおかしくないと。「Pull lives into one」と解釈できる。発音に関しては微妙に論理が捻じ曲がった奇妙な解釈だが。「Pull lives」はプルリブスとは読めない。プルライブスとなると指摘しているのに。
人気でシーズン2の製作も決まっているとか。
さて、うまく動くはずだが・・・
いや、iUIのMobile版の年数が旧年のままだ。これまで気付いたことはあったはずだが、一月だけのことなので、面倒で修正してこなかったのかもしれない。一文字削除。デバッグ完了のはず。やれやれ。へんなアルゴリズムを使っているからだよ。もう少しわかりやすく書けばいいものを。年変わりは長年鬼門だった。
尤も、iUIは既に古すぎる。使い方もわかりにくい。なんとかしたいと長年思ってはいるわけだが、元のPC版もモバイルで使えないわけでもないしとほったらかし。本体のPC版を含めてスムーズに考え直すことができる必然性のようなものをずーっと待っていた。自然観察マップのようなアプリを作ることを経験して、さてと。もう一度考え直すかな。
Geminiに相談し始めたのだが、何をやるにしても面倒なことになるのは目に見えている。結局、本サイトのURLを示して相談すると、アドバイスは「拝見したサイトはテキスト密度が高く、知的なデータベースのような側面があるため、装飾過多なものよりは Pico.css のような「文章を読みやすくすることに特化した、シンプルなフレームワーク」が、現在のスタイル(Perlによる自動生成)に最も合致するはずです」となった。一応、昨年12月と当月だけに適用してみた。ちょっと、趣味じゃないデザインと思うが、モバイル時の幅表示が完璧だね。
New Cartographies | Nicholas Carr | Substack。09/23/2018: [Internet]Rough Typeの後継。
CartgraphiesはCartgraphyの複数形だろうけど、Cartography - Wikipedia→地図学 - Wikipediaの意味か。
外気温0℃。もしかして、雪かと思ったら、その通り。8時過ぎには二階のベランダの手摺の雪はもう融けていた。昼には5℃まで上がった。居間の室温設定は22℃。ミニ書斎も20℃まで上がっている。
YouTubeに疲れ、テレビに疲れ、配信されるTVシリーズや映画に疲れ、とうとう、CDを掛けるという選択肢に辿り着く。静寂の中に音が立ち昇る。久しぶりに思い出した。しかし、耳には生体雑音のあることに気付く。これが耳鳴りかな。秋の虫の鳴き声のような。SN比の高い静寂のなかだからこそ気付く。時折、鳥の鳴き声が聞こえる。
コンピュータ机の左横に堆く積まれた本の高さは高くなるばかり。用の済んだ下の方の本を抜き取って整理するのが難しいからだ。読書マップ構想は道草に組み込むことになりそうだが、はて、どうなることやら。
ようやく、道草165に到達。{12/28/2025: [歩く]道草の生理学}←の表を参照。→{01/17/2026: [日記]夢の中で - 道草165ショート・ストーリー配信 - 「道草」は「roadgrass」か「grass on the wayside」か}で完了とするかどうか。
https://youtu.be/4nOa3gHtz9M 00:00 さて、行きます。 00:02 月が出てますね。 00:13 今日は綺麗です。 00:27 もう太陽は沈みかけてます。 00:38 ただいまの時刻は、16時34分28秒ですね。 00:59 今日は、そごうから、紙屋町から歩いてきました。 01:52 どうしますかね。 02:00 子供さんを連れて歩いてくる。 02:05 電車が来ますね。 02:15 今日はショートカットで、ショートで、録画時間が取れないと思ってたら、十分取れるみたいなので、連続で撮ります。 02:59 すじ雲がいっぱい出てますね。 03:09 さて、今日は平野橋の北側を渡ってですね。 03:55 北側方面を少し、録画しました。 04:02 北側も綺麗ですね。 04:18 さあ、今日は、東の空に月が。 04:38 半月が少し、膨らんでるぐらいの月が出てますね。 04:54 あ、ナンキンハゼで、丸坊主になっちゃいましたね。 05:40 もう向こうの、ナンキンハゼの樹木ですね。 05:49 下にいっぱいですね。 06:09 さあ、第一ヤマモモです。 06:29 あ、 06:40 ちょうど、石畳の、船着き場の石畳まで、水が上がってた。 06:48 上がるのか。 07:03 これから上がろうとしてるみたいでね。 07:05 満ちてきてる。 07:28 さて、透明度は、3段ぐらいまでは見えてますね。 08:12 4段目が、あるのかな。 08:22 見えてるかなっていう感じですね。 08:25 まあ、まあまあの透明度ですね。 08:29 見えてますもんね。 08:50 一応、充電、充電器をくっつけています。 09:17 第一ベンチ、到達ですね。 09:41 座って、夾竹桃も、ほとんど花はないですね。 09:48 でもまだ、つぼみがまだあります。 09:55 少し咲いてますね。 10:01 ここら辺、月が。 10:19 あ、今日は月がよく映るね。 10:22 いいね。 10:23 さあ、第二、船着き場ですね。 11:06 ここ、水が上がってきてます。 11:14 魚が来てもいいんだけど、ないね。 11:31 ちょっと、こちらが高く見えるな。 11:49 そうでもないのかな。 11:51 そうでもないのか。 11:56 1、2、3、4段目が見えるかどうかですね。 12:08 年を考えると、道草日記の165回ですね。 12:35 うん。 12:37 サルスベリも、ほとんど葉が落ちましたね。 12:54 太陽が沈むのが見えますね。 13:20 あれは、ハクセキレイの声だと思うんですけど。 13:40 チッチッチッチッチッチッって、鳴いていきますね。 13:49 さあ、ここは濡れてないな。 13:55 第三船着き場ですね。 14:01 まあ、ちょっと降りてみましょうか、ここは。 14:23 濡れてないから。 14:25 ここに来ると、4段目が見えますね。 14:45 1、2、3、4、 15:49 1、2、3、4、 15:53 4段目ぐらいまで見えますね。 15:56 まあ、大体、よく見える時の標準的な。 16:00 あ、ハクセキレイが来ましたね。 16:04 チュンチュンチュン。 16:07 チッチッチッチッチン。 16:09 ああ、また飛んでいきます。 16:11 カラスがいる。 16:17 このそばに着地したんですけど。 16:19 さあ、カラスくんが飛んでいってるね。 16:40 飛んでいってるね。 16:42 続いていってます。 16:55 ああ、また行きました。 17:26 第三船着き場に止まったね。 17:40 まあ、ちょっと帰るのはしんどいね。 17:42 さあ、第四船着き場です。 18:09 カラス君が歩いてますね。 18:15 ああ、このクスノキに止まったね。 18:27 さあ、第四船着き場ですね。 19:20 ウがいましたね。 19:46 ウが羽根をパタパタさしてますね。 20:27 捉えきれなかったね。 20:29 飛んでいく。 20:59 さあ、鵜の姿が撮れた、今日は。 21:03 うん。 21:04 今日は読書会がそごうであって。うん・・・あー・・・電灯がつきましたね。 21:49 日が沈んだから。 21:54 さあ、じゃあちょっともう、読書会を。 22:01 こちらの一人読書会もさっさと済ませましょう。 22:19 今日はですね。 22:29 ひっくり返す人類学。 22:31 奥野克実さん。 22:33 生きづらさのそもそもを問うと。 22:37 ちくまプリマー新書ですね。 22:44 2024年に書かれてる。 22:46 まあ、いろいろな人類学の観点から、人間とは何なのかという話ですね。 23:05 まあ、どんなものも人間とは何かを考える材料になりますけど。 23:16 人類学の観点から、どう考えたらいいんでしょうね。 23:24 いろいろな種族というか、民族というか、現代人とは全く違った生き方をしてる人たちもいるわけですね。 23:41 まあ、これはレヴィストロースの悲しき熱帯の続きみたいなもんでしょうね。 23:50 まあ、そういう気がします。 24:00 いろいろな生き方がある。 24:06 で、今日借りたのがこれですね。 24:15 捨てられた僕と母猫と奇跡。心に傷を負った二人が新たに見つけた居場所。 24:27 船ヶ山哲さん。サトルさんかな。 24:31 プレジデント社。 24:38 いや、どんな本かまだはっきり分からないんですけど。 24:45 船ヶ山哲です。哲さん。 24:47 これ、去年出た本ですね、これも。 24:52 まあ、なぜこれを借りることになったかというと、 24:58 これ日経新聞の、 25:00 ちょっと前の日経新聞の広告に出てたんですね。 25:09 10万部突破っていう。 25:12 1年で10万部、徐々に売れてる。 25:17 ずっと10万部までなった。 25:22 まあ、話題になってるんでしょうね。 25:28 まあ、今先の生きにくい話っていうと、 25:31 現代がどういう風に生きにくいかっていうのと関係があるような話ですよね。 25:36 まあ、タイトルが面白いんで。 25:51 捨てられた僕と母猫と奇跡。 25:55 母猫に育てられるんですかね。 25:58 よく分かりません。 26:00 ちょっとどんな、2人って書いてあるからな。 26:03 母猫が1人に数えられるかどうかよく分からないんで。 26:08 ちょっと中身を読んでみないといけませんね。 26:12 はい、まあそういうことで読んでみようと。 26:15 ちょっと面白いです。 26:18 すごいね。 26:31 で、これはね。 26:34 これは久しぶりに高価な本を買ってしまった。 26:40 まあ、これ前から話題にはしてるんだけど。 26:44 更新日記で話題にはしてるけど。 26:47 まあ、松岡正剛の千夜千冊。 26:51 で、松岡正剛先生が、 26:58 これはすごい、すごいというか、これにものすごく影響を受けたっていう本ですね。 27:04 人類の進化の本質とは突き詰めてみれば何なのか。 27:09 本書は人間を動物から区別する2つのもの。 27:12 身ぶりと言葉からこの大きな問いに迫っていく。 27:20 ここで言う身ぶりとは、単なる仕草にとどまらない。 27:24 技術を含む文化的行動様式。 27:28 一切を含んでいる。 27:31 二足歩行によって、 27:35 頭蓋と手足を発達させた人類が、 27:38 いかにして知性を育み、 27:41 記憶を外部のアーカイブに託していったのか。 27:44 その後の文化的価値観、文明的価値観に大きな変更をもたらした、 27:50 新たな欠乏と制御と、 27:52 壮大なパースペクティブのもと、 27:59 人の進化に理論的かつ実証的に迫った、 28:03 スリリングな大著。 28:10 すごそうでしょ。 28:12 アンドレ・ルロワ、 28:14 グーラン、 28:21 ル・ジェストゥ、 28:22 エ・ラ・パロール。 28:27 ちくま学芸文庫ですね。 28:32 松岡正剛先生が言ってるから、 28:36 ちょっと前取り上げたんだけど、 28:38 図書館で借りたので取り上げたんで、 28:44 きちっと読めてないな、 28:51 それで買いました。 28:55 とうとう、 28:57 2100円プラス税だから、 29:01 2000円以上するんです。 29:03 ごついけどね。 29:07 ごついだけじゃ、 29:08 意味がないんだけどね。 29:12 まあ、そういうことで、 29:15 今日は、 29:16 今日の3冊目、 29:17 ひっくり返す人類学も、 29:19 図書館で借りて、 29:22 身ぶりと言葉は以前、 29:24 もうだいぶ、 29:28 くたびれた本を借りた記憶があります。 29:31 まあ、そういうことで、 29:36 えー、29分だな。 29:42 さあ、日が沈んだと思うんで、 29:44 帰りましょう。 30:09 ハクセキレイ。 30:45 今日はね、 30:47 スマートな、 30:49 ツバメのように見えるんだけど、 30:51 ずいぶん大きな、 30:53 鳥を見ましたね。 30:56 ツバメじゃないのかな。 30:57 やはり、大きすぎるよな。 30:59 何してるの。 31:07 誰か、 31:08 何かしてるのかな。 31:59 さあ、第6ですね、 32:02 ここは。 32:03 あ、違うか。 32:08 第5だ。 32:09 第5船着き場です。 32:54 さあ、第3ベンチ到達ですね。 34:26 さあ、第六ですね。 第六は繋がっているんです。 34:55 さあ、まあ降りましょうか。 今日は 35:01 ウぐらいしか、見れてないかな。 35:05 まあ運が良かったね、今回は。 1、2、3、4、 35:19 4段まで見えてるね。 まあ今、満潮なんでしょうね。 35:30 これから引いていきそうな雰囲気だね。 37:00 さて、さて、さて。 37:17 さあ、今日は、夜の散歩は、 37:22 なしかな。 8,000歩超えましたね、今日。 37:28 紙屋町から歩いて帰ってきたから。 単純に歩いただけだと、 37:43 8,000歩は超えないですね。 プラスアルファなんでね。 37:50 散歩してもね、道草をしても。 やはり、 38:02 夜歩くと、よく眠れますね。 38:06 まあ、完璧に目が覚めないわけじゃないんだけど、いつもよりはだいぶ寝れます。 38:24 ああ、ここは満ち。あれは何だろう? 38:33 イソヒヨドリかな? 飛んできましたね。 38:46 今のはハクセギレイじゃない。 水面すれすれに飛んできました。 38:55 第7船着き場です。 上がってきてますね、水が。 39:12 まだ満ちてるんですね。 そうでもないか。 39:41 1、2、3、4、5段目ぐらいまで見えてますね。 6段も見えてるね。 39:49 目では。 これすごい透明度としては、これまで最高記録。 39:57 6段ぐらいが見えてるね。第7船着き場です。 1、2、3、4、5、6。 40:11 1、2、3、4、5、6。 肉眼だと6段目が一応見えますね。 40:17 カメラだと5段目ぐらいまでしか見えないです。 6段だと1.2メートル、1段が20センチですから。 40:34 さあ、今日は、買い物は昨日夜行ったので、10時ぐらいに行ったので。 40:44 雲がなくなりましたね。 水面に円形の波が広がってますね。 41:27 さあ、ああ、上に上がってきてるね。 42:07 まだ満ちてる。 第8船着き場です。 43:14 ワンちゃんを散歩させてますね。 目で見ると、もう少し暗い感じで見えてます。 44:33 さあ、第4ベンチ到達ですね。 第5ナンキンハゼですけど。 44:50 第5ナンキンハゼと、月を撮りましょうか。 45:05 周囲が暗くなるから、綺麗に。 45:09 綺麗に撮りましょうか。 周囲が暗くなるから、綺麗に。 45:10 綺麗には見えない。 明るくね、明るく映っちゃう。 45:23 終わりにしましょうか。 充電できましたね。 45:30 充電しながら撮影してるんですけど、これを撮って終わりにしましょう。 45:43 85%ぐらい電力があるので、この明るさは肉眼とほぼ一緒ですね。 46:00 これで終了します。 46:24 お疲れ様でした。 46:26 はい、 46:28 ご視聴ありがとうございます。 46:30 あれ、また来た。 46:32 また来た。 46:39 ちょっと明るく映るから。 46:41 このヒロデンで終わりにしましょう。 46:49 お疲れ様でした。 46:52 ありがとうございました。 46:54 はい、終了。
カラーの夢、リアルな夢を最近よく見る。夢を見ると寝覚めが良いような気がする。二度寝がいいようだ。Readinessの70点越えが三日続いた。Readinessは心拍数の変動から測られるようだ。負荷による心拍数の増大から平静時までの回復パターンのようなものから推定するらしい。
Gemini3が道草165のショートを作る(create_story_shorts.py)ときに「roadgrass_shorts」というフォルダ名を作ったので、えっ、これは何と思ったわけだが、よく考えると道草の意味なんだね。ジェフリー・ディーヴァーの「ロードサイド・クロス」という小説タイトルを思い出した。それで、道草を英語でなんて言うのかなとAIルと、夏目漱石の自伝的小説「道草」があることに気付いた。この英訳のタイトルが「Grass on the Wayside」。結局、Kindleでちくま文庫版準拠の「夏目漱石全集 決定版 全124作品 (インクナブラPD)」を購入して最初の方を読んで、さらにざっくり最後のほうまで見ていくと、単純ではなく文体も内容も中で大きく変化があり複雑だ、新聞連載で100以上の節に分かれている。新潮文庫版「道草」に柄谷行人の解説があるので古本で購入。何してんのかわからない・・・人生、夢の中・・・
import os
from moviepy import VideoFileClip, TextClip, CompositeVideoClip
# --- 設定 ---
VIDEO_PATH = "IMG_0039.MOV"
FONT_NAME = r"C:\Windows\Fonts\msgothic.ttc" # Windows標準フォント
OUTPUT_DIR = "roadgrass_shorts"
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
# ストーリー性を持たせた6つのシーン(開始秒、終了秒、字幕)
# ソース[1]~[11]のタイムスタンプに基づき構成
scenes = [
{
"start": 0.3, "end": 40.0,
"text": "【出発】紙屋町からの帰り道。月と沈みゆく太陽が綺麗です。"
},
{
"start": 863.0, "end": 905.0,
"text": "【観察】第3船着き場。石段の4段目まで見える、いつもの透明度。"
},
{
"start": 1186.0, "end": 1265.0,
"text": "【幸運】ウがいました。羽根をパタパタさせて…今日は運が良い。"
},
{
"start": 1321.0, "end": 1385.0,
"text": "【知索】一人読書会。人類学の観点から人間とは何かを考える。"
},
{
"start": 2242.0, "end": 2290.0,
"text": "【充足】8,000歩達成。夜歩くとよく眠れる、身体の満足感。"
},
{
"start": 2795.0, "end": 2816.0,
"text": "【結末】肉眼と同じ明るさの夜景。広電を見送って終了します。"
}
]
def create_story_shorts():
with VideoFileClip(VIDEO_PATH) as video:
# 動画のサイズ取得
w, h = video.size
target_w = int(h * 9 / 16) # 9:16の幅を計算
for i, scene in enumerate(scenes):
# 1. 切り出し
clip = video.subclipped(scene["start"], scene["end"])
# 2. センタークロップ(横長を縦長に)
clip_vertical = clip.cropped(x_center=int(w/2), width="target_w," height="h)"
# 3. 字幕(下部に表示、折り返し設定)
txt = TextClip(
text=scene["text"],
font=FONT_NAME,
font_size=45,
color='yellow',
method='caption',
size=(int(target_w * 0.9), None)
).with_start(0).with_duration(clip.duration).with_position(('center', 'bottom'))
# 4. 合成
final = CompositeVideoClip([clip_vertical, txt])
# 5. 書き出し
out_file = os.path.join(OUTPUT_DIR, f"story_{i+1}.mp4")
print(f"作成中: {out_file}")
final.write_videofile(out_file, codec="libx264", audio_codec="aac", fps=24)
final.close()
if __name__ == "__main__":
create_story_shorts()
自然・生活を捉えるのが日本的日記だろう。AIに「侘び寂び」がわかるかどうか、試してみたいところだ。この一年で生成AI/LLMで描く日記を試していく時代に入った。昨日、手書きの日記ノートのA4見開きを撮影して、Gemini3に画像貼り付けして、文面を解析して表にしてもらった。論理的には不完全な思い付きで追加しながらのチャラ書きだが、かなりまとまった。プロンプトをかなり追加して修正していったが、完全にすることは手間と時間が掛かり過ぎ。Googleスプレッドシートに出力して手を入れた。{12/28/2025: [歩く]道草の生理学}←の続き。
| 日付 | ナイト・ウォーク | 散歩世界プロジェクト | 道草日記 | 内容・備考 |
|---|---|---|---|---|
| 2025/11/28 | NW1 | WWP35 | NightSketch(4) | |
| 2025/11/30 | WWP36 | M165 | ||
| 2025/12/2 | M166 | 1/19配信(道草166ハイブリッド・ショート) | ||
| 2025/12/5 | NW2 | WWP37 | Photo(1) | |
| 2025/12/6 | NW3 | WWP38 | Photo(4) / ★blog★12/06/2025: [歩く]晴れた夜 月魚座星 灯りかな | |
| 2025/12/7 | NW4 | WWP39 | Photo(6) / ★blog★12/07/2025: [歩く]なをよべど ゆめにこられん あいうえお | |
| 2025/12/9 | NW5 | WWP40 | Photo(10)/NightSketch(3)/★blog★木星を 見間違えたり 夜散歩 (12/09/2025) | |
| 2025/12/11 | M167 | |||
| 2025/12/12 | NW6 | WWP41 | ★blog★(ふたご座流星群)12/12/2025: [天体]初冬や 流星ながる シリウスに、Photo(18)、NightSketch(1) | |
| 2025/12/13 | M168 | |||
| 2025/12/14 | NW7 | WWP42 | ★blog★(ふたご座流星群)12/14/2025: [天体]ふたご座の 流星ながる みぎひだり、Photo(9) | |
| 2025/12/15 | NW8 | WWP43 | ★blog★(ふたご座流星群)ナイトウォークへ (12/15/2025)、Photo(6)、NightSketch(1) | |
| 2025/12/16 | NW9 | WWP44 | - | NightSketch(1) |
| 2025/12/18 | M169 | |||
| 2025/12/20 | WWP45 | NightSketch(横長1) OB会帰り、★blog★ (12/20)12/20/2025: [日記]心無罣礙 | ||
| 2025/12/23 | NW10 | WWP46 | NightSketch(3) | |
| 2025/12/25 | M170 | |||
| 2025/12/26 | NW11 | WWP47 | blog (12/27)、NightSketch(3) | |
| 2025/12/27 | NW12 | WWP48 | ★blog★12/27/2025: [歩く]神無しみに 振り返り見る ジュピター星、Photo(3)、NightSketch(3) | |
| 2025/12/29 | NW13 | WWP49 | Photo(2) | |
| 2025/12/30 | NW14 | WWP50 | NightSketch(4) | |
| 2026/1/4 | NW15 | WWP51 | - | NightSketch(1) |
| 2026/1/6 | NW16 | WWP52 | - | Photo(2)、NightSketch(1) |
| 2026/1/9 | NW17 | WWP53 | blog (1/13)、冬の大三角、NightSketch(1) | |
| 2026/1/10 | NW18 | WWP53 | blog (1/13)、木星+ベテルギウス、NightSketch(2) | |
| 2026/1/11 | NW19 | WWP54 | blog (1/13)、雪の記録、NightSketch(2) | |
| 2026/1/13 | NW20 | WWP55 | ★blog★1/9-1/13、01/13/2026: [歩く]道草の整理が追い付かないが - 雪の降る街を 思い出だけが 通り過ぎて行く、NightSketch(4) | |
| 2026/1/14 | M171 | |||
| 2026/1/15 | NW21 | WWP56 | NightSketch(4) | |
| 2026/1/17 | NW22 | WWP57 | NightSketch(2) | |
| 2026/1/18 | NW23 | WWP58 | NightSketch(4) |
今のところ、動画と字幕からショート動画のエピソードをNotebookLMから提案してもらうという方法を基本に置こうとしているが、そのままでは使えない。Subtitle Editを使って、提案の妥当性を見る。もちろん、字幕だけから切り出し範囲を決定するのは不可能だ。しゃべりと動画像の両方から判断する必要があるからだ。修正済みのショート動画書き出しスクリプト(roadgrass_167_shorts_r2.py)。スクリプトのエピソード設定の部分を再編集している。テキストはすべて簡潔に書き直した。過剰な情報は視聴者の見る意欲を失わせる。見るきっかけになるような言葉に止める。エピソードは7件目を二つに分け、時間範囲も拡大している。
import os
from moviepy import VideoFileClip, TextClip, CompositeVideoClip
# --- 設定 ---
# 実行環境に合わせてフォントパスを変更してください
FONT_NAME = r"C:\Windows\Fonts\msgothic.ttc"
OUTPUT_DIR = "roadgrass_167_shorts_r2"
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
# エピソード設定(ソースのSRTタイムスタンプに基づく)
# file: 動画ファイル名, start: 開始秒, end: 終了秒, text: 字幕
episodes = [
{
"file": "IMG_0005.MOV", "start": 0.2, "end": 35.0,
"text": "さて、さて行きます・・・" # [1]
},
{
"file": "IMG_0006.MOV", "start": 646.9, "end": 665.0,
"text": "今日も荷物が・・・" # [2, 5]
},
{
"file": "IMG_0006.MOV", "start": 780.0, "end": 815.0,
"text": "石段の6段目、7段目が・・・" # [6, 7]
},
{
"file": "IMG_0006.MOV", "start": 1306.0, "end": 1323.0,
"text": "魚がいる・・・" # [3]
},
{
"file": "IMG_0006.MOV", "start": 584.0, "end": 616.0,
"text": "第一ベンチ・・・" # [2]
},
{
"file": "IMG_0007.MOV", "start": 1261.0, "end": 1318.0,
"text": "カラスの小枝事件・・・" # [4]
},
{
"file": "IMG_0007.MOV", "start": 1403.0, "end": 1574.0,
"text": "岸壁の小魚・・・" # [8, 9]
},
{
"file": "IMG_0007.MOV", "start": 1574.0, "end": 1646.0,
"text": "自然の赴くままに・・・" # [8, 9]
}
]
def create_shorts():
for i, ep in enumerate(episodes):
if not os.path.exists(ep["file"]):
print(f"警告: {ep['file']} が見つかりません。スキップします。")
continue
with VideoFileClip(ep["file"]) as video:
# 1. 切り出し
clip = video.subclipped(ep["start"], ep["end"])
# 2. 9:16 センタークロップ
w, h = clip.size
target_w = int(h * 9 / 16)
clip_vertical = clip.cropped(x_center=int(w/2), width="target_w," height="h)"
# 3. 字幕(下部中央、自動改行)
txt = TextClip(
text=ep["text"],
font=FONT_NAME,
font_size=40,
color='yellow',
method='caption',
size=(int(target_w * 0.9), None)
).with_start(0).with_duration(clip.duration).with_position(('center', 'bottom'))
# 4. 合成
final = CompositeVideoClip([clip_vertical, txt])
# 5. 書き出し
out_name = os.path.join(OUTPUT_DIR, f"167_short_{i+1}.mp4")
print(f"出力中: {out_name}")
final.write_videofile(out_name, codec="libx264", audio_codec="aac", fps=24)
final.close()
if __name__ == "__main__":
create_shorts()
perlで生成したチャプターリンク付道草167チャプター。
https://youtu.be/eHnyi5pGeWI 00:00 さて、さて、行きます。 00:04 傘忘れてきた。 00:32 取りに帰ります。
https://youtu.be/4T4tu0AK9V0 00:04 再開します。 00:11 傘立てに忘れたので、いつもと違うスタートですね。 00:24 2回目かな。濡れてるので、滑らないように気を付けないと。 00:58 さぁ、行きましょう。 01:32 図書館帰りの道草日記の167回ですね。 01:37 ちょっと明るすぎるかな。 01:56 これはホワイトバランス。 01:58 これか。 01:59 このままですかね。 02:52 充電器を背面につけているので、無線給電をしながら撮影ですね。 03:01 さぁ、渡りましょうか。 03:36 さぁ、渡ります。 05:14 今日出るときは、完全に雨が降っていて、1時間ぐらい小雨が続くでしょうという予報だったので。 05:26 あ、降ってるし、当然傘を持っていたんですけど。 05:31 これですね。 06:25 今日は満ちてるんでしょうね。 06:29 濁ってる感じがします。 06:35 スズメが飛び立ちましたね。 07:18 すっかり葉が落ちましたね。 07:46 ここはちょっと、掃いてあるような気がします。 08:09 第一ヤマモモです。 08:11 ヤマモモですね。 08:13 今日は、タバコ吸いのおじさんがおられるので、それを避けての撮影でした。 09:44 第一ベンチ到達ですね。 09:55 濡れてます。 09:56 あぁ、そうか。 10:02 今日は座っては難しい。 10:05 座って、読書会は難しいなぁ。 10:16 ライトが点いたり、消えましたね、点いてたのが。 10:21 明かりが差し込んだからかな。 10:46 さぁ、今日も荷物がちょっと重たいですね。 10:49 5冊入ってます。 10:51 8冊返して、全部。 10:56 今日はもう返しちゃって。 10:58 5冊、新たに借りました。 11:03 1、2、3、4。 11:53 今、2段目が洗われてますね。 12:02 水に洗われてます。 12:07 それを含めて4段。 12:11 5段目はちょっと。 12:14 1、2、3、4。 12:19 5段目がちょっと見えるかなって感じですね。 12:23 そんなに、ここに来るとそれほどの。 12:25 普段どおりですかね。 12:31 これぐらいの透明度。 12:33 1段が20cmです。 12:37 4段だと80cm。 12:39 1、2、3、4。 12:42 あぁ。 12:44 もう。 12:46 2段目から水は引いて。 12:49 3段目に来てますね。 13:00 1、2、3、4。 13:02 あぁ。 13:04 1、2、3、4、5。 13:06 6段目。 13:10 6段目、7段目が見えるぐらいですね。 13:19 まぁまぁの透明度だな。 13:22 でもちょっと視覚的には、 13:26 あんまり透明度が高くないように見えるんですけど、 13:30 石段を見た感じ、石段の見え方で見ると、 13:35 まぁ普通かなっていう感じですね。 14:59 さぁ。 15:03 サルスベリも完全に枯れましたね。 15:50 さぁって。 15:55 第3船着き場ですね。 16:12 あぁ、魚がいますね。 16:14 います、います。 16:16 ちょっと降りてみましょう。第3船着き場。 16:56 ちょっと。 16:57 荷物を置いてですね。 17:00 3、4、5、6。 17:25 6段目までは見えてますね。 17:28 7段目もかろうじて見えてる。 18:16 1、2、3、4、5、6。 18:19 6段目まで見えてますね。 19:00 魚がね、近寄ってくれれば、 19:03 今先、見ましたからね。 19:57 魚が。 19:59 あきらめましょうか。 20:08 あきらめますか。 20:10 あきらめましょうか。 20:17 よいしょ。 20:18 ちょっと。 20:46 肩から本を入れたバッグを掛けてね。 20:54 ズレをですね。 20:56 そうすると、 21:00 魚がいる。 21:46 魚のね、お腹が上を向いた時に白く光るんですね。 21:50 今のはチヌだと思うんですけどね。 21:58 よいしょ。
https://youtu.be/zwjqZGmNK24 00:09 ちょっと撮影、再再開ですね。 00:13 第三船着き場、石畳から。石畳、石段には寄ってきませんね、魚がね。残念ながら。石段の上を泳ぐ時もあるんですね。 00:42 さあ、第三船着き場、終了しましょう。 01:20 よいしょ。さあ、ここの花水木は完全にほぼ落ちましたね。 02:00 これは何だろう。これはクスノキですよね。 02:03 これは桜ですかね。芽が、花が咲く準備ですかね。 02:38 掃除がきれいにしてありますね。 02:53 さあ、タブノキ、クスノキ。 02:57 やはりクスノキか。 03:05 ここも桜です。さあ、第四船着き場ですね。 04:08 魚はいませんね。 04:28 三段目が見え始めてますね。 04:33 4、5、6、7。 04:35 7段目ぐらいまで見えてます。 04:41 まあ、80センチぐらいが標準的な透明度なので、4段が。 04:47 さあ、逃げられちゃったね。ちょっと映りましたけどね。 05:36 さて、第二ベンチに到達しました。 05:42 乾いてますか。いや、無理ですね。やはり。 05:50 濡れてます。さあ、どうしようかな。 06:13 えっと、まあ、何もないな。 06:58 植物は逃げていかないけどね。 07:00 さて、第五船着き場です。 07:34 いましたね。逃げちゃいましたね。 10:35 ちょっと、ガバンを持ち替えます。逆側に。 11:07 さあ、第三ベンチ、到達ですね。 12:06 前、ちょっと炎のような植物っていうのが、こんな風に変わってます。 12:11 第一椿。さあ、みんな葉が落ちましたね。 12:23 桜並木ですね、ここは。 13:00 頂点はね、ベンチが使えないんだけど、一段も濡れてるので、ちょっと難しいですね。 13:29 第六ですね。魚がいましたけどね。 13:52 さて、どうしようかな。 14:11 さあ、魚はね、ここで。 15:18 まあ、水の中ですもんね。 15:20 そう、都合よくは、この水木ですね。 16:20 こんな感じになってます。 17:03 第三椿ですね。 17:27 さて、さて、さて。 17:29 はい、はい、はい。 17:32 さて、さて、さて。 17:34 はい、はい、はい。 17:36 さあ、第七ですね。 18:05 第七船着き場です。 19:47 面白い子ですね。 20:00 結局、よく晴れましたね。 20:04 夜は星が見えるかな。 20:06 少し薄曇りな感じなので。 20:16 夜の散歩プロジェクトで、ナイトスケッチっていうのをやろうかと思ったりしてるんですけど。 20:24 まあ、ヒロデンを撮ったりすることが多いんで。 20:32 帰っているなあ、何か。 20:37 カラスかな。 20:39 そう、・・・・・・ありゃりゃ。 21:01 ナンキンハゼですね、これ。 21:19 これ、きれいに、 21:24 掃除されちゃってるから、 21:26 今年はどういうふうになるかな。 21:32 いや、もう、ねえ。 21:39 カラスの小枝事件というのが、去年は題材だったんですけど。 21:46 今年はきれいになっちゃってる。 21:55 ダメかもしれない。 21:58 まあ、 22:03 人と自然が混じり合う場所なので。 22:27 さあ、 22:31 ただいまの時刻、17時03分09秒ですね。 22:35 さあ、第8船着き場、 23:23 終点に来ましたね。 23:25 石段に魚がちょっといたような気がしましたけど、 23:35 今日は鳥と出会わないですね。 24:00 上空をカラスが飛んで帰ったぐらいですか。 24:10 写真らしい写真が、少し撮れた。(岸壁の小魚の群れが光る) 26:08 終わりにしましょう。 26:14 自然が赴くままなんで。 26:20 さあ、ここは座れそうかな。 26:39 うーん、ちょっと完璧ではないな。 26:41 さあ、終わりにしましょう。 26:52 第5ナンキンハゼですね。 26:58 はい。 27:13 終了します。 27:15 お疲れ様でした。 27:17 いつもご視聴ありがとうございます。 27:19 はい、終了しまーす。 27:22 買い物行って帰ります。 27:25 はい。
取り敢えず、YouTubeリンク付きチャプターをまず置く。
https://youtu.be/_2T9MQKvGMw 00:00 さて、図書館帰りの道草日記の168回ですね。 00:22 ただいまの時刻16時51分11秒です。 00:31 雨が、小雨が落ちてるのかもしれないんですけど 00:37 降ったりやんだりという感じで、今日はもう流して歩く感じになると思います。 01:01 もう暗くなっちゃいますね。 ナンキンハゼも。 01:05 ほとんどもう、 葉が全部落ちましたね。 01:12 第一ヤマモモですね。 今日も内蔵マイクです。 01:21 今日はスケッチみたいな感じで、やろうと思ったんですけど 01:33 まあ、ついつい、撮り始めちゃいまして。 01:54 石段は二段目ですね。 二段目にまで水面が来てます。 02:00 1、2、3、4、5 02:04 1、2、3、4、1、2、3、4、5 02:09 6段目が見えるぐらいですね。 02:21 普通の透明度ですね。 4段ぐらい。 02:29 さあ、行きましょう。 道草のね、どういう風に 02:42 どういう風にしたらいいのかなって考えてますね。 03:03 ちょっと足踏み状態。 03:05 と、・・・・・・ 03:15 さあ、第一ベンチ、到着ですね。 03:24 まあ、朗読をしようといったのもまだ続いてないし。 03:29 うーん、ちょっといろんなことをやりすぎて。 03:53 さすがに夾竹桃も、ほとんど花が、 04:03 つぼみが、上の方には見えなくはない。 04:37 第二ナンキンハゼですね。 04:42 もうほとんど、葉が落ちてます。・・・・・・さて、・・・・・・さあ、 05:56 第二船着き場も、水滴、指に、水滴が落ちましたね。 06:08 第二ヤマモモに来ましたね。 07:03 さあサルスベリも、もう何度も撮ってますね。 07:17 まあ、ハナミズキはまだ実がついてますね。 08:05 (イソヒヨドリ) 08:27 イソヒヨドリですかね。 08:42 あれ、どこ行ったのかな。 08:44 見えなくなっちゃった。手前に飛んできたのかな。 08:47 第三に、今、いたんですね。 10:36 イソヒヨドリらしくて。 10:37 黒っぽく見えるんですね。 10:39 さあ第四船着き場。 10:41 今日はさすがに、寒いですね。 11:24 10度以下。 11:26 8度ですか。 11:34 さあ、第四に続きまして、第二ベンチ。 12:08 到達ですね。 12:10 ここのハナミズキは、まだまだ、葉が落ちてませんね。 12:14 こっち、このハナミズキは落ちてます。 12:16 これもそうですね。 12:28 これも落ちてます。 12:33 これは桜ですね。 12:55 双子座流星群の、 13:22 極大日が、明日なので。 13:24 まあ、明日は一応、 13:26 まあ、 13:28 晴れ時々曇りか、曇り時々晴れか、 13:32 微妙な天候なので。 13:34 まあ、今日は無理。 13:36 今日は無理ですけど。 13:41 昨日は一つ、流れるのを見ました。 13:51 さあ、第五ですね。 13:55 第五船着き場に来ました。 13:57 第一、第五船着き場で、 14:47 第三ベンチ、到達ですね。 14:52 第六船着き場です。 15:50 これは何ですかね。 16:58 浮かんでるだけですかね。・・・・・・わかりませんねえ。 18:27 さあ、まだ十八分。 18:41 第七船着き場。 19:30 何もないと、二十分、 19:32 前後だ。 19:37 さあ、これは第四かな。 19:39 第四。 19:45 ナンキンハゼですね。 20:07 縦持ちでずっと来ちゃいましたね。 20:09 まあ、いいですけどね。 20:29 さて、第一じゃなくて、 20:31 一人読書会も、 20:33 今日は寒いし、 20:35 寒くて遅いので、 20:37 暗いので、 20:39 ブログの方で、 20:41 これもやります。 20:43 やりますね。 20:59 さあ、第八船着き場が、 21:01 見えてきましたね。 21:03 来ましたね。 21:18 ハクセキレイでしたね。 21:20 ハクセキレイが飛んできました。 21:30 暗くなっても、 21:32 まだいるんですね。 21:39 残念、逃してしまったから、 21:44 まあ、下まで降りてみましょうかね。最後の・・・ 21:59 あー雨が落ちてきた。 22:05 5時から雨だっていう予報なので、 22:09 17時12分56秒です。 22:11 今日はもう、 22:56 帰ります。 23:17 第四ベンチ、 23:19 到達ですね。 23:21 第五ナンキンハゼ。 23:23 見事に、 23:28 葉が落ちてます。 23:32 きれいに掃除してあるね、今年は。 23:34 まあ、下に掃き寄せられてるから、 23:38 さあ、どうなるんだ。 23:40 これで、 23:48 今日、終了します。 23:50 お疲れ様でした。 23:52 毎度ご視聴、 23:54 ありがとうございます。 23:56 失礼します。
さよなら3DCG、こんにちはNotebookLM。AIで激変するクリエイティブと2025年の総決算 ep636 backspace.fm チャンネル登録者数 1.47万人 10,320 回視聴 2025/12/28 にライブ配信。やはりNotebookLMだよねと思った。ソースの問題は普通のLLMでもプロンプトで絞り込める。Studioがおもしろいということだろう。
AI嫌いがチャンネル登録者数にも影響を与えるという話もそうありなんと思った。何ごとにも好き嫌いはある。捨てる神あれば拾う神ありというわけだ。自分の信じる道を進むしかない。
昔はプログラミングを毛嫌いする人もいた。今ならAIだろう。
瞠目した緑茶2L108円が2/4から158円になるという予告。卵10個パック258円も既に20円値上げして278円など、売り上げの減少を値上げでカバーしようとする動きに思えた。なんとか目玉商品で消費減少を押し留めようとする努力も限界なのかもしれない。例のポリフェノール入りのカカオチョコレートも1180円に高止まりしたままだ。消費者は最早ポリフェノール神話に挑むしかないのかもしれない。
ちょっと前、自然災害に備えてローリング・ストックをしましょうという張り紙が出たことがあった。トヨタカンバン方式なら、毎日のメニューに合わせて当日必要な分だけ購入するということになるだろう。実際にはそういうわけにはいかない。販売の単位がある。30品目の多様性が腸の健康には必要という話もあるが、毎日30品目食べられる訳ではない。ローリング・メニュ―を考えて、在庫を最小限化する工夫の必要があるだろう。
お米がほぼなくなりそうなので、昨晩お米を買いに行くと、同じ銘柄が3,980円から4,980円に。目を疑った。25%アップ。まあ、全体的にそれぐらいアップしている感じがある。仕方がないので、VTBPの国産米にした。4,280円也。他の一般銘柄とは別の場所に置いてある。もう他に5,000円/5kg以下のものはない。主食はお米以外の選択肢を模索しないといけないかな。4980円/21日=237円/日也。1.5合/日。3膳/日。79円/膳か。250kcal/膳150g程度。たんぱく質3.8-3.9g。ライ麦トースト5枚(実際は6枚入り、測定すると60g/枚)で248円。242kcal/100g、155kcal/枚。たんぱく質11.3g/100g。1斤340g以上。ちょっと、一枚当たりのカロリー計算が合わないけど。40-50円/枚なら安いね。低糖質高たんぱくだし。
高ポリフェノールカカオ86%チョコレートは120円クーポンが付いたので、一昨日、最後の一袋を購入したが、昨晩も維持されていたので一袋追加購入。しかし、高過ぎるよね。これで終わりにするか真剣に考えよう。
他に高いものは、素焼きミックスナッツ(アーモンド・くるみ・カシューナッツ)が1280円/410g、食べ過ぎる感じもあるので、個包装の28gx7袋=196g、598円に切り替え。183kcal,たんぱく質5.4g,脂質16.3g,糖質2.8g,食物繊維2.0g/28g。意味を考えないと、これも神話だ。
年末から作り始めた食物データベース・ノートとレシマルの品目検索で一目瞭然だ。
{01/27/2026: [日記]分かれ目・切れ目の物価高騰最前線}←の続き。
{追記(2026-01-30): 今日、パンと牛乳・豆乳、キャベツのみじん切り、冷凍ブロッコリーなどを買いに行くと お米の価格が一気に下げられていた。チョコレートも例の980円、120円クーポン付き復活。おいおい、やれやれ。ここに書くと連動して動く・・・スモール・ワールドかな? まあ、コメが主食と言っても一日一食だからねえ。朝はパンだし、もう一食を麺類やピザ、弁当などにするということになる。友達が送ってくれた切り餅もまだ半分1.8kgあるし。これはおいしい。いつもは味噌汁にサバ缶とお雑煮にして食べるのだが、パンがなくて困った時、トースターで焼いた餅に、ジャムを塗ってチーズを載せて食べると結構乙なものだった。切り餅はお米よりもだいぶ高価なはずだけど^^;)}
もう記憶から遠い。いろいろなことがあったから。検索して{漫勉 浦沢直樹×浦沢直樹 (2016/10/08)}←を見つけた。漫勉も今はneoになっている。気付いてはいたが、なかなか辿り着けなかった。AKIRAがそれを手繰り寄せた。再放送をNHK ONEで見た。
「三月のライオン」が題材でもあったので、{ぴよ将棋、実戦詰将棋研究 (2022/07/16)}{夏の夜の図書館駆動型読書論 VII うつ病九段 (2022/07/30)}←の記事にも関係している。見ようと思った切っ掛けだ。
しかし、創造というものがどのようなものかを教えてくれる番組は少ない。
「浦沢直樹の漫勉neo (20)大友克洋 2026年1月4日(日)午前0:06~0:55 ※3日(土)深夜 [Eテレ]」も忘れないようにしないと。その前、午後10時からAKIRAも放映される。スモール・ワールドだよ。GoogleのTodoに入れているのにさっきまで思い出せなかった。Google Calendarのアプリってないのかな。タブをウインドウで開いて、別にすればいいわけだけど。ショートカットを作るという方法もあったはず。もはや、そういう思想は馴染まないのかな。Chromeはタスクマネージャさえ持っている。
The Night Managerのシーズン2が配信され始めたが、最初がよくわからない。どうも10年前のものがシーズン1らしい。よかったことは憶えているが、筋は忘れている。ナイトで検索したが出てこない。Nightで検索すると出てきた。{ 最近では、「The Night Manager」の6回シリーズが、やはり英国のスパイものだけど、重厚感、英国的ハードリアリズムにヒューマニズムを加えて見応えがあった。ジョン・ル・カレ原作。脚本はDavid Farr (theatre director) - Wikipedia。最近、レイ・ブラッドベリが「白鯨」の脚本を書いたということを知ったとき、screenplayの訳が「脚本」だとわかった。言葉から受けるイメージはむしろカメラワークなので、これまで意味を調べたことさえなかった。脚本ならシナリオ(scenario)だろうと考えていたわけだ。: 広島-中日戦、「路上のジャズ」、コルトレーンとドルフィーのフリージャズ、「The BFG」と「SPECTRE」 (2016/09/18)}←。シーズン1のエピソード8から見始めた。
最近、Clariceを見つけて気になっていた。昨晩深夜、エピソード1を見た。これもかなり良い。お勧めの作品だね。「クラリス」は、「羊たちの沈黙」の“バッファロー・ビル事件”から1年後、1993年にFBI捜査官として現場に復帰したクラリス・スターリング(レベッカ・ブリーズ)を主人公に、彼女自身の知られざるストーリーに深く踏み込む。聡明で傷つきやすいクラリスの勇敢さは、彼女の内面に光を与え、それが怪物や狂人たちを引きつけてしまう。・・・(primevideo.com)。
PF読書会で取り上げた本。
読書会で疑問に思ったことをGemini3と対話、表出力だけ残す。
| 時代 | 主な評価軸 | 捉え方 |
|---|---|---|
| 中世 | 宗教・無常 | 執着を捨てるための修行の書 |
| 近世 | 文芸・教養 | 雅な文体と隠遁美学のモデル |
| 近代 | 古典文学 | 日本文化の伝統としての随筆 |
| 現代 | 災害・文明批評 | 乱世や危機の時代を生き抜く知恵 |
| 災厄名 | 発生年(西暦) | 概要と長明の記述 |
|---|---|---|
| 安元の火災 | 1177年 | 都の3分の1が焼失。「吹き迷う風に、とかく移りゆく」と、火の勢いの恐ろしさを描写。 |
| 治承の辻風 | 1180年 | 巨大な竜巻が発生。家々が宙を舞い、吹き飛ばされた様子を「地獄の業風(ごうふう)なり」と表現。 |
| 福原遷都 | 1180年 | 平清盛による強引な遷都。荒れ果てていく京都の街と、人々の混乱と嘆きが綴られています。 |
| 養和の飢饉 | 1181年-1182年 | 干ばつ、台風、洪水が重なり大飢饉に。道端に死体が溢れ、親子の絆すら壊れる惨状を記録。 |
| 元暦の地震 | 1185年 | 琵琶湖の水が溢れ、大地が裂ける大地震。「世の中の恐ろしき中に、恐ろしきは地震なり」と述懐。 |
年末から、藤井聡太名人・竜王のYouTube動画を見ている。評価の基準はAIの最善手ということにはならない。当然のことながら、AIを見ながら将棋を指しているわけではなく、自分で考えて指している。完璧な将棋を目指していたが、そういうものは結局ないのではないかという考えが、面白いと思える方向に価値を置くのがよいという考えを導き出したらしい。
AIで忙しすぎて、将棋を取り上げる暇がない。王将戦はABEMAで午前中見て、昼からはYouTubeのトリビアで静かに観戦という感じ。感想戦はYouTube。将棋は静かなのと進行が遅いのがプログラマーには好都合なわけだ。邪魔にならない。のめり込んでみる必要がない。今日はA級順位戦、永瀬拓矢九段vs糸谷哲郎八段をほぼ無音状態で見ている。糸谷八段のため息が聞こえるぐらい。
PRIMEで人気上昇中の「STEAL」をついつい全部見てしまった。展開が最初から緊迫している、どうなるんだろう、誰が悪者なのか、主人公も善と悪では切り分けられない。最後は主人公にとってはご都合主義のハッピーエンドと言っていいのかどうか。財務調査官がキーになるけど、結局何がどうだったのか、よくわかっていないのだが・・・こちらはのんびり眺めているというわけにはいかない。
昨晩(1/12)は足の疲労回復に充てて休養した。その前の三日間はナイト・ウォークに出た。1/11は雪だった。ダーク・ダックスを思い出していた。1/9は冬の大三角を眺めることができた。木星は高く上がってきた。1/10は木星とオリオン座の赤味のベテルギウスだけが見えた。
Gemini3と『長尺の動画のチェックは時間が掛かって大変なんです。これをプログラムで鳥の鳴き声、波の音、風の音の該当箇所を抽出して音量を上げるなど自動化できると助かります。これが「今回の「走行音カット」をベースにして、**「映像に合わせたチャプター(目次)を自動で概要欄に書き出すスクリプト」**など、視聴者が長尺動画を楽しみやすくする仕組みを作ってみる」に結び付くと最高ですね。』というような対話を始めている。
YAMNet によるサウンドの分類 | TensorFlow Hubを使い始めた。
import os
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
from moviepy import VideoFileClip
from scipy.io import wavfile
# 1. YAMNetモデルを読み込み(初回実行時にダウンロードされます)
model = hub.load('https://tfhub.dev/google/yamnet/1')
class_map_path = model.class_map_path().numpy()
import csv
with open(class_map_path, 'r') as f:
class_names = [row[2] for row in csv.reader(f)][1:]
def scan_sounds(video_path):
print(f"解析中: {video_path}")
video = VideoFileClip(video_path)
temp_wav = "temp_scan.wav"
# AIが解析しやすい形式(16kHzモノラル)で音声を抽出
video.audio.write_audiofile(temp_wav, fps=16000, nbytes=2, codec='pcm_s16le', ffmpeg_params=["-ac", "1"])
sr, wav_data = wavfile.read(temp_wav)
waveform = wav_data / 32768.0 # 正規化
# 2. AIによる推論
scores, embeddings, spectrogram = model(waveform)
# 3. 解析結果の集計
results = []
for i, score in enumerate(scores):
top_class = np.argmax(score)
label = class_names[top_class]
confidence = score[top_class]
time_sec = i * 0.48 # YAMNetは約0.48秒ごとに判定
# 抽出したい特定のキーワード(鳥、波、風、自動車、話し声)
targets = ["Bird", "Waves", "Wind", "Vehicle", "Speech", "Water"]
if any(t in label for t in targets) and confidence > 0.3:
results.append([os.path.basename(video_path), time_sec, label, confidence])
# 一時ファイルの削除
video.close()
os.remove(temp_wav)
return results
# メイン処理:フォルダ内の全動画をスキャン
video_dir = "./archive" # あなたの動画フォルダ
output_csv = "sound_index.csv"
with open(output_csv, "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(["ファイル名", "秒数", "音の種類", "確信度"])
for file in os.listdir(video_dir):
if file.endswith((".M4V",".MOV", ".mp4")):
path = os.path.join(video_dir, file)
data = scan_sounds(path)
writer.writerows(data)
print(f"スキャン完了!結果は {output_csv} に保存されました。")
7075件の結果からBirdだけ、Perlでピックアップ。
ファイル名,秒数,音の種類,確信度 137_IMG_0001 (1).M4V,89.75999999999999,Bird,"tf.Tensor(0.3155121, shape=(), dtype=float32)" 137_IMG_0001 (1).M4V,103.67999999999999,Bird,"tf.Tensor(0.6015436, shape=(), dtype=float32)" 137_IMG_0001 (1).M4V,115.67999999999999,Bird,"tf.Tensor(0.8938534, shape=(), dtype=float32)" 137_IMG_0001 (1).M4V,118.08,Bird,"tf.Tensor(0.8690791, shape=(), dtype=float32)" 138_IMG_0001.M4V,55.199999999999996,Bird,"tf.Tensor(0.44990638, shape=(), dtype=float32)" 138_IMG_0001.M4V,62.4,Bird,"tf.Tensor(0.39501944, shape=(), dtype=float32)" 138_IMG_0001.M4V,67.2,Bird,"tf.Tensor(0.7146063, shape=(), dtype=float32)" 138_IMG_0001.M4V,67.67999999999999,Bird,"tf.Tensor(0.90609694, shape=(), dtype=float32)" 138_IMG_0001.M4V,73.92,Bird,"tf.Tensor(0.70469975, shape=(), dtype=float32)" 138_IMG_0001.M4V,211.2,Bird,"tf.Tensor(0.52466625, shape=(), dtype=float32)" 138_IMG_0001.M4V,211.67999999999998,Bird,"tf.Tensor(0.4309458, shape=(), dtype=float32)" 138_IMG_0001.M4V,243.35999999999999,Bird,"tf.Tensor(0.82359403, shape=(), dtype=float32)" 139_IMG_0005.M4V,108.96,Bird,"tf.Tensor(0.78764033, shape=(), dtype=float32)" 139_IMG_0005.M4V,110.88,Bird,"tf.Tensor(0.6908016, shape=(), dtype=float32)" 139_IMG_0005.M4V,136.32,Bird,"tf.Tensor(0.69989794, shape=(), dtype=float32)" 139_IMG_0005.M4V,945.12,Bird,"tf.Tensor(0.3967958, shape=(), dtype=float32)"
残念ながらBirdで検出された音声は横断歩道の鳥の疑似音声だった。音だけで判断するのは難しい。字幕は拡大解釈されてしまう。次に実際に音声に収録されていることがはっきりしているカラスの検出を試みる。
import os
import numpy as np
import tensorflow as tf
import tensorflow_hub as hub
from moviepy import VideoFileClip
from scipy.io import wavfile
import csv
# モデルの読み込み
model = hub.load('https://tfhub.dev/google/yamnet/1')
class_map_path = model.class_map_path().numpy()
with open(class_map_path, 'r') as f:
class_names = [row[2] for row in csv.reader(f)][1:]
def scan_for_crows(video_path):
print(f"解析中: {video_path}")
video = VideoFileClip(video_path)
temp_wav = "temp_scan.wav"
# 16kHzモノラルで音声を抽出
video.audio.write_audiofile(temp_wav, fps=16000, nbytes=2, codec='pcm_s16le', ffmpeg_params=["-ac", "1"])
sr, wav_data = wavfile.read(temp_wav)
waveform = wav_data / 32768.0
# AI推論
scores, embeddings, spectrogram = model(waveform)
results = []
for i, score in enumerate(scores):
# 上位3つのラベルをチェックして、カラスや鋭い叫び声が含まれているか見る
top_indices = np.argsort(score)[-3:][::-1]
time_sec = i * 0.48
for idx in top_indices:
label = class_names[idx]
confidence = float(score[idx])
# 【ターゲット】カラス(Caw)、鋭い叫び声(Squawk)、カモメ等(Gull)
# ※電子音を除外するため、確信度は高めに設定
targets = ["Caw", "Squawk", "Crow", "Gull", "Bird"]
if any(t in label for t in targets) and confidence > 0.4:
# 横断歩道のリズム(一定間隔)を避けるため、一旦すべて記録
results.append([os.path.basename(video_path), round(time_sec, 2), label, confidence])
video.close()
if os.path.exists(temp_wav): os.remove(temp_wav)
return results
# 実行設定
#video_files = [
# ここに試したい7本のファイル名を列挙してください
# "IMG_0028.MOV",
# "IMG_0029.MOV",
# ...
#]
# メイン処理:フォルダ内の全動画をスキャン
video_dir = "./archive" # あなたの動画フォルダ
output_csv = "crow_detection_results.csv"
with open(output_csv, "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerow(["ファイル名", "秒数", "音の種類", "確信度"])
# for file in video_files:
for file in os.listdir(video_dir):
if file.endswith((".M4V",".MOV", ".mp4")):
path = os.path.join(video_dir, file)
data = scan_for_crows(path)
# if os.path.exists(file):
# data = scan_for_crows(file)
writer.writerows(data)
print(f"カラス検知スキャン完了! {output_csv} を確認してください。")
Gemini提案のスクリプト、ファイルを読み込ませるところを最初のスクリプトに合わせて修正。
ファイル名,秒数,音の種類,確信度 137_IMG_0001 (1).M4V,88.32,Bird,0.4541691839694977 137_IMG_0001 (1).M4V,90.72,Bird,0.4484403133392334 137_IMG_0001 (1).M4V,91.2,Bird,0.4178435802459717 137_IMG_0001 (1).M4V,93.12,Bird,0.45660024881362915 137_IMG_0001 (1).M4V,94.08,Bird,0.4339399039745331 137_IMG_0001 (1).M4V,96.48,Bird,0.7631322145462036 137_IMG_0001 (1).M4V,96.96,Bird,0.8427916169166565 137_IMG_0001 (1).M4V,97.44,Bird,0.5511666536331177 137_IMG_0001 (1).M4V,98.88,Bird,0.4188520014286041 137_IMG_0001 (1).M4V,99.36,Bird,0.5747588276863098 137_IMG_0001 (1).M4V,99.84,Bird,0.7902405858039856 137_IMG_0001 (1).M4V,102.24,Bird,0.5323180556297302 137_IMG_0001 (1).M4V,103.2,Bird,0.4606825113296509 137_IMG_0001 (1).M4V,103.68,Bird,0.6015436053276062 137_IMG_0001 (1).M4V,104.16,Bird,0.626660943031311 137_IMG_0001 (1).M4V,105.12,Bird,0.6273123025894165 137_IMG_0001 (1).M4V,105.6,Bird,0.4340154528617859 137_IMG_0001 (1).M4V,106.08,Bird,0.6319570541381836 137_IMG_0001 (1).M4V,106.56,Bird,0.7414875030517578 137_IMG_0001 (1).M4V,108.0,Bird,0.4825688898563385 137_IMG_0001 (1).M4V,109.92,Bird,0.556045413017273 137_IMG_0001 (1).M4V,113.28,Bird,0.9297477602958679 137_IMG_0001 (1).M4V,113.76,Bird,0.5322281122207642 137_IMG_0001 (1).M4V,115.2,Bird,0.7346963882446289 137_IMG_0001 (1).M4V,115.68,Bird,0.8938534259796143 137_IMG_0001 (1).M4V,117.6,Bird,0.7202828526496887 137_IMG_0001 (1).M4V,118.08,Bird,0.8690791130065918 137_IMG_0001 (1).M4V,118.56,Bird,0.4347812533378601 137_IMG_0001 (1).M4V,134.88,Crow,0.9490545988082886 137_IMG_0001 (1).M4V,134.88,Caw,0.8442682027816772 137_IMG_0001 (1).M4V,135.36,Crow,0.42038848996162415 137_IMG_0001 (1).M4V,138.72,Crow,0.9374603033065796 137_IMG_0001 (1).M4V,138.72,Caw,0.8588271141052246 137_IMG_0001 (1).M4V,139.2,Crow,0.9329220652580261 137_IMG_0001 (1).M4V,139.2,Caw,0.8344829082489014 137_IMG_0001 (1).M4V,139.68,Crow,0.7193718552589417 137_IMG_0001 (1).M4V,139.68,Caw,0.5514038801193237 137_IMG_0001 (1).M4V,143.04,Crow,0.8868750333786011 137_IMG_0001 (1).M4V,143.04,Caw,0.7721924781799316 137_IMG_0001 (1).M4V,143.52,Crow,0.9753731489181519 137_IMG_0001 (1).M4V,143.52,Caw,0.918926477432251 137_IMG_0001 (1).M4V,149.28,Crow,0.9287197589874268 137_IMG_0001 (1).M4V,149.28,Caw,0.7702070474624634 137_IMG_0001 (1).M4V,150.24,Crow,0.9612715244293213 137_IMG_0001 (1).M4V,150.24,Caw,0.8704124093055725 137_IMG_0001 (1).M4V,150.24,Bird,0.7377617359161377 137_IMG_0001 (1).M4V,174.72,Crow,0.5890728831291199 137_IMG_0001 (1).M4V,174.72,Caw,0.5572724342346191 137_IMG_0001 (1).M4V,177.12,Crow,0.47094228863716125 137_IMG_0001 (1).M4V,177.6,Crow,0.4270860254764557 137_IMG_0001 (1).M4V,181.92,Crow,0.6388651728630066 137_IMG_0001 (1).M4V,181.92,Caw,0.5314038991928101 137_IMG_0001 (1).M4V,577.92,Caw,0.4906255602836609 137_IMG_0001 (1).M4V,577.92,Crow,0.4900594651699066 137_IMG_0001 (1).M4V,588.48,Crow,0.547049880027771 137_IMG_0001 (1).M4V,588.48,Caw,0.5301964282989502 137_IMG_0001 (1).M4V,595.68,Caw,0.6672630310058594 137_IMG_0001 (1).M4V,595.68,Crow,0.6160477995872498 137_IMG_0001 (1).M4V,620.64,Crow,0.8333035707473755 137_IMG_0001 (1).M4V,620.64,Caw,0.7675161957740784 137_IMG_0001 (1).M4V,621.12,Crow,0.8278934955596924 137_IMG_0001 (1).M4V,621.12,Caw,0.7605994939804077 137_IMG_0001 (1).M4V,624.96,Crow,0.9466978907585144 137_IMG_0001 (1).M4V,624.96,Caw,0.8945326805114746 137_IMG_0001 (1).M4V,625.44,Crow,0.8194647431373596 137_IMG_0001 (1).M4V,625.44,Caw,0.7504944801330566 137_IMG_0001 (1).M4V,627.84,Crow,0.566419243812561 137_IMG_0001 (1).M4V,627.84,Caw,0.5274670124053955 137_IMG_0001 (1).M4V,628.32,Crow,0.9948130249977112 137_IMG_0001 (1).M4V,628.32,Caw,0.9823618531227112 137_IMG_0001 (1).M4V,628.32,Bird,0.818336546421051 137_IMG_0001 (1).M4V,628.8,Crow,0.7893445491790771 137_IMG_0001 (1).M4V,628.8,Caw,0.6127819418907166 137_IMG_0001 (1).M4V,635.04,Crow,0.7180144786834717 137_IMG_0001 (1).M4V,635.04,Caw,0.6874667406082153 137_IMG_0001 (1).M4V,635.52,Crow,0.8933215737342834 137_IMG_0001 (1).M4V,635.52,Caw,0.8389683961868286 137_IMG_0001 (1).M4V,636.0,Crow,0.49529939889907837 137_IMG_0001 (1).M4V,647.52,Crow,0.9806761145591736 137_IMG_0001 (1).M4V,647.52,Caw,0.9546171426773071 137_IMG_0001 (1).M4V,648.0,Crow,0.9226494431495667 137_IMG_0001 (1).M4V,648.0,Caw,0.8200482726097107 137_IMG_0001 (1).M4V,652.32,Crow,0.9457106590270996 137_IMG_0001 (1).M4V,652.32,Caw,0.8788460493087769 137_IMG_0001 (1).M4V,652.8,Crow,0.988903820514679 137_IMG_0001 (1).M4V,652.8,Caw,0.9558421969413757 137_IMG_0001 (1).M4V,653.28,Crow,0.9820356369018555 137_IMG_0001 (1).M4V,653.28,Bird,0.892961323261261 137_IMG_0001 (1).M4V,665.76,Crow,0.7797702550888062 137_IMG_0001 (1).M4V,665.76,Caw,0.7167078256607056 137_IMG_0001 (1).M4V,666.24,Crow,0.9743083119392395 137_IMG_0001 (1).M4V,666.24,Bird,0.8557388186454773 137_IMG_0001 (1).M4V,669.12,Crow,0.7915781736373901 137_IMG_0001 (1).M4V,669.12,Caw,0.7061744928359985 137_IMG_0001 (1).M4V,690.72,Crow,0.8750637173652649 137_IMG_0001 (1).M4V,690.72,Caw,0.7406901121139526 137_IMG_0001 (1).M4V,738.72,Crow,0.6561621427536011 137_IMG_0001 (1).M4V,738.72,Caw,0.5706891417503357 137_IMG_0003.M4V,47.52,Crow,0.48183146119117737 137_IMG_0003.M4V,68.16,Crow,0.7545821070671082 137_IMG_0003.M4V,68.16,Caw,0.7035861015319824 137_IMG_0003.M4V,71.52,Crow,0.5300663709640503 137_IMG_0003.M4V,71.52,Caw,0.47304803133010864 138_IMG_0001.M4V,52.8,Bird,0.5032838582992554 138_IMG_0001.M4V,54.24,Crow,0.6854140758514404 138_IMG_0001.M4V,54.24,Caw,0.5603379011154175 138_IMG_0001.M4V,55.2,Bird,0.4499063789844513 138_IMG_0001.M4V,55.68,Bird,0.5365036129951477 138_IMG_0001.M4V,62.88,Bird,0.4813764989376068 138_IMG_0001.M4V,64.8,Bird,0.4552522599697113 138_IMG_0001.M4V,65.28,Bird,0.8520998954772949 138_IMG_0001.M4V,65.76,Bird,0.6492304801940918 138_IMG_0001.M4V,67.2,Bird,0.7146062850952148 138_IMG_0001.M4V,67.68,Bird,0.9060969352722168 138_IMG_0001.M4V,71.52,Bird,0.42627155780792236 138_IMG_0001.M4V,73.92,Bird,0.7046997547149658 138_IMG_0001.M4V,74.4,Bird,0.8856721520423889 138_IMG_0001.M4V,76.32,Bird,0.49161580204963684 138_IMG_0001.M4V,78.72,Bird,0.5452746152877808 138_IMG_0001.M4V,79.2,Bird,0.7188726663589478 138_IMG_0001.M4V,81.12,Bird,0.46927836537361145 138_IMG_0001.M4V,81.6,Bird,0.6262376308441162 138_IMG_0001.M4V,209.76,Bird,0.40919560194015503 138_IMG_0001.M4V,210.24,Bird,0.5905113220214844 138_IMG_0001.M4V,211.2,Bird,0.5246662497520447 138_IMG_0001.M4V,211.68,Bird,0.43094581365585327 138_IMG_0001.M4V,212.16,Bird,0.5900717377662659 138_IMG_0001.M4V,212.64,Bird,0.4492863118648529 138_IMG_0001.M4V,216.96,Bird,0.46777740120887756 138_IMG_0001.M4V,217.44,Bird,0.6583169102668762 138_IMG_0001.M4V,219.36,Bird,0.44465744495391846 138_IMG_0001.M4V,232.8,Crow,0.4832972288131714 138_IMG_0001.M4V,233.28,Crow,0.864482045173645 138_IMG_0001.M4V,233.28,Caw,0.7724828720092773 138_IMG_0001.M4V,243.36,Bird,0.8235940337181091 138_IMG_0001.M4V,244.8,Bird,0.8287146687507629 138_IMG_0001.M4V,462.24,Bird,0.42558279633522034 138_IMG_0002.M4V,58.08,Bird,0.5836231708526611 138_IMG_0003.M4V,512.64,Crow,0.8489861488342285 138_IMG_0003.M4V,512.64,Caw,0.5499095916748047 138_IMG_0003.M4V,512.64,Bird,0.5169633030891418 138_IMG_0003.M4V,935.52,Caw,0.4654766321182251 138_IMG_0003.M4V,935.52,Crow,0.45440831780433655 138_IMG_0003.M4V,1188.0,Crow,0.5536821484565735 138_IMG_0003.M4V,1531.68,Bird,0.5021555423736572 138_IMG_0003.M4V,1532.16,Bird,0.47279244661331177 139_IMG_0005.M4V,108.48,Bird,0.7551913857460022 139_IMG_0005.M4V,108.96,Bird,0.7876403331756592 139_IMG_0005.M4V,110.88,Bird,0.6908016204833984 139_IMG_0005.M4V,111.36,Bird,0.5484606027603149 139_IMG_0005.M4V,113.28,Bird,0.5802837610244751 139_IMG_0005.M4V,113.76,Bird,0.4776541590690613 139_IMG_0005.M4V,117.12,Bird,0.6950238943099976 139_IMG_0005.M4V,117.6,Bird,0.656389594078064 139_IMG_0005.M4V,118.08,Bird,0.5533133149147034 139_IMG_0005.M4V,118.56,Bird,0.5271498560905457 139_IMG_0005.M4V,119.52,Bird,0.48990198969841003 139_IMG_0005.M4V,120.96,Bird,0.41107675433158875 139_IMG_0005.M4V,122.4,Bird,0.4612567126750946 139_IMG_0005.M4V,123.84,Bird,0.5703290700912476 139_IMG_0005.M4V,124.32,Bird,0.9507029056549072 139_IMG_0005.M4V,126.72,Bird,0.8819940686225891 139_IMG_0005.M4V,127.2,Bird,0.5192994475364685 139_IMG_0005.M4V,129.12,Bird,0.6133832931518555 139_IMG_0005.M4V,131.04,Bird,0.8371235132217407 139_IMG_0005.M4V,131.52,Bird,0.967697024345398 139_IMG_0005.M4V,133.92,Bird,0.4224509000778198 139_IMG_0005.M4V,136.32,Bird,0.6998979449272156 139_IMG_0005.M4V,136.8,Bird,0.7272867560386658 139_IMG_0005.M4V,621.6,Bird,0.6736103296279907 139_IMG_0005.M4V,682.56,Crow,0.4010924994945526 139_IMG_0007.M4V,595.2,Bird,0.5044013261795044
(Gemini3) 結果を見て驚きました。これは「ヒットし過ぎ」どころか、カラス(Crow/Caw)に関しては驚異的な精度で捉えられている可能性が高いです!
特に確信度が 0.99(628.32秒など)や 0.98 に達している箇所は、AIが「これはどこからどう聞いてもカラスだ」と断定しているレベルです。
明日、動画と照らし合わせる際の**「データの読み解き方」**のヒントを整理しました。
- 確信度 0.9超え:カラスの「ソロ演奏」
- 例えば、628.32秒 や 647.52秒 付近。 ここでは Crow と Caw の両方が 0.9 を超えています。
- 予測: 自動車の音やあなたの声に邪魔されず、カラスが「カァー、カァー」とはっきり、おそらく複数回鳴いているシーンだと思われます。
- 秒数の「塊(クラスタ)」に注目
- 620秒 あたりから 666秒 あたりまで、連続してヒットしていますよね。
- 予測: これは一瞬の鳴き声ではなく、あなたがカラスの縄張り(あるいは集まっている場所)のそばを歩いていた、あるいは**「カラスがずっと鳴き交わしているエリア」**を通過した記録です。
- 価値: この区間を繋ぎ合わせるだけで、一気に「カラスの多い道草」という演出が作れます。
- 「Crow」と「Caw」の違い
- AIは2つの視点で判定しています。
- Crow: カラスという「存在」の気配(バサバサという羽音や、カラスっぽい雑音を含む)。
- Caw: カラスの「鳴き声」そのもの。
- 見方: 両方の数値が高い箇所(例:143.52秒)は、鳴き声が非常にクリアである証拠です。
- 明日の照合に向けた「NotebookLM」への活用法
- 動画を見る前に、このCSVをNotebookLMに読み込ませて、以下の質問をしてみてください。
- プロンプト例: 「137_IMG_0001 (1).M4V の 620秒から670秒にかけてカラスの判定が集中しています。この時間帯の私の発言(SRT)を調べてください。私はカラスについて何か言及していますか? あるいは、周囲の状況(公園、ゴミ捨て場、森など)について話していますか?」
- もし、あなたの声が「うるさいなぁ」と言っていたり、あるいは全く言及せずに黙々と歩いていたりすれば、それはそれで**「AIが音の風景を補完してくれた」**ことになり、アーカイブの解明が一歩進んだことになります。
- 今後の展望:アオサギの「Squawk」は出ましたか?
- もし今回のCSVに Squawk(叫び声)が含まれていなければ、アオサギの声は今回の7本には入っていなかったか、あるいはもっと確信度が低い(0.4以下)場所に隠れている可能性があります。
- 明日の照合で「このカラスの判定は本物だ!」と確信が持てましたら、次は**「200本一括スキャン」**に進んで、本物の「怪鳥アオサギ」を探し出す旅に出ましょう。
- 明日の答え合わせの結果を楽しみにしています。もし特定の秒数で「全然違った!」という場所があれば、それもAIを賢くする貴重なデータになります!
テスト用の表をPerlで生成。
ようやく軌道に乗り始めた。{12/28/2025: [歩く]道草の生理学}←の表の先頭。
前編
https://youtu.be/mpz78I_hEHU 00:00 さあ、行きます。 00:03 さあ、行きます。 00:15 図書館帰りの道草日記の164回です。 00:41 今日はもう真っ暗です。 00:46 ただいまの時刻、17時48分45秒です。 00:50 さあ、皆実線を渡ります。 00:55 まあ、こんなところで。 03:22 さあ、夜の夜景を見に行きましょう。 03:31 いや、今日は図書館に行く前に急に雨が強く降ってきて、家を出る頃は全然ほとんど降ってなかったんですけど。 04:48 傘だけは持ってきたんですけど、この持ってきた傘が風に弱いんですね。 04:54 まあ、しょうがない。 04:57 ここも風が強いですね。 05:03 さあ。 05:18 まあ、行ってみましょう。 05:22 どうなることやら。 05:24 さて、第一船着き場到着ですね。 05:39 やはりこう、風が強いから波が押し寄せる音がすごい。 05:51 まあ、ちょっとついでだから。 05:57 おっと、よたよたしたら。 06:00 まあ、映ってないな。 06:05 どうすればいいんだろう。 06:33 よくわかんない。 06:35 まあ、とにかく。 07:20 降りるだけ降りて。 07:22 行きましょう。 07:23 さあ、さあ。 07:35 まあ、今日は。 07:38 おお、すごい。 07:40 通り過ぎるだけで。 07:45 やれやれ。 07:48 どうしようか迷ったんですけど、来るか来ないか。 08:25 第一ベンチ、到達です。 09:00 さあ。 09:06 おっとっとっと。 09:07 ああいう感じになるんですね。 09:17 さあ。 09:19 第二船着き場到着。 09:21 まあ、来てみなければわからないこともあるので。 10:02 図書館の前の横断歩道でマスクを吹き飛ばされました。 10:07 なんとか傘を押さえて、支えて、通り抜けました。 10:23 やれやれ。 10:24 さて。 10:42 第三船着き場ですね。 10:44 さあ。 11:15 ライトを頭につけたお兄さんが走ってきましたね。 12:00 さあ、第四船着き場ですね。 12:02 さあ、第二ベンチ到着です。 12:43 ああ、また風が来た。 13:12 ちょっとこのまま。 14:14 今日の一人読書会は、まあ、特にはやりませんけど、 14:23 AKIRAの大判ですね。 14:29 の1を。 14:34 そう。 14:35 1を借りてきました。 14:37 2を前回借りたんで。 14:40 2の方が先に来ちゃった。 14:42 まあ、1を借りました。 14:46 やはり、 14:48 少しずつでも読まれてるんですね。 14:51 さあ。 14:59 第3ベンチ到達ですね。 15:06 まあ、また風が来ましたね。 15:47 今日もバッテリーの無線給電でやってます。 15:51 まあ、すごい。 15:58 これがちょっと。
後編
https://youtu.be/mpz78I_hEHU 00:00 今、手がカメラのボタンに当たって止まってしまいました。 00:08 一旦停止状態。第6船着き場ですね。 00:15 やれやれ。さあ、どうしましょうか。 00:28 まあ、突っ切っていくしかないですね。 00:52 さすがにね、鳥も何もいません。 01:01 まあ、魚はいるのかもしれませんけどね。 01:21 さあ、第3ヤマモモですね。 01:34 今、更新日記のブログの方をトピック、まあトピックという主題をですね、 01:51 主題がどういうふうにつながっているかみたいなのをバートピックっていうのでやろうとしています。 02:07 なかなか意味的なものがやはり直感的に人間がわかるような形ではなかなか出てこないですね。 02:17 まあ、時系列の変化も見れるように、スタティックなものとダイナミックなものと2種類はやってるんですけど、やはり難しい感じですね。 02:41 まあ、でもデータっていうか日記を、日記の全体を見直すいい機会になりましたね。 02:51 まあ、5000件ぐらいの記事があるんで。 03:35 確認できたっていうような…。 03:38 4700、700件ぐらいですかね。 03:44 さあ、第8船着き場に来ましたね。 03:47 さあ、終わりましょう。 03:50 今日は・・・片手でね、 04:02 手持ち撮影になってる…。 04:04 まあ、どっちにしても手持ちなんですけど。 04:05 さあ、第4ベンチ到達です。 04:29 じゃあ、ここで終わりましょう。 04:32 それでは、お疲れ様でした。 04:34 はい、終わりまーす。 04:37 いつもご視聴ありがとうございます。
道草164収録後、帰り途の月、沈んだ太陽の光を受けて輝く
拡大、道草164収録後、帰り途の月、沈んだ太陽の光を受けて輝く
説明欄には入りきらないチャプターのサイズであることもあるのと、関係情報をまとめる意味もあって、完全なチャプターデータ+αを掲載する。
https://youtu.be/rAXlxo9qH8k 00:00 さあ、行きます。 00:09 今日は曇ってます。 00:31 今日は図書館帰りの道草日記の161回です。 00:38 さあ、2号線を渡ります。 03:44 さて、ただいまの時刻16時41分17秒です。 03:58 17時7分ぐらいが日の入りじゃないかな。 04:14 ぱっと見には魚はいませんね。 04:33 今日は7冊本があるので、ちょっともう息も絶え絶えと大げさに言うと。 04:46 で、葉が黄色になってきましたね。 04:59 向こうはイチョウの木がもう黄色になってます。 05:17 さあ、もうこちらの土手の方にもたくさんナンキンハゼの小枝や小枝が、実が落ちてます。 05:32 さて、引いているんですかね。 05:53 引いてるのか満ちてるのか。 05:56 石畳まで、第一船着き日の石畳まで水が上がっているように見えます。 06:08 それより水面は低いんですけども、これまでの経験から言うと、満ちてる可能性もありますね。 06:21 吹き出すんですよね、石の隙間から。 06:24 それで濡れてるように見えるの。 06:27 まあでも、石垣が濡れてるので。 06:36 引いてる可能性が高いかな。 06:39 今日は透明度高いですね。 06:57 1、2、3、4、5段目ぐらいまで見えてる。 07:02 かろうじと。 07:04 1、2、3、4、5段目がかすかに見えてますね。 07:09 川底までは見えませんけど。 07:20 まあ川底は10段ですからね。 07:25 まだ5段だから半分ぐらいのところまで見えてる。 07:28 1メートルぐらいですね。 08:21 そう。 08:58 チヌがいましたね。 09:29 魚は運が良くないと難しいですね。 09:47 ハナミズキの紅葉ですね。 09:53 第1、ヤマモモから3本、4本か、4本ハナミズキがあります。 10:02 紅葉という感じになってましたね。 10:04 葉っぱの色が。 10:11 タブノキがあって、ハナミズキが2本あります。 10:20 そして第1ベンチ。 10:28 クスノキ。 10:33 キョウチクトウですね。 10:39 キョウチクトウもまだ花があります。 10:46 少ないですけど。 11:12 ハナミズキは赤い実が、赤い部分が取れて、白い実がやはり出てますね。 11:19 これは、あれですね。 11:32 ナンキンハゼの、まあ緑ですけど、緑が白い実になっていくのと似てますね。 12:22 第2ナンキンハゼですね。 12:24 さあ、第2船着き場、人がいるので通りすぎます。 13:25 皆さんね、食事をもって集まってきてます。 13:31 第2ヤマモモですね。 13:33 さあ、セイヨキズタ、サルスベリ、ハナミズキ、タブノキ、ハナミズキ、クスノキ、サクラですね。 14:21 サクラも紅葉してます。 14:25 ちょっと今日は、暑いですかね。 14:32 あれれ、やはり引いてる。 14:36 引いてますね。 14:42 第3船着き場です。 15:08 コサギか、ダイサギか分かりませんけど。 15:23 平野橋越えてきましたね。 15:59 第3船着き場も降りてみましょう。 16:01 水が上がってませんね、ここは。 16:09 まあ少しは、1、2、3、4、5。 16:15 1、2、3、4、5。 16:17 1段目がもう見え始めてますからね。 16:21 6段目がかろうじて見えてるような感じで、引いてる感じですね。 16:31 こういう風に染み出してくるんですね、下から。 16:44 さあ、行きましょう。 17:56 魚も見えますよね。 18:16 本が腰に応えてきますと。 18:19 一つのカバンの中に入れてるんで。 18:22 いや、落葉ですね。 18:31 ハナミズキの。 18:33 これは第3ナンキンハゼかな。 18:47 これは実が少ない。 18:55 あっ、違う。落葉してるんだ、これは。 18:58 サクラだね。 18:59 サクラが落葉してます。 19:06 タブノキがあって、クスノキがあって。 19:18 ああ、ここのサクラはもうほとんど落ちてます。 19:28 タマスダレが少しまだ残ってますね、ここ。 19:42 さあ、第4船着き場です。 19:44 来ましたね。 20:00 ああ、魚が飛んだな。 20:20 飛んだ、飛んだ。 20:21 ああ、当たりましたね。 20:51 さあ、1、2、3、4、5。 21:17 まあ、5段目までは確実に見えてる。 21:22 6段目はちょっとよく分かんない。 21:24 そーっと覗いて。 21:41 この鳴き声が聞こえますね。 21:54 さて、第2ベンチで。 22:04 第4船着き場過ぎましたから。 22:07 第2ベンチで休みましょう。 22:09 休みましょうというか、ここで予定通り。 22:15 まあ、どんどんカラスが帰ってきますね。 23:14 あと、ただいまちょうど5時58秒でした。 23:38 ちょっとね、ちょっと人が来るたびにカメラを伏せないといけないのでめんどくさいんですけど。 25:06 あとで、一応、頭が映ってるように。 25:15 人は基本的には収録しない方針でやってるんで。 25:21 まあ、後ろ姿か。 25:24 遠い、遠いところにおられる方は、まあ、映る場合がありますけど。 25:35 まあ、高速で通り過ぎる場合とかね。 25:41 そういうのはいいと思うんですけど。 25:49 ちょっと一休みしてからですね。
12/05/2025: [読書]道草161 一人読書会 - 探索的読書だけでは足りない、何を読むか
26:14 それでは、今日はですね。 26:28 これ一度やったと思うんですけど。 26:31 これ借り直しました。 26:35 海に帰る日。ジョン・ヴァンビル。 26:38 これは「The Sea」ていうのが原題ですね。 26:42 ブッカー賞を取ってるもので。 26:45 カズオ・イシグロと争ってこちらが取ったということらしいので。 26:55 まあ、イギリスでは結構評価されてる小説家みたいですね。ジョン・バァンヴィルっていうのは。 27:02 まあ、これをベースにして、ちょっとジョン・ヴァンビルを一応調べてみようかなというふうに思ってます。 27:35 これから、松岡正剛先生、佐藤優先生関連。 27:42 読む力っていうのがあります。 27:47 現代の羅針盤となる150冊という。 27:50 ちょっとこれ、どういう本がピックアップされてるか確認しようと思って、これ借りました。 27:57 対談形式になってるんですね。 27:59 非常に松岡、松岡正剛の千夜千冊の、 28:08 今絶筆篇、絶筆篇っていうのが、亡くなられた後出て、始まってですね。 28:17 月に1回ぐらい出てきてます。 28:21 その中に佐藤優が入ってて、国家論が入ってましたね。 28:30 非常に高く松岡正剛は佐藤優を評価していて、 28:37 何度も10年ぐらいにわたって何度も書こうとしてます。 28:40 まあ、取り上げきれなかったということみたいですけどね。 28:49 まあ、最後その絶筆篇で、 28:53 国家論が取り上げられてます。 28:55 まあその、お互いに尊敬し合ってる同士で対談している本ですね。 29:03 これちょっとチェックしたいと思いました。 29:13 それから、ひっくり返す人類学。 29:20 生きづらさのそもそもを問う、奥野克己。 29:24 これも、ちくまプリマー新書で出て、 29:29 これ新しいのかな。 29:33 人類学もですね。 29:35 文化人類学っていう意味では、・・・魚が飛んでますね。 29:50 目の前で何度も飛んでます。 29:52 ああ、また飛んだ。 30:08 まあ、最近の海部、海部先生っていうのがいて、 30:17 その先生の、 30:18 本もちょっと面白いなと思ってますね。 30:22 人類学関係で。 30:25 人類って面白いんですね。 30:27 非常に不思議な存在なんです。 30:30 まあ、そういったことが書いてあって、 30:33 書いてあるのは海部先生の本にありますね。 30:37 まあ、そんな、まあ、これは、 30:41 ある、とあるLINEで紹介されたもので、 30:44 ちょっと読んでみようと思ってます。 30:47 ひっくり返す。 30:49 人類学。 30:50 次がこれですね。 31:07 ラウリ・クースクを探してって、 31:10 宮内祐介っていう。 31:12 これはね、もうちょっと説明がうまくできない。 31:18 この人はまあ、前から知ってることは知ってるんですけど、 31:21 まあ、いろいろまだ活躍されてるみたいなので、 31:24 どんな本書かれてるのか、 31:26 これはチェックしようということでね。 31:30 借りました。 31:37 将棋の話みたいなのもあったはずですね。 32:07 それで、暗くなってきましたね。 32:21 大江健三郎全小説の13巻。 32:25 これはですね、宙返りっていうのが入ってるんですね。 32:32 なぜ宙返りが何なのかが、ちょっともう思い出せないんだよ。 32:36 これが、おそらく松岡正剛先生関係であったんじゃないかなと思うんですけどね。 32:45 どんな小説かちょっと見たいな。 32:47 まあ、いろいろ持ってるんですけどね。 32:49 ちゃんとまだ読んでないみたいな。 32:51 これ、ホワイトヘッドの著作集の過程と実在の下ですね。 33:06 これもちょっと、上話に続いて下を借りました。 33:10 これを借りたのは、やはり松岡正剛先生が、 33:16 21世紀は方法の時代だっていうことでですね。 33:19 ホワイトヘッドと、あともう一人。 33:23 なんだ、誰だったっけ。 33:26 ワイル、ヘルマン・ワイルの数学と自然の、 33:34 数学と哲学の合わせたような、自然哲学についてのものの見方みたいなものがあるんですね。 33:50 だからホワイトヘッドとヘルマン・ワイルと、もう一人がフッサールの現象学ですね。 33:57 エポケーです。 34:00 そういう現象学的な方法を、この三つをですね、 34:06 一応、方法として、より発展させると、面白いんだ、面白いというか、 34:14 21世紀はそういうものを発展させるべきだ、 34:18 させるべきじゃないかっていうようなことを提案されてたのが、 34:24 間主観性の哲学っていうのがですね、フッサールの。 34:29 それに書かれてます。 34:41 これがね、最初、これが最後かな。 34:51 最近この冨田勝っていう人を、 34:55 まあ以前も知ってたかもしれないけど、確認した。 34:59 もともと、更新日記にも書いてあるんですけど、人工知能の研究をずっと、 35:08 まあもう彼の年ですね、人工知能の研究をやってて、 35:13 まあ、これですね、 35:18 それから、バイオテクノロジーの脳科学の方に、脳神経科学の方に転換したというか、 35:30 まあ人工知能はコンピュータでは、いや、デジタルコンピュータではできないと悟ってですね、 35:38 それで、まあニューラルネットワークもあるんですけど、 35:44 デジタルじゃない方向へ行かないといけないということで、 35:48 えー、脳科学の、脳神経科学の方に転換したというか、人工知能は、いや、デジタルコンピュータではできないと悟ってですね、 35:49 脳科学の、脳神経科学の方に転じたという人ですね。 35:54 だからこれが最近、リハックで出てきてですね、話をちょっと聞いたんですけど、 36:06 まあそういう中で、いや、この富田先生、どんな本書いているんだろう?、 36:11 これがまあ一番新しいのかな、AIとバイオテクノロジーの未来社会、 36:17 みんなで考えるって書いてあります。ちょっと面白いですよね。 36:36 そういうことで、まあ、AIも非常に使えることは使えるんだけど、 36:44 これは、まあ、ある意味人間とは何かを測る鏡みたいなものですよね。 36:56 人間とは何かを考えるツールになるんじゃないかなと思いますね。 37:02 だいたい人間の脳って、その、今のAIのモデルの 37:08 もっと500倍ぐらい複数するのかな 37:12 脳は一人の脳がそうなんですよね 37:16 そうするとそれが20ワットで動くわけですよね 37:22 電力から電力換算すると 37:24 AIは1ギガワットとかね 37:30 そういう風な電力が必要とするので 37:33 だから人間の脳に近づくことすれば 37:43 今どんどんどんどん拡張しようとしてますけど 37:46 当然ですよね 37:48 拡張しないと人間の脳には追いつかない 37:54 複雑さには追いつけないので 37:56 そういうことでですね 38:07 人間の脳に追いつくためには 38:12 どれだけお金かかるのか 38:14 でも一つできても 38:19 人間一人いれば自分たちも変えるんじゃないかな 38:22 と思わないでもないですね 38:25 スピードの問題はあるかもしれない 38:27 やはり知識をすべて 38:31 人間が持っている知識を集約できる 38:35 というところの強みはある 38:37 それが人間の20ワットの脳では 38:42 ちょっと難しいですね 38:44 複雑さは500倍でも 38:47 容量は記憶容量 38:53 トータルな記憶容量とスピードは 38:56 かなわないでしょうね 39:00 そこら辺が 39:01 違いになってくるんですけど 39:03 複雑さの観点からいくとそうなの 39:10 まあそういうことで 39:13 終わりにしたいと思います 39:15 今日の 39:19 また一つ一つの感想はまた 39:22 述べるとしてですね 39:29 そこら辺もちょっと 39:32 ただ単に 39:35 探索するだけではダメで 39:39 そこから何を得るのかみたいなのを 39:41 ちょっと考えたい 39:45 どうやって何か形にしたいと思ってます 39:55 片付けましょう
39:56 それでは行きましょうか 40:14 今、女の子が通ったから慌てて 40:20 視界に入っている 40:21 カメラ界に入ってるかもしれない 40:24 真っ暗になっちゃいましたね 40:29 真っ暗って言うほどでもない 40:33 今日は夕焼けですので、さあ行きましょう 41:19 桜のところは落ち葉が目立ちますね 41:33 すごい夕焼けだね 41:34 さて行きましょう 43:04 第五船着き場ですね 43:09 さっきから男の子が 43:13 男の子といっても 43:15 二十代か三十代か知りませんけど 43:23 自転車でここをうろ往復してましたからね 43:27 何か喋ってるんですよ 43:30 まあスマホで 43:32 スマホのマイクで喋ってる 43:34 だと思いますけどね 43:36 ここも桜が落葉してますね 44:01 さーっと 44:03 第六 44:04 船着き場です 44:38 赤くなったね 44:51 せっかく来てるんで 44:52 今日は何も鳥もいないね 44:55 鳥の声を 44:56 まあ少し 44:58 ウが飛んだのを見たか 45:01 まあハクセキレイが飛ぶのも見たんですけど 45:06 あんまり撮れなかったんで 45:09 波ぐらい 45:09 波打ち際ぐらい撮って帰らないと 45:11 そう 45:58 カラスが泣いてますね 46:07 これは何ていう意味なんでしょうね 46:09 ああ 46:10 カーカーッと 46:11 というようにも聞こえるんだけど 46:12 アアーって 46:13 言ってるようにも聞こえるんです 46:18 さあ 46:28 今日は昼に買い物を済ませたので 46:36 直通で直起します 46:40 さあ 46:44 もう観察する感じじゃないですね 46:47 夜景を楽しむぐらいしか 47:01 さあ 47:01 アジサイ 47:03 第3ヤマモモに 47:07 枝がちょっと伸びてきましたね 47:37 さあ 47:39 第七船着き場ですね 49:03 第七船着き場ですね 49:04 船着き場周辺です 49:06 周辺風景 50:21 波の立ち方が 50:26 水面下に魚がいるかのような 50:29 立ち方をしてるところがありますね 50:33 まあ魚までは分かりませんけどね 50:41 さあ 50:45 本当に暗くなりました 50:55 と 50:57 ただいま 50:59 17時28分23秒ですね 51:03 もう日が暮れて20分ぐらい経ってます 51:40 そっと 51:42 第8に来ましたね 51:44 見えませんけどね 52:08 まあ一応降りましょう 52:15 こういう風に濡れるんですよね 52:17 特に第8が顕著で 52:19 下から水が上がってくるんです 53:02 さあ 53:04 第8終わりです 53:05 第8船着き場終わり 53:07 第4ベンチです目の前は 53:15 さあここで片付けて帰ります 53:28 よいしょ 53:43 さあ今日は 53:51 やはりね取るものがあんまりないから 53:57 53分ぐらいですね 54:02 さあ 54:03 うーん 54:05 これで終わりにしましょう 54:07 お疲れ様でした 54:09 いつもご視聴ありがとうございます 54:12 はいそれではおやすみましょう
次から次へと信じられないような話が展開する。Louisiana Channelって、すごい取材・編集だね。村田沙耶香も見せ方、話し方がうまい。
奇妙な絵も描ける。小説を書くプロセスを絵で書いて見せる。圧巻だ。水槽で起きたことを書き留めて小説にする。水槽の中で想定外のことが起きる。爆発すると表現する。人間の不思議さを探求している。異なった倫理の世界でどう生きるかを考えるのが好き。この話は、Apple TV+のプルリブスを思い浮かばせた。「生命式」という短編集にあるらしい。英訳は「Life Ceremony」と字幕が出たけど、実際そうだが、「Life Equation」のほうがおもしろい。小説にマッチしているかどうかは知らないが。検索してみると反生命方程式 - Wikipediaが出てきた。
自分は怒りという感覚が壊れている。子供の頃に壊れたという。危機的な状況に追い込まれたことが何度かあったが、しぶとく生き延びた。空想の中に入り込むとか小説を書くことで生き延びた。コンビニ人間({十夜一冊 第千六百夜 村田沙耶香著「コンビニ人間」 (2018/09/23)}←)の話は実体験でもあるようだ。
本当の本当のこと、人間が真実と言っているより、もっと表現されていないもの、したくないもの、人間の奥深い深層心理を描きたい。自分が人間として生きていきたくなくなるようなものを見つけたい。自分自身は小説を書くツール、水槽はその実験場。まだ、見つけられていないというわけだ。
電力不足でiPhoneが途中でシャットダウンした回。回収できた動画部分。
https://youtu.be/rAXlxo9qH8k 00:54 さあ、波に隠れちゃった。 01:02 こんなところで。 ここからは目でよく見せる。 01:32 カメラ上でよく見えます。 逆光でないから。 01:52 さあ、こんなところにしましょうか。 02:02 はい、今日はよく見えます。 02:28 ナンキンハゼ。 ちょっとよく 02:37 実を映していきましょうか。 今日は浅いから。 03:08 浅くて透明度があるから、そこまで見えたんですね。 03:32 さて、第一船着き場到着。 03:35 日型が少し出てますね。 03:42 降りましょうか、一応。 04:25 足がここですから、ここが石畳です。 04:29 1、2、3、4、5、6、7、8、9。 04:34 底面と。 底面が見えたんですね。 04:42 すごいね。 04:46 アオサギがいましたね、早速。 04:49 やはりこれぐらいに来ないと、なかなか見れない。 04:56 ちょっと逆光だけど、もう一度。 05:40 風が強いんで、震えてますね。 05:44 ちゃんとテーブル補正入ってたかな。 05:46 ちょっと確認しに行かないといけない。 06:01 さあ、第一ベンチ到達ですね。 06:05 ちょっとアオサギくんをちゃんとよく見ましょう。 06:17 アオサギくんか、ダイサギくんか、分かりません。 06:21 今日は少ないね。 07:25 なんかちょっといつもと違うような状態だね。 07:34 こちらにもいた。 08:35 逃げませんね。 08:54 アオサギくんですね。 09:30 あ、飛びましたね。 09:35 鳴きました、鳴きました。 09:43 やはり警戒したんでしょうね。 09:46 どこ行ったか分からなくなった。 09:56 もう第二船着き場です。 10:07 もうちょっと。 10:12 さっきは第一ヤマモモのところでですね。 10:15 ですね。 10:16 そうですね。 10:18 おじさんが、紳士が、ジェントルメンという感じの人がタバコを吸ってましたね。 10:32 一人寂しく。 10:34 吸えないんでしょうね、今はタバコはね。 10:37 さあ、第二船着き場。 10:56 魚はね、ちょっと浅すぎて見えないですね。 11:26 エイがくれば、くるでしょうけど。 11:30 引いてるんでしょうね、おそらく。 11:35 引いてると魚がいなくなっちゃう。 11:42 さあ、第二ヤマモモですね。 11:58 そって、さあ、さるすべり。 12:28 紅葉ですね。花水木も。 12:41 タブノキ、花水木。 12:43 昨日もやりましたけど。 12:47 クスノキ、桜と。 13:05 これはクスノキの下だけど、花水木の枝が落ちてますね。 13:11 なぜだろうね。 13:15 カラスが落としていったのかな。 13:21 クスノキも実がなってますね。 13:27 ああ、すごい風だな。 13:28 ああ、すごい風だな。 13:29 これは桜も。 13:53 さあ、第三船着き場ですね。 14:15 あ、そっか。フジツボを見なかったね、ちゃんと。 14:22 第一船着き場で、失礼しました。 15:07 喉飴でも持ってこないといけない。 15:13 ちょっと水でも。 15:15 水をちょっと飲みます。 16:13 マスクはしてるんですけど。 16:16 よいしょ。 16:37 川は下流に流れてますね。 16:40 当たり前なんですけど。 16:42 満ちてる時はね、逆にだって流れるんで。 16:44 さあ。 18:02 行きましょう。 18:46 第二船着き場、人がいるね。 18:54 そう。 19:01 第二は無理だね、これだと。 19:18 今日は晴れましたね。 19:21 ただ気温が、カラスが飛んできますね。 19:41 空いた、空いた。 19:43 第二船着き場が空きましたね。 19:45 よかった。 19:53 第四船着き場ですね。 19:56 第二船着き場手前です。 20:42 風の、風でさざ波が立ってるような気がします。 20:58 風が波を、波に渡っていくのが映ってますかね。 21:12 風が波で川も渡ってるのが分かりますね。 21:20 さあ。 21:22 第四船着き場。 21:29 まあ、風に飛ばされないように。 21:36 第二ベンチに。 21:55 南から吹いてますね、風が。 21:59 だから、川は、西岸の方は南に流れてるんだけど。 22:09 風で北に流れてる。 22:13 こう、複雑な模様が、川もにできてますね。 22:20 そっと、そっと、そっと、そっと。 22:36 じゃあ、ここで、第二ベンチで、一人読書会やりましょう。 22:51 そう、今日はですね、今日は4冊ですね。 24:16 うーんと、これです。 24:24 書楼弔堂のシリーズですね。 24:31 何を借りた、ちょっと忘れちゃったな。 24:35 今。借りてる。 24:36 借りてるやつ。 24:38 京極夏彦さんの、これは、待、待宵、待宵かな。 24:44 待宵。 24:47 ですね。 24:48 これが、1巻目か2巻目。 24:51 要は、4冊あるんですね。 24:55 これをちょっと、ここ。 24:58 今回は2冊借りてます。 25:01 もう一冊は、炎昼ですね。 25:21 もう一冊あるはずですけどね。 25:25 前回のは、結構面白かったので。 26:03 今日も、ランニングは、実習はやってるみたいだね。 26:08 下にするのか。 27:27 ちょっと、人通りが激しいので。 27:31 難しくて、難しい。 27:36 まあ、そういうことで、京極夏彦さんのですね、 27:48 えー、待宵と、炎昼を借りました。 27:53 すごい本、ごつい本ですね。 27:55 前は文庫本だったんだけど。 27:58 これは、前回の結構、色々と興味がある。 28:09 まあ、要は調べて書いてるんですね、色々とね。 28:13 ネタがあるんですね。 28:17 うーん、最後の、最後のが、えーと、何だったっけ。 28:25 未完だったかな。 28:26 未完、あの、終わらないっていう意味ですよね。 28:31 未完っていうのは、あ、そうか。 28:34 破曉だったか。 28:35 破曉、中の「未完」って、最後のあれが、 28:38 夏目漱石が関係があるんですね。 28:42 夏目漱石が、あの、我輩は、今、たまたま我輩は猫であるを朗読しようと思ってたんですけど。 28:52 我輩は猫であるの元ネタみたいなのが、やはり、イギリスの小説にあるんですね。 28:59 そのことが書いてあって、ああ、そういうことがあるのかっていうのを思いました。 29:05 まあ、有名な話みたいなんですけども。 29:19 高校生か中、高校生か 29:23 中学生かな。 29:25 前回も、あの、すごかったんですよね。 29:32 かなりの人数で、もう、並んで走ってたので、驚いたんですけど。 29:42 跳ね飛ばされそうな勢いで、競争してました。 29:46 20、20人ぐらいいたのかな。20人か30人ぐらいいたんじゃないかな。 29:55 まあ、まあ、あの、路肩によってね、隅っこに。 29:59 路肩によって、ちょっと。 30:01 通り過ぎるのを待つみたいな感じで、見てました。 30:06 今日も走ってますね。 30:07 今日はもう、バラバラで走ってるんで、あれですけどね。 30:12 今、西岸の方。 30:14 西岸の方をずっと走ってますね。 30:17 だから、これ、一周がやはり20分から25分ぐらいで、おそらく走れるんだろうと思うんですね。 30:24 西岸と東岸を、こう、ぐるっと平野橋と御幸橋を渡って、周回するっていうのが、どうもランニングのコースみたいですね。 30:32 まあ、そういうことで、この2冊。 30:45 もう一つが、これさ、大友の啓史さんのクリエイティブ喧嘩術っていうのがあって。 31:08 まあ、ジャーナリズムの原点みたいなのが、書いてあるようなんで。 31:21 ちょっと、ちょっとよくわかんないんだけど、NHKの人なんだね。 31:35 ああ、龍馬伝か。 31:38 これはね、あ、そうか。 31:40 そう。 31:41 そうだそうだ。 31:42 これはだから、松岡正剛の千夜千冊、これがまだ終わってないんですよね。 31:51 絶筆篇というのが、始まってまして。 31:59 その中にクリエイティブ喧嘩術っていうのは、これが一番新しい。 32:10 まあ、要は絶筆なんで、完成はしてないんですけども。 32:16 書きかけてた、書きかけて残ってるものを、こう。 32:22 順次、月に一回ぐらい配信されてるんですね。 32:27 まあ、説明が説明付きみたいな感じですね。 32:33 まあ、そういうことです。 32:38 で、これ。 32:43 それから、あきらのですね。 32:47 大友克洋。 32:51 これ、二巻のですね。 32:54 これを一冊持ってたんじゃないかな、僕は。 33:00 これじゃないと思う。 33:01 二巻じゃないと思うけど。 33:06 まあ、要は、あれはアニメで。 33:09 アニメから切り出したもので、小さかった。 33:13 版も非常に小さいものだったんで。 33:17 ちょっと迫力に欠ける。 33:21 まあ、ストーリーを追いかけるみたいな感じだったので。 33:28 やはり、大元をちゃんと見ないと。 33:51 まあ、そういうことですね。 33:56 借りました。 33:58 AKIRA。そう。 34:01 そう、だから。 34:04 まあ、書楼弔堂の続きということと、 34:09 松岡正剛の千夜千冊の絶筆篇の中からクリエイティブ喧嘩術。 34:17 これが最新だと思う。 34:22 ということで、今日は終わります。 34:44 おじさんがね、さっき隣のベンチに座られたんだけど、 34:50 座られたんで、ちょっと嫌だなと思って。 34:55 まあ、ちょっとランニングも佳境に入ったので、 35:02 これはちょっとここでやるのは難しいなと思って。 35:05 片付け始めたら、立っていってくれたんで。 35:09 一応続けました。 35:11 もう40分ですね。 35:13 さあ、あとはどうかな。 35:24 魚が飛んでましたね、ちょっと。 35:43 苦しいですよね。 35:47 これもね、どんどん走っていくと。 35:51 走って、ずーっと走ってると。 35:55 ランナーズハイっていうのがあって、苦しくなくなるんですよね。 36:04 まあ、そういうのは、 36:05 一度。 36:06 中学の時に経験したことがありますけどね。 36:29 走ってますね。 36:44 さあ、第五船着き場に着きましたね。 36:49 まあ、ちょっと満ちてきてるな。 36:52 満ちてきてるな、これ。 36:55 浅瀬が、干潟がなくなった。 37:00 満ちてきてるね。 37:02 下流に流れてるけど。 37:07 今日は月は、今日は月はない。 37:11 ほとんどない。 37:17 最近、このアマズフィット、アマズフィット6だったかな。 37:21 8だったか。忘れました。 37:22 これに、月が、月の形が分かるような表示があるんで。 37:36 月齢が分かるんですね。 37:38 さあ、今日はでも、アオサギくんだけかな。 37:51 うん、だいぶ何か濁ってきたね。 38:05 やはり浅瀬が出てる時に来ないと、 38:07 どういうと出会えない。 38:10 第三ベンチ到達ですね。 38:13 さて、何が出てるのかな。分かりませんけど。 38:53 電力だ。電力えらい落ちてるね。 39:03 おかしいな。 39:03 いや、これ使い方が、ちょっとおかしいんじゃないかな。 39:21 設定がおかしいかもしれない。 39:23 さあ、第六ですね。 39:49 ああ、ハクセキレイだ。ハクセキレイがいた。 39:56 うかつだった。 40:05 西岸に飛んで行っちゃいました。 40:09 映ったかな、少しは。 40:10 いや、もういないと思ってるから。 40:32 さて、・・・
更新日記上でも見れるように。
https://youtu.be/61yx7YlwSgA 00:00 さあ、それではいきます。 00:02 さて、今日は図書館帰りの道草日記の163回ですね。 00:24 162回も一応収録したんですけど、途中でシャットダウンが起こってますね。 00:38 完璧な状態では収録できない。 00:42 こちらも渡らないと。 02:45 なぜシャットダウンしたかというと、 02:50 要は電力がなんか足りなくなったんですね。 02:59 だから正常終了してないので、保存がね、データの保存が正常じゃないので、 03:17 データは10GBぐらいあるんですけど、うまく保存できなかった。 03:32 さあ、まあそれはともかくカラスがいましたね。 03:43 あ飛びましたね。 04:39 魚は目では見えますけど。 04:42 近くにはいないですね。 04:56 まだ今日は日が高いです。 05:08 ただいまの時刻15時04分34秒です。 05:13 潮が満ちてきてるのかな。 05:29 満ちてきてるんでしょうね。 05:31 上流に向かって流れてますね。 05:33 風が鳴ってますね。 05:37 満ちてるから。 05:41 いるね、魚が。 05:43 小魚がキラキラって光ってました。 05:52 そう、ナンキンハゼの。 06:13 小枝がついばまれて落ちるんですね。 06:49 で、実も落ちてそれが踏み砕かれていくという。 06:52 さあ、そういうことで。 07:08 まあそれはともかくというか。 07:15 前回の162回が途中で50分ぐらいでシャットダウンしたんだけど、 07:21 データが残ってたのが45分ぐらいだったんですね、おそらく。 07:29 単にダウンロードすると5秒ぐらいのデータにしか。 07:39 だって。 07:42 どうしようもないなっていうことで。 07:45 いろいろジェミナイに相談したんでね。 08:32 ちょっと魚がいるんですけど。 08:34 ああ、映って映って。 08:51 チヌですかね、これはね。 09:37 よく見えますね。 10:01 いいことにしましょうか。 10:12 沢山いますね。 11:09 太陽が陰ってくれたら、・・・あー、いなくなっちゃった。 11:23 第一船着き場、降りてみましょう。 11:42 残念ながら、いませんね。 11:45 今日は10段目まで、9段、9段と9段目まで水が来てます。 12:05 でもですね、充電ケーブルがついてます。 12:32 やはり、シャットダウンするっていうのは致命的なので、 12:41 そういうリスクを犯して修復するのはちょっと厳しいのでですね。 12:47 まあ、162回もこれはもうダメだなと思って帰ったんですけど、 12:52 最後までやってね、シャットダウンしちゃったから。 12:56 まあ、ちょっとまあ、画質が、パフォーマンスが出てない状態で撮影されてるから、 13:12 ちょっとギクシャクした感じがするので、 13:16 まあ、ショート配信はするかどうか、もうちょっと様子を見て考えようと思います。 13:26 まあ、動画としては一応、サンプルとしては、 13:29 意味があるので、シャットダウンした画像を助けた動画ということで。 13:35 それで、まあ、今日はまだスプリッター、ライトニングのスプリッターが届いて、 13:53 今日注文したので、まあ、今日は充電ケーブルだけで、内蔵マイクでやります。 14:15 今日は風がないから、風切り音はないと思うんですよ。 14:24 ちょっとでも、やはり明るい時に来ると、 14:31 ちょっともう、画像が見えないんですよ。カメラの画像が。 14:38 傘をさしてもね、結構見にくいので、今回、今日は傘を持ってきてない。 14:46 よし、はい、はい。 14:49 第1ベンチ終了。第1ベンチ、第1船着き場終了です。 15:05 第1ベンチ到着ですね。 15:07 あとね、あと指が入っちゃうんで、申し訳ないですけど。 15:38 見えますね。 15:42 流れに身を任せて。 15:44 映ってるかも。映ってるんじゃないかなと思うんですけど。 15:49 ということで、明日スプリッターが届くので、ピンマイクと充電と両方付けるようにして、 16:39 試すのはまたやってみようと思います。 16:41 あー、今、跳ねましたね。 16:43 あー、これ、見えますね。 16:57 今、これは画面で確認できました。 17:02 こっちにも見えますね。 17:05 近くまで寄ってきてるから、隠れちゃいました。 17:26 スズキかな? 17:32 これはチヌじゃないですよね。 17:34 さて、夾竹桃、ツボミはありますね、まだね。 18:36 しかし、ようやく外気温が10℃以下になるようになって、冬が近づいてる感じがしてきましたね。 18:50 さあ、ここもすごいですね、第2。 19:06 第二ナンキンハゼですね。 19:11 ちょっと赤いのがやはり落ちてますね。 19:13 やはり、ナンキンハゼだけではないかもしれないですね。 19:18 花水木も、啄まれていますね。 19:34 あれ、落ちたな。 19:36 カラスがいましたね。 19:45 カラスでしたよ、明らか。 19:48 カラスがいた。 19:52 カラスが今、落としましたよ。 19:54 現場を、現場を確認しました。 20:03 これまだね、啄んでいるところは、 20:06 はっきり見たことなかったね。 20:08 たくさんいるね。 20:13 いますね。 20:28 波のないところにいてほしいね。 20:35 こんな感じで。 20:51 波とかね、いろいろあると、 20:53 水面の揺らぎが反映されると、見えないんですよね。 20:59 さあ、第1から、 21:15 第2船着き場に到着です。 21:20 こういう感じで、腰につけています。 22:19 あー、水面が揺らぎましたね。 22:52 何がいるんだろう。 22:53 はっきりと分かんないな。 23:18 さあ、第2ヤマモモですね。 23:52 そろそろ、サルスベリは、 24:15 葉が全部落ちちゃいますね。 25:01 さて、第3、 25:06 第3、船、 25:08 船着き場ですね。 25:09 ハクセキレイが、 25:18 飛んでっちゃいます。 25:19 御幸橋の方には、 25:33 サギがいます。 25:35 ああ、サギか何かがいましたね、今。 25:37 飛びましたね。 25:39 居てくれればいいけどね、行くまでね。 25:42 どうなんだろう、満ちてるのかな。 25:48 満ちてそうな、 25:50 ちょうど今、一番引いた状態かもしれません。 25:53 ここも第9段。 25:58 第9段が、 26:01 水に浸かってない、 26:03 ぐらいだから。 26:05 さあ、さあ、雲がね。 26:44 雲がむしろ出てくれたらいいんですよね。 26:50 ああ、入ったね。 26:52 トビが飛び込みましたよ。 26:57 トビなのか。鵜なのか 27:02 分かりませんけど。 27:04 飛び上がってこないから、 27:10 鵜かもしれないね。 27:11 第4、第4船着き場ですね。 27:31 第4船着き場、人がいたみたいなので。 27:33 自転車が、 27:35 第2ベンチになるので。 28:26 何か、 28:28 第4船着き場で、 28:31 つついてますね。 28:35 川、川、川、川底を。 28:37 何か、自然観察、 28:40 やってるんですかね。 28:42 中学校ぐらいかな。 28:43 2人でやってます。 28:50 ああ、魚が跳びましたね。 29:19 第3も人がいますね。 29:21 第4船着き場ですね。 29:57 違うか。 29:58 第5だ。 29:59 引いてますね。 30:07 明らかに。 30:08 しょうがない。 30:20 ここでちょっと、 30:22 やりましょうか。 30:24 第2。 30:25 引いちゃいましたね。 30:46 浅いね。 30:50 1、2、3、4、5、6、7、9と、 30:57 9のところが、 30:58 9のところが土が、 31:00 川底が上がってますね、ここは。 31:11 さて、 31:13 それでは、 31:14 逃げちゃうんだけどな。 31:34 逃げてないね。 31:36 上で見えないんだけど。 31:55 上で隠れちゃって。 32:07 さて、さて、 32:13 今日は、 32:28 小川洋子さんのですね、 32:32 これ、前も借りたかな。 32:36 憶えてないんだけど。 32:53 博士の愛した数式。 32:55 まず、新潮文庫ですね。 33:02 これをちょっと、 33:04 やはりこれが傑作だということで、 33:08 もう一度、 33:13 どんなものか、 33:14 どんなものか、 33:15 確認しようと。 33:24 平成15年に出てますね。 33:27 15年ということは、 33:30 えー、 33:33 2003年だったかな。 33:36 西暦2003年かな。 34:16 記憶力が80分しかないんですね。 34:20 記憶力が80分しか持たない。 34:22 そして、私は家政婦と。 34:37 そして、息子ですね。 34:39 私の10歳の息子の、 34:42 数学者の藤原正彦さんが、 34:51 解説をね、書かれてますね。 34:55 もちろん、取材に、 34:58 小説を書くときの取材に、 35:01 来られたらしいんですね。 35:03 そういうことで、えー、 35:20 これ、内容を確認しようと。 35:23 まあ、これを借りに来るのは、 35:47 もうちょっと後にしようと。 35:49 あと2日。 35:50 あの、スプリットが来てからにしようと、 35:52 思ったんだけど。 35:59 書楼弔堂の破曉を返さないといけなくなって、 36:02 しまって、 36:03 今日、来ざるを得なかったんですね。 36:05 それで、まあ、 36:10 まあ、まず充電だけ、 36:12 充電だけちゃんとして、 36:16 撮影が、 36:18 うまくできるのかどうかを、 36:21 まあ、確認するのも、 36:23 重要だなと思って。 36:25 まずそれから実験。 36:27 まあ、分けて考えないと。 36:29 充電と、 36:31 給電の問題と、 36:33 充電というよりは給電ですよね。 36:38 給電と、 36:52 このピンマイクを、 36:54 そのスプリッターで分けてですね、 36:58 レシーバーをつけ、 36:59 レシーバーをつけた状態で、 37:01 給電しながらやるのと、 37:03 まあ、どうかですね。 37:04 そこをちょっと、 37:06 まあ、条件が違ってくるので、 37:08 給電が、 37:09 まあ、要は、 37:11 ファイナルカットカメラと、 37:13 それから、 37:15 ZEPPのその、 37:17 あれですよね、 37:23 ウォーキングのあの、 37:24 モニタリングですよね。 37:26 GPSのデータの記録と、 37:28 それから、 37:30 ピンマイクも可動と、 37:32 3つ同時に動くので、 37:34 まあ、スプリットカメラが、 37:36 ファイナルカットカメラが、 37:38 一番大きな電力消費だと、 37:40 思うんですけど、 37:42 それ全部動かしてみてどうかっていうのと、 37:45 まあ、2つだけ動かしてどうかっていうのとね、 37:47 まあ、 37:49 あー跳びますね、魚が。 37:51 2カ所で跳ねました。 37:53 まあ、そういうことでですね、 37:58 まあ、実験を 38:00 兼ねて、今日は来ました。 38:08 それでは、もうちょっと、 38:10 下流に行って、 38:15 コサギ君か、アオサギ君がいるかどうか、 38:17 確かめて帰りましょうか。 40:06 実がなってます。硬いです。 41:41 サギがいないね。 41:56 第6ですね、ここ。第6船着き場。 41:58 ただいまの時刻、 42:22 15時41分46秒ですね。 42:24 今、それが第1ツバキでしたけど、 43:06 第2ツバキはどうなってるんですかね。 43:08 花が咲くんですかね。 43:32 第3ツバキは、 45:02 花じゃないような、 45:06 葉っぱのような気がする。 45:14 後ろの方は、 45:19 花が咲くような、 45:21 気がしないでもない。 45:34 ですね。まあ、 45:36 様子見ておきましょう。 45:38 さて、アジサイ。 45:41 第3ヤマモモですね。 45:43 第七船着き場ですね。 47:24 増えてきましたね。 48:06 鳩か、どうしましょうか。 50:16 上空、トビが回っているようですけど。 50:32 なんでしょうけど。 51:46 ああ、飛んでますね。 51:48 全然出てない。 52:29 ですね。 52:31 トビと飛行機が、 52:39 飛んでますね。 52:44 岸壁で、 53:11 空を見上げて。 53:13 危険だ。 53:18 さあ、やはり終わりにしましょう。 53:25 買い物に行って帰ります。 53:39 でも、鳥がなぜかいないね。 53:48 今日は 54:14 魚デーだったね。 54:18 終了です。 54:20 電車が来てますね。 54:42 それでは、終わります。 54:44 ご苦労様でした。 54:46 ありがとうございます。 54:48 いつもご視聴ありがとうございます。 54:50 終わります。
更新日記は元々jperlで書いていて、Windowsの「Command Prompt」から「Power Shell」への移り変わりとともに、結果として今はperlで書き直したものも混在しているが、jperlはまだ現役だ。Windows11からUTF-8への移行が鮮明になったが、WEBのお陰でレガシーSJISは残る。日本語エディタの問題はあるわけだが、ファイル名の取り扱いは問題がありそうだし、UTF-8のテキスト画面からSJISのテキスト画面に貼り付けると自動的に変換される。更新日記のRSSやATOMはUTF-8に変換しているといってもね。どれほど意味があるのか。
そして、生成AI/LLMの時代はPythonになった。そちらはお任せに近いが、現実世界とのインターフェースはjperl/perlと自分自身になる。コンテンツのデータ整理・加工・プランニング及びデバッグ担当。昨日(1/19)は、Engramの件で訪れて、ついでにDeepSeekとスクリプティングをして、一日中夜遅くまで過ごした。DeepSeek二人分の対話が必要だった。一人分のチャットログの分量的(10000行/450~500KB/DS人)は{記憶の細道プロジェクト うむむ、M1 MacBook Airを使う流れ (2025/07/06)}←の時と変わらないだろう。
道草166のデータは写真が38枚、短い動画が三つという変則的なものになっている。iPhone XRのメモリが乏しい状態で道草に臨まなくてはならなかったからだ。{12/03/2025: [日記]道草166 - 更新日記の混沌から道草・散歩世界の混沌へ}←。
3分のショート動画の条件を満たすためには、動画の長さを考慮すると、写真を1.3秒ごとに時系列で表示しつつ、短い動画を合間に挟む必要がある。写真は音声がないので、シャッター音でリズム感を出すことにした。シャッター音はiPhone XRのPCM録音アプリを起動・録音している状態でシャッターを切って、該当箇所を0.5秒間切り出したもの。
夜遅くかなり意図通りに動く動画ができたが、動画の音声が動画から静止画に移っても続いて、シャッター音が後にズレてしまう。おかしくなるのは一つの動画が終了した後に生ずることに気付いた。その動画は再生はできるが、長さが00:00:00となっていて異常な感じがする短い動画だ。ナンキンハゼの白い実が風に震えている。これを外すと意図通りの動画ができた。長さが0になっているということは、おそらくファイルが壊れているんだろう。写真を撮るつもりが動画になって瞬間的に中止した記憶がある。道草166ハイブリッド・ショート😀
# windows_explorer_sort_video_creator_final_robust.py - 異常ファイル自動除外版
import os
import json
import datetime
import subprocess
import shutil
from pathlib import Path
import sys
from PIL import Image
import tempfile
import re
from datetime import timezone, timedelta
def check_ffmpeg():
"""FFmpegがインストールされているか確認"""
try:
result = subprocess.run(['ffmpeg', '-version'], capture_output=True, text=True, shell=True)
if result.returncode == 0:
return True, "FFmpegが見つかりました"
else:
return False, "FFmpegの実行に失敗しました"
except FileNotFoundError:
return False, "FFmpegが見つかりません"
def normalize_path(path):
"""パスを正規化"""
if not path:
return path
abs_path = os.path.abspath(path)
abs_path = abs_path.replace('/', '\\')
abs_path = os.path.normpath(abs_path)
return abs_path
def fix_image_orientation(image_path):
"""
画像のExif Orientationタグを読み取り、適切に回転させた画像を一時ファイルに保存
"""
try:
with Image.open(image_path) as img:
exif = img._getexif()
if exif and 274 in exif:
orientation = exif[274]
if orientation == 3:
img = img.rotate(180, expand=True)
elif orientation == 6:
img = img.rotate(270, expand=True)
elif orientation == 8:
img = img.rotate(90, expand=True)
# 一時ファイルに保存
temp_dir = tempfile.gettempdir()
temp_filename = f"fixed_{os.path.basename(image_path)}"
temp_path = os.path.join(temp_dir, temp_filename)
img.save(temp_path)
return temp_path
except Exception as e:
print(f" 画像の向き修正エラー: {e}")
return image_path
def convert_utc_to_jst(utc_dt):
"""
UTC日時を日本時間(JST)に変換
JST = UTC + 9時間
"""
if not utc_dt:
return None
# UTCのオフセットを設定
if utc_dt.tzinfo is None:
# タイムゾーン情報がない場合はUTCと仮定
utc_dt = utc_dt.replace(tzinfo=timezone.utc)
# 日本時間に変換
jst_offset = timedelta(hours=9)
jst_timezone = timezone(jst_offset)
return utc_dt.astimezone(jst_timezone).replace(tzinfo=None)
def get_video_metadata_date_advanced(file_path):
"""
動画ファイルからメディアメタデータの作成日時を詳細に取得
FFmpegの複数の方法を試す
"""
file_path = normalize_path(file_path)
filename = os.path.basename(file_path)[:40]
print(f" 動画メタデータ取得中: {filename}")
# 方法1: format_tagsのcreation_timeを取得
try:
cmd1 = [
'ffprobe', '-v', 'quiet',
'-show_entries', 'format_tags=creation_time',
'-of', 'default=noprint_wrappers=1:nokey=1',
file_path
]
result1 = subprocess.run(cmd1, capture_output=True, text=True, shell=False)
if result1.returncode == 0 and result1.stdout.strip():
creation_time_str = result1.stdout.strip()
print(f" format_tags.creation_time: {creation_time_str}")
# 様々な形式の日付をパース
parsed_date = parse_date_string(creation_time_str)
if parsed_date:
print(f" メタデータ日時を使用: {parsed_date}")
return parsed_date
except Exception as e:
print(f" method1 error: {e}")
# 方法2: ストリームのタグからも取得を試みる
try:
cmd2 = [
'ffprobe', '-v', 'quiet',
'-show_entries', 'stream_tags=creation_time',
'-of', 'default=noprint_wrappers=1:nokey=1',
file_path
]
result2 = subprocess.run(cmd2, capture_output=True, text=True, shell=False)
if result2.returncode == 0 and result2.stdout.strip():
creation_time_str = result2.stdout.strip()
print(f" stream_tags.creation_time: {creation_time_str}")
parsed_date = parse_date_string(creation_time_str)
if parsed_date:
print(f" ストリームメタデータ日時を使用: {parsed_date}")
return parsed_date
except Exception as e:
print(f" method2 error: {e}")
# 方法3: 全メタデータをダンプして日付らしきものを検索
try:
cmd3 = ['ffprobe', '-v', 'quiet', '-show_format', '-show_streams', file_path]
result3 = subprocess.run(cmd3, capture_output=True, text=True, shell=False)
if result3.returncode == 0:
output = result3.stdout
# 日付らしきパターンを検索
date_patterns = [
r'creation_time=([^\n]+)',
r'date=([^\n]+)',
r'creation_date=([^\n]+)',
r'creationdate=([^\n]+)',
r'DateTimeOriginal=([^\n]+)',
r'DateTime=([^\n]+)'
]
for pattern in date_patterns:
matches = re.findall(pattern, output, re.IGNORECASE)
for match in matches:
if match:
print(f" パターン '{pattern}' で発見: {match}")
parsed_date = parse_date_string(match)
if parsed_date:
print(f" 検出メタデータ日時を使用: {parsed_date}")
return parsed_date
except Exception as e:
print(f" method3 error: {e}")
print(f" メタデータ作成日時が見つかりませんでした")
return None
def parse_date_string(date_str):
"""
様々な形式の日付文字列をパースする(UTC対応版)
"""
if not date_str or not isinstance(date_str, str):
return None
date_str = date_str.strip()
# よくある日付形式のリスト(タイムゾーン対応)
formats = [
# ISO 8601形式(タイムゾーン付き)
"%Y-%m-%dT%H:%M:%S.%fZ", # 2025-12-02T07:43:09.000000Z
"%Y-%m-%dT%H:%M:%SZ", # 2025-12-02T07:43:09Z
"%Y-%m-%dT%H:%M:%S.%f", # 2025-12-02T07:43:09.000000
"%Y-%m-%dT%H:%M:%S", # 2025-12-02T07:43:09
# タイムゾーンオフセット付き
"%Y-%m-%dT%H:%M:%S.%f%z", # 2025-12-02T07:43:09.000000+00:00
"%Y-%m-%dT%H:%M:%S%z", # 2025-12-02T07:43:09+00:00
# 標準形式
"%Y-%m-%d %H:%M:%S", # 2025-12-02 07:43:09
"%Y:%m:%d %H:%M:%S", # 2025:12:02 07:43:09
"%Y/%m/%d %H:%M:%S", # 2025/12/02 07:43:09
"%Y%m%d %H:%M:%S", # 20251202 07:43:09
"%Y-%m-%d", # 2025-12-02
"%Y:%m:%d", # 2025:12:02
"%Y/%m/%d", # 2025/12/02
"%Y%m%d", # 20251202
]
# まず、タイムゾーン情報を保持しながらパースを試みる
for fmt in formats:
try:
dt = datetime.datetime.strptime(date_str, fmt)
# Zで終わる場合はUTCとして扱う
if date_str.endswith('Z'):
dt = dt.replace(tzinfo=timezone.utc)
# UTCを日本時間に変換
dt_jst = convert_utc_to_jst(dt)
if dt_jst:
# 明らかに間違った日付でないかチェック
current_year = datetime.datetime.now().year
if 1990 <= dt_jst.year <= current_year + 5:
return dt_jst
# タイムゾーンオフセットがある場合
elif dt.tzinfo is not None:
# 日本時間に変換
dt_jst = convert_utc_to_jst(dt)
if dt_jst:
current_year = datetime.datetime.now().year
if 1990 <= dt_jst.year <= current_year + 5:
return dt_jst
# タイムゾーン情報がない場合
else:
# ZがなくてもISO形式でTを含む場合はUTCと仮定(多くの動画ファイルでこの形式)
if 'T' in date_str and '.' not in date_str and 'Z' not in date_str:
# 例: 2025-12-02T07:43:09
# 多くの動画メタデータはUTCだがZを付けないことがある
dt = dt.replace(tzinfo=timezone.utc)
dt_jst = convert_utc_to_jst(dt)
if dt_jst:
current_year = datetime.datetime.now().year
if 1990 <= dt_jst.year <= current_year + 5:
return dt_jst
else:
# タイムゾーン情報がないが、明らかに異常でない日付
current_year = datetime.datetime.now().year
if 1990 <= dt.year <= current_year + 5:
return dt
except ValueError:
continue
# 特殊なケース:時間がなかった場合に00:00:00を追加
if len(date_str) == 10 and '-' in date_str: # YYYY-MM-DD形式
try:
dt = datetime.datetime.strptime(date_str, "%Y-%m-%d")
current_year = datetime.datetime.now().year
if 1990 <= dt.year <= current_year + 5:
return dt
except ValueError:
pass
print(f" 日付パース失敗: {date_str}")
return None
def get_exif_date_for_image(file_path):
"""
画像からExif日付を取得
"""
try:
with Image.open(file_path) as img:
exif = img._getexif()
if exif:
# EXIFタグ 36867: DateTimeOriginal (撮影日時) - 最優先
if 36867 in exif:
date_str = exif[36867]
try:
exif_date = datetime.datetime.strptime(date_str, "%Y:%m:%d %H:%M:%S")
print(f" Exif撮影日時(DateTimeOriginal): {exif_date}")
return exif_date
except ValueError:
pass
# EXIFタグ 306: DateTime (作成日時)
if 306 in exif:
date_str = exif[306]
try:
exif_date = datetime.datetime.strptime(date_str, "%Y:%m:%d %H:%M:%S")
print(f" Exif作成日時(DateTime): {exif_date}")
return exif_date
except ValueError:
pass
except Exception as e:
print(f" Exif取得エラー: {e}")
return None
def get_file_system_dates(file_path):
"""
ファイルシステムの日付を取得
"""
try:
stat = os.stat(file_path)
ctime = datetime.datetime.fromtimestamp(stat.st_ctime) # 作成日時(ファイルシステム)
mtime = datetime.datetime.fromtimestamp(stat.st_mtime) # 更新日時
# どちらが古いか(通常、作成日時が撮影日に近い)
return min(ctime, mtime)
except:
return datetime.datetime.now()
def get_windows_explorer_sort_date(file_path, file_type="image"):
"""
Windowsエクスプローラーと同じ方法で日付を取得(日本時間対応版)
"""
file_path = normalize_path(file_path)
filename = os.path.basename(file_path)[:50]
print(f"\n 処理中: {filename}")
print(f" タイプ: {file_type}")
# ファイルシステムの日付を取得(フォールバック用)
fs_date = get_file_system_dates(file_path)
print(f" ファイルシステム日付: {fs_date.strftime('%Y-%m-%d %H:%M:%S')}")
if file_type == "image":
# 画像:Exif日付を最優先
exif_date = get_exif_date_for_image(file_path)
if exif_date:
# Exif日付が明らかにおかしい場合(未来の日付など)はファイルシステム日付を使用
current_year = datetime.datetime.now().year
if exif_date.year > current_year + 5 or exif_date.year < 1990:
print(f" Exif日付が異常({exif_date.year}年) → ファイルシステム日付を使用")
return fs_date
print(f" Exif日付を使用: {exif_date.strftime('%Y-%m-%d %H:%M:%S')}")
return exif_date
print(f" Exif日付なし → ファイルシステム日付を使用")
return fs_date
elif file_type == "video":
# 動画:メディアメタデータの作成日時を最優先
metadata_date = get_video_metadata_date_advanced(file_path)
if metadata_date:
# メタデータ日付が明らかにおかしい場合はファイルシステム日付を使用
current_year = datetime.datetime.now().year
if metadata_date.year > current_year + 5 or metadata_date.year < 1990:
print(f" メタデータ日付が異常({metadata_date.year}年) → ファイルシステム日付を使用")
return fs_date
# 日本時間への変換を確認(parse_date_string内で既に変換済み)
print(f" メタデータ日付を使用(日本時間): {metadata_date.strftime('%Y-%m-%d %H:%M:%S')}")
return metadata_date
print(f" メタデータ日付なし → ファイルシステム日付を使用")
return fs_date
else:
return fs_date
def check_video_file(file_path):
"""
動画ファイルの健全性チェック
長さが0秒または異常な動画ファイルを検出
"""
file_path = normalize_path(file_path)
try:
# 動画の長さを取得
cmd = [
'ffprobe', '-v', 'error',
'-show_entries', 'format=duration',
'-of', 'default=noprint_wrappers=1:nokey=1',
file_path
]
result = subprocess.run(cmd, capture_output=True, text=True, shell=False)
if result.returncode != 0:
print(f" 動画ファイル検査エラー: {result.stderr[:100]}")
return False, "FFprobe実行エラー"
if not result.stdout.strip():
print(f" 動画ファイル検査エラー: 長さ情報が空")
return False, "長さ情報なし"
try:
duration = float(result.stdout.strip())
# 長さチェック
if duration <= 0:
print(f" 異常な動画ファイル: 長さ={duration}秒(0秒以下)")
return False, f"長さ0秒(異常)"
elif duration < 0.1: # 0.1秒未満も異常とみなす
print(f" 異常な動画ファイル: 長さ={duration}秒(極端に短い)")
return False, f"長さ{duration}秒(極端に短い)"
elif duration > 3600: # 1時間以上は異常とみなす(オプション)
print(f" 異常な動画ファイル: 長さ={duration}秒(極端に長い)")
return False, f"長さ{duration}秒(極端に長い)"
else:
print(f" 動画ファイル正常: 長さ={duration:.2f}秒")
return True, f"長さ{duration:.2f}秒"
except ValueError:
print(f" 動画ファイル検査エラー: 長さの解析失敗")
return False, "長さ解析失敗"
except Exception as e:
print(f" 動画ファイル検査エラー: {e}")
return False, f"検査エラー: {e}"
def check_image_file(file_path):
"""
画像ファイルの健全性チェック
"""
file_path = normalize_path(file_path)
try:
# PILで画像を開いてチェック
with Image.open(file_path) as img:
# 画像の基本情報を取得
width, height = img.size
format = img.format
if width <= 0 or height <= 0:
print(f" 異常な画像ファイル: サイズ={width}x{height}")
return False, f"異常なサイズ: {width}x{height}"
print(f" 画像ファイル正常: {format}形式, {width}x{height}ピクセル")
return True, f"{format}形式, {width}x{height}px"
except Exception as e:
print(f" 画像ファイル検査エラー: {e}")
return False, f"検査エラー: {e}"
def generate_media_json_with_windows_sort(folder_path, output_file="media_sequence.json"):
"""
Windowsエクスプローラーと同じ方法でソートしたJSONを生成(日本時間対応)
異常ファイルを自動検出して除外
"""
print("="*80)
print("Windowsエクスプローラーソート順JSON生成(日本時間対応・異常ファイル自動除外)")
print("="*80)
print("仕様:")
print(" 写真: Exif撮影日時を使用")
print(" 動画: メディアメタデータ作成日時(UTC→JST変換)を使用")
print(" 異常ファイル(長さ0秒の動画など)を自動除外")
print("="*80)
# 拡張子の定義
image_exts = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.heic', '.heif', '.JPG', '.JPEG', '.PNG', '.GIF', '.BMP'}
video_exts = {'.mp4', '.mov', '.avi', '.mkv', '.flv', '.wmv', '.webm', '.m4v', '.mpg', '.mpeg', '.3gp', '.mts', '.m2ts', '.MOV', '.MP4', '.AVI', '.MKV'}
media_files = []
folder_path = normalize_path(folder_path)
# 異常ファイルリスト
bad_files = []
good_files = []
# 全てのファイルを再帰的に取得
all_files = []
for file_path in Path(folder_path).rglob('*'):
if file_path.is_file():
all_files.append(str(file_path))
print(f"フォルダ内の全ファイル数: {len(all_files)}")
print("\nファイル検査を開始します...")
# 各ファイルの検査と日付取得
for i, file_path_str in enumerate(all_files):
ext = os.path.splitext(file_path_str)[1].lower()
filename = os.path.basename(file_path_str)
print(f"\n[{i+1}/{len(all_files)}] 検査中: {filename}")
if ext in image_exts:
file_type = "image"
# 画像ファイルの健全性チェック
is_ok, message = check_image_file(file_path_str)
elif ext in video_exts:
file_type = "video"
# 動画ファイルの健全性チェック
is_ok, message = check_video_file(file_path_str)
else:
# メディアファイルではない
continue
if not is_ok:
# 異常ファイルを記録
bad_files.append({
"path": file_path_str,
"type": file_type,
"reason": message,
"filename": filename
})
print(f" ? このファイルは除外されます: {message}")
continue
# 正常ファイルのみ日付を取得
date = get_windows_explorer_sort_date(file_path_str, file_type)
# 相対パスを取得
try:
relative_path = str(Path(file_path_str).relative_to(folder_path))
except:
relative_path = str(file_path_str)
media_files.append({
"path": relative_path,
"type": file_type,
"creation_time": date,
"full_path": file_path_str,
"filename": filename,
"status": "正常"
})
good_files.append(filename)
print(f"\n正常なメディアファイル数: {len(media_files)}")
print(f"除外された異常ファイル数: {len(bad_files)}")
if bad_files:
print(f"\n除外された異常ファイル一覧:")
for i, bad_file in enumerate(bad_files, 1):
print(f" {i:3d}. {bad_file['filename']} - {bad_file['type']} - 理由: {bad_file['reason']}")
if not media_files:
print("正常なメディアファイルが見つかりませんでした")
return None
# 日付で昇順ソート
media_files.sort(key=lambda x: x["creation_time"])
# 結果を表示
print("\n" + "="*80)
print("ソート結果(正常ファイルのみ、最初の20ファイル)")
print("="*80)
for i, media in enumerate(media_files[:20], 1):
time_str = media["creation_time"].strftime("%Y-%m-%d %H:%M:%S")
type_icon = "??" if media['type'] == 'image' else "??"
filename = media['filename'][:60]
print(f"{i:4d}. {time_str} {type_icon} {filename}")
# 最後の10ファイルも表示
if len(media_files) > 20:
print(f"\n... ({len(media_files) - 20} ファイル省略) ...\n")
print("ソート結果(最後の10ファイル)")
print("-" * 80)
for i, media in enumerate(media_files[-10:], len(media_files) - 9):
time_str = media["creation_time"].strftime("%Y-%m-%d %H:%M:%S")
type_icon = "??" if media['type'] == 'image' else "??"
filename = media['filename'][:60]
print(f"{i:4d}. {time_str} {type_icon} {filename}")
# 統計情報
total_image = sum(1 for m in media_files if m['type'] == 'image')
total_video = sum(1 for m in media_files if m['type'] == 'video')
print(f"\n統計情報:")
print(f" 正常な写真: {total_image}個")
print(f" 正常な動画: {total_video}個")
print(f" 合計正常ファイル: {len(media_files)}個")
print(f" 除外された異常ファイル: {len(bad_files)}個")
# 日付範囲
if media_files:
first = media_files[0]["creation_time"]
last = media_files[-1]["creation_time"]
days = (last - first).days
print(f"\n日付範囲: {first.strftime('%Y-%m-%d')} ? {last.strftime('%Y-%m-%d')} ({days}日間)")
# JSONデータを生成
media_sequence = []
for media in media_files:
if media["type"] == "image":
item = {
"type": "image",
"path": media["path"],
"duration": 1.3,
"zoom_effect": True,
"with_shutter": True,
"shutter_volume": 0.7
}
else: # video
item = {
"type": "video",
"path": media["path"],
"duration": None,
"start_time": 0.0,
"speed": 1.0
}
media_sequence.append(item)
# ファイルに保存
output_path = os.path.join(folder_path, output_file)
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(media_sequence, f, indent=2, ensure_ascii=False)
# 異常ファイルリストも保存(オプション)
if bad_files:
bad_files_path = os.path.join(folder_path, "excluded_files.json")
with open(bad_files_path, 'w', encoding='utf-8') as f:
json.dump(bad_files, f, indent=2, ensure_ascii=False)
print(f"\n除外ファイルリストを保存しました: {bad_files_path}")
print(f"\nJSONファイルを保存しました: {output_path}")
print(f"合計 {len(media_files)} 個の正常ファイルを処理しました")
# サンプルを表示
print(f"\nサンプル(最初の5エントリ):")
for i, item in enumerate(media_sequence[:5], 1):
print(f" {i}. {item['type']}: {item['path'][:60]}")
return output_path
def create_shutter_sound(input_audio, output_file="shutter.wav", start_time=9.0, end_time=10.0):
"""シャッター音を作成"""
ffmpeg_available, ffmpeg_message = check_ffmpeg()
if not ffmpeg_available:
print(f"{ffmpeg_message}")
return False
input_audio = normalize_path(input_audio)
if not os.path.exists(input_audio):
print(f"ファイルが見つかりません: {input_audio}")
return False
output_path = normalize_path(output_file)
print(f"シャッター音を作成中: {input_audio} ({start_time}-{end_time}秒)")
cmd = f'ffmpeg -y -i "{input_audio}" -ss {start_time} -to {end_time} -c:a pcm_s16le -ar 44100 -ac 2 "{output_path}"'
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode == 0:
print(f"シャッター音を作成しました: {output_path}")
return True
else:
print(f"エラー: {result.stderr[:500]}")
return False
except Exception as e:
print(f"エラー: {e}")
return False
def create_video_from_json(json_path, output_video="youtube_shorts.mp4", shutter_sound_path=None):
"""
JSONから動画を作成(異常ファイル対応版)
各クリップ処理前に健全性チェックを実施
"""
print(f"動画作成開始: {json_path}")
print("="*80)
print("異常ファイル対応版")
print("特徴:")
print(" 1. 各クリップ処理前に健全性チェック")
print(" 2. 異常なファイルは自動スキップ")
print(" 3. 音声漏れ防止対策済み")
print("="*80)
ffmpeg_available, ffmpeg_message = check_ffmpeg()
if not ffmpeg_available:
print(f"? {ffmpeg_message}")
return False
with open(json_path, 'r', encoding='utf-8') as f:
media_sequence = json.load(f)
folder_path = os.path.dirname(json_path)
output_path = os.path.join(folder_path, output_video)
output_path = normalize_path(output_path)
temp_dir = os.path.join(folder_path, "temp_video_creation")
os.makedirs(temp_dir, exist_ok=True)
clip_files = []
skipped_files = []
try:
print(f"\n{len(media_sequence)}個のメディアを処理中...")
for i, media in enumerate(media_sequence):
media_type = media.get("type")
relative_path = media.get("path")
full_path = os.path.join(folder_path, relative_path)
full_path = normalize_path(full_path)
if not os.path.exists(full_path):
print(f"ファイルが見つかりません: {full_path}")
skipped_files.append({"filename": os.path.basename(relative_path), "reason": "ファイル不存在"})
continue
# ファイルの健全性チェック
if media_type == "video":
is_ok, message = check_video_file(full_path)
if not is_ok:
print(f" 異常な動画ファイルをスキップ: {os.path.basename(relative_path)} - {message}")
skipped_files.append({"filename": os.path.basename(relative_path), "reason": f"動画異常: {message}"})
continue
elif media_type == "image":
is_ok, message = check_image_file(full_path)
if not is_ok:
print(f" 異常な画像ファイルをスキップ: {os.path.basename(relative_path)} - {message}")
skipped_files.append({"filename": os.path.basename(relative_path), "reason": f"画像異常: {message}"})
continue
clip_filename = os.path.join(temp_dir, f"clip_{i:04d}.mp4")
if media_type == "image":
duration = media.get("duration", 1.3)
zoom_effect = media.get("zoom_effect", True)
with_shutter = media.get("with_shutter", True)
shutter_volume = media.get("shutter_volume", 0.7)
print(f" [{i+1}/{len(media_sequence)}] 画像: {os.path.basename(relative_path)}")
print(f" 長さ: {duration}秒, シャッター音: {'あり' if with_shutter else 'なし'}")
fixed_image_path = fix_image_orientation(full_path)
if zoom_effect:
filter_complex = (
f"scale=1080:1920:force_original_aspect_ratio=increase,"
f"crop=1080:1920,"
f"zoompan=z='zoom+0.002':d=1:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=1080x1920"
)
else:
filter_complex = (
f"scale=1080:1920:force_original_aspect_ratio=increase,"
f"crop=1080:1920"
)
# 画像クリップを作成(常に音声ストリームあり)
if with_shutter and shutter_sound_path and os.path.exists(shutter_sound_path):
print(f" ?? シャッター音を追加(1回のみ)")
# シャッター音の長さを取得
shutter_info_cmd = f'ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "{shutter_sound_path}"'
shutter_info = subprocess.run(shutter_info_cmd, shell=True, capture_output=True, text=True)
shutter_duration = 1.0 # デフォルト値
if shutter_info.returncode == 0:
try:
shutter_duration = float(shutter_info.stdout.strip())
except:
shutter_duration = 1.0
# シャッター音が画像の長さより長い場合は制限
if shutter_duration > duration:
shutter_duration = duration
# 画像クリップを生成(シャッター音付き)
cmd = f'ffmpeg -y -loop 1 -i "{fixed_image_path}" -i "{shutter_sound_path}"'
cmd += f' -filter_complex "[0:v]{filter_complex}[v];[1:a]atrim=0:{shutter_duration},adelay=0|0,apad=whole_dur={duration},volume={shutter_volume}[a]"'
cmd += f' -map "[v]" -map "[a]"'
cmd += f' -c:v libx264 -preset fast -tune stillimage -pix_fmt yuv420p -r 30'
cmd += f' -c:a aac -b:a 128k'
cmd += f' -t {duration} "{clip_filename}"'
else:
print(f" 音声なし(無音ストリームを追加)")
# 音声なしの場合は無音の音声ストリームを追加
cmd = f'ffmpeg -y -loop 1 -i "{fixed_image_path}" -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100'
cmd += f' -filter_complex "[0:v]{filter_complex}[v]"'
cmd += f' -map "[v]" -map 1:a'
cmd += f' -c:v libx264 -preset fast -tune stillimage -pix_fmt yuv420p -r 30'
cmd += f' -c:a aac -b:a 128k'
cmd += f' -t {duration} "{clip_filename}"'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
print(f" 画像変換エラー: {result.stderr[:200]}")
skipped_files.append({"filename": os.path.basename(relative_path), "reason": f"変換エラー: {result.stderr[:100]}"})
continue
clip_files.append(clip_filename)
elif media_type == "video":
duration = media.get("duration")
start_time = media.get("start_time", 0.0)
print(f" [{i+1}/{len(media_sequence)}] 動画: {os.path.basename(relative_path)}")
# 動画クリップを作成(音声付き)
cmd = f'ffmpeg -y'
if start_time > 0:
cmd += f' -ss {start_time}'
cmd += f' -i "{full_path}"'
if duration:
cmd += f' -t {duration}'
# 動画の音声を確実にクリップ終了時に終了させる
cmd += f' -vf "scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920"'
cmd += f' -c:v libx264 -preset fast -pix_fmt yuv420p -r 30'
cmd += f' -c:a aac -b:a 128k'
cmd += f' -af "apad=pad_dur={0.01}"' # 微小なパディングを追加して確実に終了
cmd += f' -shortest' # 動画または音声の短い方で終了
cmd += f' "{clip_filename}"'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
print(f" 動画処理エラー: {result.stderr[:200]}")
skipped_files.append({"filename": os.path.basename(relative_path), "reason": f"処理エラー: {result.stderr[:100]}"})
continue
# 処理後のクリップの健全性をチェック
is_ok, message = check_video_file(clip_filename)
if not is_ok:
print(f" 処理後のクリップが異常: {message}")
skipped_files.append({"filename": os.path.basename(relative_path), "reason": f"処理後異常: {message}"})
continue
clip_files.append(clip_filename)
if not clip_files:
print("処理できるクリップがありませんでした")
if skipped_files:
print(f"\nスキップされたファイル ({len(skipped_files)}個):")
for i, skipped in enumerate(skipped_files, 1):
print(f" {i:3d}. {skipped['filename']} - {skipped['reason']}")
return False
print(f"\n{len(clip_files)}個の正常クリップを結合中...")
if skipped_files:
print(f"スキップされたファイル: {len(skipped_files)}個")
for i, skipped in enumerate(skipped_files[:10], 1): # 最初の10個のみ表示
print(f" {i:3d}. {skipped['filename']} - {skipped['reason']}")
if len(skipped_files) > 10:
print(f" ... 他{len(skipped_files)-10}個")
# クリップの結合
list_file = os.path.join(temp_dir, "clips.txt")
with open(list_file, 'w', encoding='utf-8') as f:
for clip in clip_files:
clip_path = normalize_path(clip)
clip_path = clip_path.replace("'", "'\\''")
f.write(f"file '{clip_path}'\n")
# クリップを結合(concat demuxerを使用)
combine_cmd = f'ffmpeg -y -f concat -safe 0 -i "{list_file}" -c copy -movflags +faststart "{output_path}"'
print("最終動画を生成中...")
result = subprocess.run(combine_cmd, shell=True, capture_output=True, text=True)
if result.returncode == 0:
print(f"\n動画作成成功: {output_path}")
# 出力動画の健全性チェック
is_ok, message = check_video_file(output_path)
if is_ok:
print(f"出力動画正常: {message}")
else:
print(f"出力動画に問題あり: {message}")
if os.path.exists(output_path):
size = os.path.getsize(output_path) / (1024*1024)
print(f" ファイルサイズ: {size:.2f} MB")
duration_cmd = f'ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "{output_path}"'
duration_result = subprocess.run(duration_cmd, shell=True, capture_output=True, text=True)
if duration_result.returncode == 0:
total_duration = float(duration_result.stdout.strip())
minutes = int(total_duration // 60)
seconds = int(total_duration % 60)
print(f" 動画の長さ: {minutes}分{seconds}秒 ({total_duration:.1f}秒)")
# スキップファイル情報を保存
if skipped_files:
skipped_path = os.path.join(folder_path, "skipped_files.json")
with open(skipped_path, 'w', encoding='utf-8') as f:
json.dump(skipped_files, f, indent=2, ensure_ascii=False)
print(f"\nスキップファイルリストを保存しました: {skipped_path}")
return True
else:
print(f"\n動画結合エラー: {result.stderr[:500]}")
return False
except Exception as e:
print(f"\n予期せぬエラー: {e}")
import traceback
traceback.print_exc()
return False
finally:
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir, ignore_errors=True)
print("一時ファイルをクリーンアップしました")
def main_menu():
"""メインメニュー - 異常ファイル対応版"""
print("="*80)
print("YouTubeショート動画作成ツール - 異常ファイル対応版")
print("="*80)
print("特徴:")
print(" 1. 長さ0秒の動画など異常ファイルを自動検出・除外")
print(" 2. 各処理段階でファイル健全性チェック")
print(" 3. 音声漏れ防止対策済み")
print(" 4. 動画メタデータUTC→日本時間変換")
print("="*80)
ffmpeg_available, ffmpeg_message = check_ffmpeg()
print(f"FFmpegステータス: {ffmpeg_message}")
if not ffmpeg_available:
print("\n警告: FFmpegがインストールされていません。")
print("ダウンロード: https://ffmpeg.org/download.html")
print("または Windows用: https://www.gyan.dev/ffmpeg/builds/")
print("\nインストール後に再度実行してください。")
input("Enterキーを押して終了...")
return
while True:
print("\n" + "="*80)
print("メインメニュー(異常ファイル対応版)")
print("="*80)
print("1. メディアフォルダからJSONを生成(異常ファイル自動除外)")
print("2. JSONから動画を作成(異常ファイル対応)")
print("3. シャッター音を作成")
print("4. 終了")
print("="*80)
try:
choice = input("\n選択 (1-4): ").strip()
if choice == '1':
print("\n" + "="*80)
folder_path = input("メディアフォルダのパスを入力 (デフォルト: .): ").strip()
if not folder_path:
folder_path = "."
folder_path = normalize_path(folder_path)
if not os.path.exists(folder_path):
print(f"フォルダが存在しません: {folder_path}")
continue
try:
json_path = generate_media_json_with_windows_sort(folder_path)
if json_path:
print(f"\nJSONファイルが生成されました: {json_path}")
except Exception as e:
print(f"エラー: {e}")
import traceback
traceback.print_exc()
elif choice == '2':
print("\n" + "="*80)
print("動画作成(異常ファイル対応版)")
print("="*80)
json_path = input("JSONファイルのパスを入力: ").strip()
if not json_path:
print("JSONファイルのパスを入力してください")
continue
json_path = normalize_path(json_path)
if not os.path.exists(json_path):
print(f"JSONファイルが見つかりません: {json_path}")
continue
output_name = input("出力動画ファイル名 (デフォルト: youtube_shorts.mp4): ").strip()
if not output_name:
output_name = "youtube_shorts.mp4"
folder_path = os.path.dirname(json_path)
shutter_sound = os.path.join(folder_path, "shutter.wav")
use_shutter = "n"
if os.path.exists(shutter_sound):
print(f"\nシャッター音ファイルが見つかりました: {shutter_sound}")
use_shutter = input("シャッター音を使用しますか? (y/n): ").strip().lower()
shutter_path = shutter_sound if use_shutter == 'y' else None
print("\n動画作成を開始します...")
try:
success = create_video_from_json(json_path, output_name, shutter_path)
if success:
output_path = os.path.join(folder_path, output_name)
print(f"\n動画作成が完了しました!")
print(f"出力ファイル: {output_path}")
# Windowsの場合、再生を提案
if sys.platform == "win32":
play = input("\n動画を再生しますか? (y/n): ").strip().lower()
if play == 'y':
os.startfile(output_path)
else:
print("\n動画作成に失敗しました")
except Exception as e:
print(f"\nエラー: {e}")
import traceback
traceback.print_exc()
elif choice == '3':
print("\n" + "="*80)
print("シャッター音の作成")
print("="*80)
input_audio = input("録音ファイルのパスを入力: ").strip()
if not input_audio:
print("ファイルのパスを入力してください")
continue
input_audio = normalize_path(input_audio)
if not os.path.exists(input_audio):
print(f"ファイルが見つかりません: {input_audio}")
continue
output_file = input("出力ファイル名 (デフォルト: shutter.wav): ").strip()
if not output_file:
output_file = "shutter.wav"
start_time = input("開始時間(秒, デフォルト: 9.0): ").strip()
start_time = float(start_time) if start_time else 9.0
end_time = input("終了時間(秒, デフォルト: 10.0): ").strip()
end_time = float(end_time) if end_time else 10.0
try:
success = create_shutter_sound(input_audio, output_file, start_time, end_time)
if success:
print(f"\nシャッター音を作成しました: {output_file}")
else:
print("\nシャッター音の作成に失敗しました")
except Exception as e:
print(f"エラー: {e}")
elif choice == '4':
print("\n" + "="*80)
print("プログラムを終了します。")
print("="*80)
break
else:
print("\n無効な選択です。1-4の数字を入力してください。")
except KeyboardInterrupt:
print("\n\n中断されました。")
break
except Exception as e:
print(f"\n? エラー: {e}")
# 次の操作のために一時停止
if choice != '4':
input("\n続行するにはEnterキーを押してください...")
if __name__ == "__main__":
if sys.platform == "win32":
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
try:
from PIL import Image
print("Pillow (PIL) がインストールされています")
except ImportError:
print("警告: Pillow (PIL) がインストールされていません。")
print("画像の向き修正にはPillowが必要です。")
print("インストール: pip install Pillow")
response = input("続行しますか? (画像の向きは修正されません) (y/n): ").strip().lower()
if response != 'y':
sys.exit(1)
try:
main_menu()
except KeyboardInterrupt:
print("\n\nプログラムを中断しました。")
sys.exit(0)
except Exception as e:
print(f"\n予期せぬエラー: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
いつもの完全主義の長ったらしい冗長なスクリプトだが、参考にはなるだろう。記録。絵文字はHTMLコードにしようかと思ったが、スクリプトでもあるので、preタグ内、SJISで取り扱うのはややこしいので削除した。
外気温が上がってきた。予報通り。道草・散歩世界で結局何をすればAIを活用できるのか。字幕を意味があるように構成すること。いやはや、AIというよりは自分自身に戻ってくるという話。それを少し考慮した字幕構成。
(前編) https://youtu.be/ulQRnsOP-5U 00:01 さあ、行きます。 00:19 さて、・・・・・・図書館帰りの道草日記の169回かな、だと思うんですけど。 00:40 行きます。 01:11 (皆実線ヒロデンが通る) 01:36 やっとこさ渡りました。 01:44 (南区役所前電停のヒロデン) 02:43 (南区役所前電停のヒロデンが交差) さあ、どうでしょうか。(広島駅行についで宇品港行も出発) 04:33 今日もよく晴れましたね。 04:56 ここ、ボートが行ったね。 04:59 ボートが行きましたね。 05:36 波が打ち寄せています。 05:43 魚は見えませんね。 05:55 さあ、引いているのか満ちているのか。 06:08 ずっともう先に行きました。 06:33 ちょっと、第一ベンチでちょっと手ぶれ補正が入っているかどうか確認します。 06:47 いつもそう言いながら、確認しないで突っ走っちゃうんだけど。 06:51 今日はちゃんと確認しましょう。 06:55 さあ、何か。 07:21 下流の方には水鳥が居そうな雰囲気はありますね。 07:28 さあ、・・・・・・1、2、3、4、5、6、7段目ですね。 08:28 7段目に水面がちょうど重なっているぐらいの感じです。 08:36 ちょっと透明度は高いとは言えないですね。 08:43 まあ、今ボートが走ったんで、巻き上げられている可能性もありますね。 08:54 川底から。 08:55 さあ、もうすぐ冬至ですからね。 09:39 ただいま16時28分46秒です。 09:42 さて、ちょっとここで停止します。 10:13 よいしょ。 10:14 はい、一旦停止します。 10:24 はい。 10:32 はい。
(後編) https://youtu.be/FlZsqamigMM 00:00 さあ、再開します。 00:02 やはりね、手ブレ補正が入ってないですね。 00:05 すいません。 00:10 画面が揺れるんですよね。 00:12 やはり、見た感じで分かるんですね。 00:19 さあ、もう電池が90%まで落ちているので、バッテリーが、バッテリーつけますね。 00:32 つけました。 01:09 これでいきましょう。 01:18 よし。 01:19 手ブレ補正とバッテリーを調整して、つけて、無線給電で行きます。 01:37 夾竹桃も、もう見えない状態だと言ってもいいぐらいの感じになりましたね。 02:02 まあ、冬ですからね。 02:04 まあ、でも、でもとか言いながら、いつも蕾がありますね。 02:18 はい、行きます。 02:29 行きます、行きます。 02:57 さあ、第二船着き場ですね。 02:59 今日は透明度がちょっと低い感じですね。 03:23 1、2、3、4、5、6、7。 03:26 7段目が水にかかり始めてますね。 03:35 少し満ちているのかもしれませんね。 03:37 川が流れている感じがないので、満ちてきているでしょう、おそらく。 03:48 そう。 03:55 ただいまの時刻、16時34分05秒です。 04:01 さあ、サルスベリを 04:46 いや、通り過ぎちゃいましたね。 04:48 目立たないから。 05:29 さあ、第三の船着き場ですね。 07:01 さあ、第四の船着き場です。 08:03 さて、第二ベンチで、一人読書会、やりましょう。 08:21 あれ、何か水が落ちている。 08:24 雨よ、雨が落ちている。 08:35 ちょっと行かんね。 08:43 第三に行ってみましょう。 09:17 ああ、いましたね、何か。 09:19 鳥がいるなと思っていたら、上がってきている。 09:24 これはカモですね。カモか何か。(ヒドリガモ - Wikipedia参照) 10:44 こちらに気がついています。 11:08 これが今、飛んできました。1羽。 11:24 鳴きましたね。ヒューって。 11:45 まだ逃げませんね、あの2羽。 11:57 もう一度上がってくるかもしれません。 12:09 上がる気はない感じですね。 12:43 さあ、どうなるんだろう。 13:41 ハクセキレイが飛んできましたね。あー(鴨たちが)みんな飛んでいっちゃった。 14:09 この3羽が遠くから。 14:11 第1船着き場ぐらいから見えた3羽ですね。 14:15 さあ、第5。 14:27 第5船付き場です。 14:29 まあ、こんなところにしておきましょう。 15:12 まあ、今日はよかった。来たかいやったね。 15:21 何もないとね。 15:25 まあ、何もないのも事象ではありません。 15:46 ここら辺をずっと泳いでいるんですね。 15:48 さて、太陽はもう沈みますね。 16:01 さて、太陽が沈む前に、読書会を。 16:09 まあ、ここは、少しは、ここは大丈夫だ。 16:16 ここは、大丈夫だ。 16:20 よいしょ。ちょっと濡れてるんだけど。 16:24 やれやれ。 16:35 さて、日が沈みかけてます。 16:49 今日は、えーとですね。 17:00 漫画です。 17:04 AKIRAをね。 17:08 AKIRAはやはり、この大きい版を、大きい版で見ないと。 17:33 このKC、KCデラックスっていうやつですね。 17:43 これをですね。 17:49 KCデラックス講談社。 17:52 これを見ないと、いけないんです。 17:57 とうとうこれ、4巻まで、なんとか頑張って読んでます。 18:01 頑張ってというか。 18:02 あの、面白いんだけど。 18:06 ボリュームがすごいんですね。 18:09 ボリュームがすごいから、読むのに時間はかかります。 18:15 これですね。 18:19 これが5巻。 18:20 まあ、4巻まで読みました。 18:25 6巻ですね。 18:26 5、6を、借り、予約借りました。 18:29 これは、誰だったかな。 18:44 あの、有名な漫画家の。 18:47 漫画家がやはり、これは、絵がすごいし。 18:52 まあ、これは、革新的な漫画だったらしいですね。 18:58 これの影響を、ものすごく。 19:01 まあ、ちょっとこれも、いろいろ検証してみないといけないですけど。 19:05 アニメだけじゃなくって、映画とか、映画なんかにもね。 19:21 ものすごく影響してるのではないですかね。 19:24 映画とか、ゲームとか。 19:26 世界観。ですね。 19:30 攻殻機動隊の立ちコマっていうのがありますけど。 19:33 それの原型みたいな映画。ありますね。 19:36 装甲車みたいな感じだけど。 19:39 そしてまあ、世界が破滅するっていうね。 19:46 破滅して、そこから再生していくっていう。 19:54 ストーリーを含めて。 19:57 まあ、同じようになったら怒られるけど。 20:02 そういう設定の物語。 20:05 今、非常にたくさんありますね。 20:07 最近、Amazonでシーズン2が始まりました。 20:12 フォールアウト。 20:13 フォールアウトっていうのも始まりましたね。 20:17 あれも非常に面白いですね。 20:21 世界観はある意味似てるのかもしれない。 20:25 まあ、だいぶ違うんだけど。 20:28 非常に、これはゲームにフォールアウトっていうのが。 20:32 フォールアウトっていうのがあるらしいんですけど。 20:38 まあ、どっちが先か。 20:41 ちょっとこれ、おそらくこれは。 20:46 そういう意味では画期的な本なのかもしれない。 20:50 非常に面白い。面白いです。 20:59 4巻までようやくやりました。 21:05 それから、それから、例の。 21:17 龍と苺ですね。19巻。 21:20 柳本光晴さん。 21:22 これ、クライマックスなんで。 21:31 ちゃんと、最後までやります。 21:33 20巻まで出てるのかな。 21:36 これも、これも面白いですよね。 21:38 もう一つは。 21:42 これ。 21:43 これ、安野貴博さんのサーキットスイッチ。 21:52 ちょっとこれも、どんなもんかを確認しようと思って借りてます。 22:00 まあ、そういうことで。 22:08 ひとり読書会。 22:10 まあ、そういうことで。 22:13 まあ、面白いということ。 22:15 AKIRAが面白い。 22:16 龍と苺も面白い。 22:18 サーキットスイッチは、どんなものかを確認するというところです。 22:25 はい、以上です。 22:28 えー、終わりにし、終わりにします。 22:37 片付けて、歩きましょう。 22:41 ああ、やったね。 22:57 今先の鴨の三羽が、どんどん飛んできました。 23:05 かわし、かわしのほとんどに。 23:10 こちらはカラスが、今、鳴いてましたね。 23:16 あれは、ナンキンハゼかも。 23:35 御幸橋ヒロデンが行ってます。 23:37 さあ、片付けましょう。 23:45 ちょっとね、手持ち撮影なので、・・・えー・・・どうなってるかな。 24:23 ちょっと置きました。立てかけました。 24:48 ベンチの隙間にですね。 25:01 カラスが、鳴いてますね。 25:05 ここは俺の領分だって。 25:08 怒ってるんかもしれません。 25:10 さあ、・・・・・・はい。 26:08 よいしょ。立ち上がった。ようやく 26:21 行きましょう。 26:39 これは何かな。何か鳴きましたね。 27:26 まあ、これぐらいで、今日のところは。 27:51 はい。 28:02 (カラスの鳴き声)・・・あー 28:21 (カラスが)2羽いますね。 28:30 こちらが鳴いてました。 28:31 ああ、飛びましたね。 28:49 さあ、やはりナンキンハゼですね。 29:06 こんな風な実になってます。 29:20 さあ、第六船着き場ですね。 29:39 1、2、3、4、5、6。 29:42 1、2、3、4、5、6。 29:45 六段目ぐらいまで、上がってきてますね。 29:49 やはり、満ちてますね、これは。 30:17 帰ってますかね。 30:37 さあ、帰りましょう。 30:40 寒くなってきました。 30:47 これが、目立つんですけどね。 31:15 いつも何かここら辺、あるので、何かなと。 31:26 これもセンサー。 31:42 カラスが、鳴いてたカラスが、飛んでいきましたね。 32:28 西岸の方に。 32:34 二羽で。 32:37 ずっと、二羽で行動してますね。 32:51 さあ、第七ですね。 32:53 第七船着き場。 33:16 ここは、二段ぐらいは見えてるね。 33:54 さあ、ナンキンハゼですね。 34:19 これも、ナンキンハゼの実です。 34:28 だいぶ、掃き寄せられてますね、ここもね。 35:32 さあ、第八船着き場。 35:34 最後の船着き場に、到着しました。 35:40 ああ、いましたね。 35:44 ハクセキレイですよ。 35:54 残念。 35:56 逃しちゃった。 35:58 もう、いないだろうと思ったら、いるんだね、ハクセキレイは。 36:02 ハクセキレイが、一番いるんだね。 36:10 さあ、一、二、三、四、五、六段目か。 36:26 ちょっと、横から、もう一度よく見て。 36:42 一、二、三、四、五、六です。 36:45 そうですね、もうすぐ、五段目に、また、来ますね。 36:48 満ちてるね。 36:50 まあ、これで、三段ぐらい。 36:54 五段だと、六、七、八段ぐらいまで、見えてますね。 36:59 満ちてきてます。 37:03 足跡があるな、ここ。 37:15 土の、中に入ってる。 37:18 さあ。 37:23 さあさあさあ。 37:25 終わりにしましょう。 37:27 はい。 37:30 これで、終了しまーす。 37:32 ご視聴ありがとうございます、いつも。 37:35 お疲れ様でした。 37:37 失礼しまーす。