◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り34日。API 連携を足したアプリは移行先の確認を●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SONNET 4.5 — Claude API での提供終了は 11/30、残り34日。API 連携を足したアプリは移行先の確認を●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/アプリ開発
◇ アプリ開発/2026-07-29上級

壁紙カタログに同じ絵が二度並んでいた — 知覚ハッシュの閾値を324枚で実測して決める

画像カタログの重複検出を、SHA-256・dHash・色相署名・ブロック署名の4通りで実測しました。dHash 単独では適合率0.9%。平坦な画像でハッシュが潰れる現象と、閾値ではなく正解ラベルの方が間違っていた顛末を、再現できるコードと数値で共有します。

画像処理4知覚ハッシュdHash重複検出アセット管理Node.jssharp個人開発229

✦ プレミアム記事

朝、自分の壁紙アプリのカタログ画面をスクロールしていて、指が止まりました。

同じ絵が、少し離れた位置に二度並んでいます。

片方は初期に入れたもの、もう片方は後から別バッチで追加したもの。ファイル名も追加日も違うので、これまで一度も気づきませんでした。個人開発で数千枚のアセットを扱っていると、こうした取りこぼしが静かに積み上がっていきます。

App Store のレビューで指摘されたわけではありません。それでも、お金を払って使ってくださっている方の画面に同じ絵が二度出るのは、避けたいところでした。

手作業で全部見比べる選択肢はありません。機械で見つける仕組みを入れることにしました。

その過程で、事前に思い描いていた設計は二度ひっくり返りました。以下、実際に測った数字とともに残しておきます。

検証セットを手元に切り出す

本番カタログをそのまま実験台にすると、結果を後から検証できません。挙動を数字で確かめられるよう、同じ性質を持つ検証セットを合成しました。

1290×2796(iPhone の縦解像度)の JPEG を160枚。中身はグラデーション・ぼかしたブロブ・ストライプ・ノイズ雲の4種類を40枚ずつ用意しました。壁紙カタログにありがちな構成をなぞっています。

そこから、意図的に5種類の派生を作りました。

派生の種類枚数正解の扱い
JPEG 品質92→74 で再エンコード54重複
1290×2796 → 828×1792 にリサイズ32重複
明度を6%上げる23重複
上下左右を2%クロップして戻す15重複
色相を80度回す40別物

合計324枚。最後の色相変種を「別物」に置いたところが、この検証の肝になります。壁紙アプリでは色違いこそが並べたい商品であって、統合されては困ります。

環境は Node 22 系と sharp(libvips 経由)です。以降の数字は全てこの構成での実測です。

なお、公開当初は sharp の版数を「8.18.3」と書いておりましたが、これは libvips 側の番号との取り違えでした。sharp 本体の版は 0.3x 系で、8.x という番号は libvips のものです。版の数字は再現の手がかりになるだけに、誤ったまま残したくありませんでした。

SHA-256 から始めて、すぐ行き詰まる

最初に試したのはファイルのバイト列に対する SHA-256 でした。実装は数行で済みますし、まずは完全一致だけでも掃除できるはずと考えていました。

結果は、真の重複124組のうち検出できたのは3組。再現率2.4%です。

理由は考えてみれば当たり前でした。JPEG は再エンコードした時点でバイト列が変わります。リサイズも明度調整もクロップも同様です。バイト一致で拾えるのは「同じファイルを二度アップロードした」ケースだけで、そのケースはアップロード時のガードで既に潰してありました。

残っていたのはまさに「見た目は同じだがバイトは違う」ものばかりで、ハッシュの完全一致はその全てを素通りさせます。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦SHA-256 による完全一致は、再エンコードやリサイズを挟んだ124組の重複のうち3組しか拾えず再現率2.4%でした。バイト一致がなぜ役に立たないのかを数字で示します
✦dHash 単体を閾値10で回すと再現率97.5%・適合率0.9%(誤検出16,570組)。原因は元画像160枚のうち80枚が「情報量ゼロのハッシュ」に潰れていたことでした。popcount ゲートで誤検出が0組になるまでの過程を全て掲載します
✦自動統合・目視レビュー・別物の3バンドに分ける判定器の実装全文と、324枚 6.67秒(20.6 ms/枚)の実測。取りこぼし0組・自動統合帯の適合率96.9%まで詰めた設定値をそのまま使えます
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

◇ アプリ開発2026-10-26
段階公開の最初の5%で見えた Crash-free 99.7%、何ユーザーから信じてよいのか
段階公開 5% の Crash-free 率は、母数が小さいほど区間が広く、進む・止めるの根拠になりません。Wilson 区間で「進む・待つ・止める」を判定する Python と、毎回見ると誤って止める確率の実測をまとめます。
◇ アプリ開発2026-09-10
Rork のリポジトリに置く最初の EAS Workflow と、失敗した回にだけ届かない通知
Rork から書き出したリポジトリに .eas/workflows を二本置くまでの手順と、needs でつないだ通知が失敗した回にだけ届かなくなる理由を、手元で走る検査スクリプトの実行結果つきで書き残します。
◇ アプリ開発2026-09-07
アプリから外部の AI にユーザーの文章を送るとき、Play の「データの安全性」に何を書くか
外部の AI にユーザーの入力を渡すアプリで、Play のデータ安全性フォームの収集・共有・一時処理をどう区分するか。送信を一箇所に集める実装と、順序を誤ると消し漏れるマスキングの実測を添えて整理します。