47
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RustとAIで、空の雲が「うんこ型」かどうか真剣にブラウザで推論する

47
Last updated at Posted at 2025-12-08

面白かったらシェア、いいねよろしくお願いします!

空見てる?

Generated Image December 06, 2025 - 5_15PM.jpeg

みなさんは空を見ることは好きですか?
僕は太陽を見ると眩しくてくしゃみが出ますが好きです。

それにしても雲って面白いですよね。
一つとして同じ形はありません。

あの戦士シュタルクもこう言いました。
image.png

そう、雲は時にお下品な形にもなります。

面白いですね。

ということで、撮影された雲の形がどれだけうんこに似ているかを計測するアプリを作ります。(作りながら記事を書いている)

ちなみに、クソアプリアドベントカレンダーでは下ネタを許可されているので僕は堂々とクソアプリを公開できます。

どんな内容のものでも構いません。それこそ下ネタでも大いに結構ですが、個人や特定の組織などを誹謗・中傷や名誉を害するようなものは投稿しないでください。

成果物

PC・スマホのブラウザで動きます!

雲の形を取得する

image.png

ひとことに雲といっても撮像環境によって色味が大きく変わって見えるでしょう。
ルールベースで白色をマスクしてもいいのですが、これだと不安定ですし面白みがありません。
ここは流行りの AI に処理をしてもらいましょう。

使用したデータセットはSWIMSEGです。

ダウンロードにはフォームで利用方法を回答する必要があるので「記事の執筆のため」とし、無事ダウンロードできました。

このデータセットは1013件の雲パッチ画像とそのマスクのペアです。
このデータを使ってモデルをトレーニングしていきます。

image.png

モデルはU-Netを11エポック回しました。LLMが吐いたコードでそのまま動きました。

image.png

貧乏なので無料Colab GPUでトレーニングしました。
モデルはtensorflow.js形式で保存します。
なぜかというと、ユーザーのブラウザで推論させたいからです。
GPUサーバーを立てると毎月$50ほど飛びますからね。

image.png

パターンマッチング

さて、雲の範囲をマスクで得られたとしても、それがうんこ型であるかは分かりません。
ここで問題なのが、向きとサイズが全くわからないということです。

幸いなことにセグメンテーションは綺麗に行えているので比較的実装が簡単なHuモーメントで計算します。

簡単に説明すると、「回転、サイズに関わらず同じ形のシルエットなら同じ値になる特徴記述子」です。

回転とスケールに頑健なアルゴリズムとしてAKAZEとSIFTがありますが、ブラウザで動かすための実装が大変でした。(画像処理エンジニア検定エキスパート合格者なのに情けない)

OpenCVに依存すればAPIを呼ぶだけなのですが、ブラウザ向けにはオーバースペックだったので Rustで自前実装し、wasm-bindgenで呼び出します。

検出したブロブを取り出してそれぞれHuモーメントでスコアを計算していきます。
現在の指標だと 大体0.005を超えたら「かなりうんこ」 です。

ちなみに、テンプレートとして使用している画像はこれです。
高得点を目指したい場合はこの形の雲を探すとよいでしょう。

template.png

wasmで公開している関数は一つだけです。
細かく呼び出す方がオーバーヘッド大きいという噂なのでコアロジックを固めています。

use wasm_bindgen::prelude::*;
mod hu_moments_matching;

#[wasm_bindgen]
pub fn hu_moments_matching(
    template_width: u32,
    template_height: u32,
    template_rgba: Vec<u8>,
    mask_width: u32,
    mask_height: u32,
    mask_rgba: Vec<u8>,
    rgb_threshold: u8,
    min_area: u32,
    min_similarity: f64,
) -> Result<JsValue, JsValue> {
    hu_moments_matching::hu_moments_matching(
        template_width,
        template_height,
        template_rgba,
        mask_width,
        mask_height,
        mask_rgba,
        rgb_threshold,
        min_area,
        min_similarity,
    )
}

できたもの

雲が茶色にセグメンテーションされ、うんこが検出されると緑のクロスヘアが表示されます。

image.png

Huモーメントは回転に頑健なので、回転させても判定が可能です。

image.png

推論速度は M4 Macbook AirのChromeで1秒かからない程度でした。

今後の展望

ブリストルスケールに対応した形状の分類を行うことができるともっと面白そうです。

本当はやりたかったのですが、雲の種類の分類が難しかったため断念しました。
ルールベースで行うには複雑で、機械学習ベースで行うには適したデータが見つかりませんでした。
手動でのアノテーションをするほどクソアプリに手間はかけられないです。

image.png

おまけ

何でもかんでもLLMに投げるこの時代だからこそTransformerを使わずに、そして古き良きルールベースに挑戦したかったのです。

開発はもうLLM任せで良いのかもしれませんが、実行時にどれだけエコであるかはこだわり続けるべきなのかなと思ったりします。

例えばこのアプリが「毎回サーバーに画像を送信して、LLMに送信する」仕組みだったら...
レスポンスまでの時間は長く、呼び出しの度にコストがかかり、バックエンドを用意する手間もかかるでしょう。

これがビジネスだと「やっぱり分類も行いたい」といった要求があとから出てくるかもしれないので、仕組みと性能と開発スコープが完全にコントロールできる個人開発でしかなし得ないことではありますが...

ここまで読んだあなたへ

あなたは「うろこ雲を見た時にコロコロうんちを連想する呪い」にかかりました。

47
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?