AI・機械学習チームの鴨田です。この記事はAI・機械学習チームブログリレーの12日目の記事です。11日目は池嶋さんによる「Agentic MLOpsで加速する機械学習開発」でした。
娘の影響でYoutubeで「シナぷしゅ」を見ることが多くなったのですが、毎月更新される月歌(その月のテーマソング)とそれと共に投稿されるパパ・ママ向け解説動画が楽しみになりました。プロデューサーが直接こだわりを解説していて内容が濃くおすすめです。

記事要約
- Facebook/Meta AIの画像セグメンテーションモデル「SAM3」を使って猫の画像からMaskを抽出
- 抽出したMaskをマトリックス・コードのアニメーションと組み合わせて動く猫のシルエットを表現
きっかけ
YouTube*1を見ていたら、マトリックス・コードで猫のシルエットが表現されているTシャツを着ている人を発見しました。
「これ、手元で実現できないかな?」と考えていたところ、ちょうど以前申請していたFacebook/Meta AIのSAM3(Segment Anything Model 3)のモデル利用許可メールが届きました。
そこで、次のアプローチで実現しました。
- SAM3を使って猫の画像から猫のMaskを抽出
- マトリックス・コード生成ツールを改修してMask領域を描画しないようにする
- 猫のシルエットが浮かび上がるマトリックス・コードアニメーションを完成させる
SAM3とは
SAM3(Segment Anything Model 3)は、Meta AI Researchが2025年にリリースした最新の画像・動画セグメンテーションモデルです。主な特徴は次の通りです。
SAM3の主な特徴
1. Promptable Concept Segmentation
SAM3の最大の特徴は、テキストプロンプトによるセグメンテーションです。従来のSAMでは点やボックスを指定する必要がありましたが、SAM3では「cat」のようなテキストを与えるだけで、画像内の該当するオブジェクトを自動でセグメンテーションします。
「cat」と指示すると、猫の範囲全体をMaskします。「ear」と指示すると生き物の耳をちゃんと認識して、インスタンスごとにMaskが生成されます。

2. 画像と動画の両対応
SAM3は静止画だけでなく、動画のセグメンテーションにも対応しています。動画内のオブジェクトを追跡しながらフレームごとにMaskを生成できるため、今回のような動的なアニメーション作成にも活用できます。
3. ゼロショット学習
事前学習済みモデルを使うだけで、特定のドメインに対するファインチューニングなしで高精度なセグメンテーションができます。
詳細はHugging Faceのモデルページを参照してください。
実装:SAM3でMaskを抽出
環境セットアップ
まず、必要なライブラリをインストールします。
!pip install -U transformers !pip install -U av
SAM3は利用申請が必要なモデル(gated model)のため、Hugging Faceでモデルページにアクセスしてライセンスに同意する必要があります。その後、トークンを使ってログインします。
from huggingface_hub import login login(token="YOUR_HF_TOKEN")
静止画からのMask抽出
次のコードで猫のMaskを抽出します。プロンプトには「cat」を使用します。
from transformers import Sam3Processor, Sam3Model import torch from PIL import Image device = "cuda" if torch.cuda.is_available() else "cpu" # モデルとプロセッサの読み込み model = Sam3Model.from_pretrained("facebook/sam3").to(device) processor = Sam3Processor.from_pretrained("facebook/sam3") # 画像の読み込み image = Image.open("cat_image.jpg").convert("RGB") # テキストプロンプトでセグメンテーション inputs = processor(images=image, text="cat", return_tensors="pt").to(device) with torch.no_grad(): outputs = model(**inputs) # 後処理 results = processor.post_process_instance_segmentation( outputs, threshold=0.5, mask_threshold=0.5, target_sizes=inputs.get("original_sizes").tolist() )[0] print(f"Found {len(results['masks'])} objects")
動画からのMask抽出
動画の場合は、SAM3VideoModelを使用します。
from transformers import Sam3VideoModel, Sam3VideoProcessor from transformers.video_utils import load_video model = Sam3VideoModel.from_pretrained("facebook/sam3").to(device, dtype=torch.bfloat16) processor = Sam3VideoProcessor.from_pretrained("facebook/sam3") # 動画の読み込み video_frames, _ = load_video("cat_video.mp4") # セッションの初期化 inference_session = processor.init_video_session( video=video_frames, inference_device=device, processing_device="cpu", video_storage_device="cpu", dtype=torch.bfloat16, ) # テキストプロンプトの追加 inference_session = processor.add_text_prompt( inference_session=inference_session, text="cat", ) # 全フレームを処理 outputs_per_frame = {} for model_outputs in model.propagate_in_video_iterator( inference_session=inference_session, max_frame_num_to_track=130 ): processed_outputs = processor.postprocess_outputs(inference_session, model_outputs) outputs_per_frame[model_outputs.frame_idx] = processed_outputs
これで、各フレームごとに猫のMaskが取得できます。
MaskをASCII artに変換
抽出したMaskをマトリックス・コード生成ツールで使えるよう、ASCII artに変換します。
import numpy as np from PIL import Image def generate_mask_ascii_art(masks, scale_factor=0.5, fill_char="#", bg_char=" "): """ Mask領域をASCII artとして出力 """ if hasattr(masks, 'cpu'): masks = masks.cpu().numpy() # 複数Maskを結合 if masks.ndim == 3: combined_mask = np.any(masks > 0, axis=0).astype(np.uint8) * 255 else: combined_mask = (masks > 0).astype(np.uint8) * 255 # リサイズ mask_img = Image.fromarray(combined_mask) orig_w, orig_h = mask_img.size aspect_correction = 0.5 # コンソール文字の縦横比補正 new_w = int(orig_w * scale_factor) new_h = int(orig_h * scale_factor * aspect_correction) resized_img = mask_img.resize((new_w, new_h), resample=Image.NEAREST) resized_mask = np.array(resized_img) # ASCII artに変換 aa_lines = [] for row in resized_mask: line = "".join([fill_char if val > 0 else bg_char for val in row]) aa_lines.append(line) return "\n".join(aa_lines) # ASCII artを生成してファイルに保存 ascii_art = generate_mask_ascii_art(results["masks"], scale_factor=1/7, bg_char=" ") with open("ascii_art.txt", "w") as f: f.write(ascii_art)

夕方に撮影者の影が重なる影響で、尻尾が欠ける程度の欠損はあるものの、シルエット全体としては猫と認識できる十分な精度でした。*2
茶トラの尻尾と背景が似ているため誤検出(False Positive)が多くなると思いましたが、むしろ逆で尻尾が消失していたのが面白い発見でした。
実装:マトリックス・コードと組み合わせ
OSSの選定と改修
マトリックス・コードのアニメーションには、unimatrixというOSSを使用しました。これはターミナル上で映画「マトリックス」のような緑色の文字が流れるアニメーションを表示するツールです。
このOSSを改修して、次の機能を追加しました。
1. Mask機能の追加
ASCII artファイルから#がある座標を読み取り、その座標では文字を描画しない。
def load_mask(filename): """ ASCII artファイルを読み込み、#がある座標のセットを返す """ mask_positions = set() try: with open(filename, 'r', encoding='utf-8') as f: for y, line in enumerate(f): for x, char in enumerate(line.rstrip('\n')): if char == '#': mask_positions.add((y, x)) except Exception as e: print(f"Warning: Could not load mask file '{filename}': {e}") return mask_positions
2. アニメーション機能の追加
ディレクトリ内の複数のASCII artファイルを順番に読み込んで、フレームアニメーションを実現します。
def load_mask_files(directory): """ ディレクトリ内のascii_art_*.txtファイルを番号順に読み込む """ pattern = str(Path(directory) / "ascii_art_*.txt") files = glob.glob(pattern) def extract_number(filepath): match = re.search(r'ascii_art_(\d+)\.txt$', filepath) return int(match.group(1)) if match else 0 files.sort(key=extract_number) return files
3. 描画処理の修正
Writerクラスに、Mask領域をスキップする処理を追加しました。
def is_masked(self, y, x): """ 指定座標がMask領域かチェック """ return (y, x) in self.mask_positions def draw(self, node): """ Mask領域では描画をスキップ """ y = node.y_coord x = node.x_coord if self.is_masked(y, x): return # Mask領域では何も描画しない # 通常の描画処理...
実施結果
猫のシルエットがマトリックス・コードの中に浮かび上がりました。

コード
今回作成したコードはMask含めてGitHubで公開しています。
余談:Google Colabのメモリ不足
動画のセグメンテーションを実行する際、Google Colabの無料枠ではメモリが不足してしまいました。SAM3VideoModelは動画の全フレームをメモリ上に展開するため、数分の動画でも数GBのメモリを消費します。
結局、Google Colab Proに課金してハイメモリランタイムを使用することで解決しました。もしメモリに制限がある場合は、次のような対策が有効です:
- 動画の解像度を下げる
- フレームレートを下げる(間引く)
- 処理するフレーム数を制限する(
max_frame_num_to_trackパラメータ)
# フレーム数を制限する例 for model_outputs in model.propagate_in_video_iterator( inference_session=inference_session, max_frame_num_to_track=50 # 最初の50フレームのみ処理 ): ...
まとめ
SAM3のPromptable Concept Segmentationを使うことで、「cat」という一言のプロンプトから猫のMaskを簡単に抽出できました。抽出したMaskをマトリックス・コードと組み合わせることで、猫のシルエットが浮かび上がる「cat matrix」を作成できました。
SAM3は画像処理の民主化を大きく前進させるツールだと感じました。従来はセグメンテーションに専門知識が必要でしたが、SAM3を使えば誰でも簡単に高精度なセグメンテーションが可能です。
皆さんもSAM3を使って、面白いビジュアル表現に挑戦してみてはいかがでしょうか。
We are hiring!
AI チームでは、最新の機械学習技術を用いて、実社会の複雑な課題解決に取り組むエンジニアを募集しています。 ご気軽にカジュアル面談からでも応募をお待ちしております。