3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Twitterの飯テロ画像をブロックするchrome拡張機能を作った

Posted at

駆逐してやる...!飯テロ画像を...1枚残らず...!

Twitterに蔓延る飯テロ画像、許すまじ。
という事で、Twitter上の飯テロ画像を機械学習で検知し、ブロックするクローム拡張機能を作りました。

画像のような食欲をそそるラーメンも...
meshi-tero

このとおり!きれいに隠すことができます!
before after

拡張機能としてリリースしているので、よろしければこちらのリンクからDLしてください!
Chrome拡張機能 - 飯テロブロッカー

ソースコードも公開中です。
https://github.com/Nemurino-kai/FoodPornBlocker

以下、拡張機能の仕組みなどについて、技術的な話をしていきます。

導入したライブラリ

次の外部のライブラリを導入しました。

  • ml5.js
    • Tensorflowをjavascript上で動かすことができます。
  • jQuery
  • HTML操作のため。

大まかな仕組み

1.ドメインがtwitter.comならjsを起動、ページを監視
2.ページに変化があったら、ページの画像部分を抽出してくる
3.画像をImageNetで学習したMobileNetに入力し、クラス分類する。
4.分類されたクラスが食品なら、画像を置き換える。食品でなければ、そのまま表示

1.ページを監視する

var observer = new MutationObserver(replace_image);
observer.observe(document, {
    childList: true,
    subtree: true,
});

MutationObserverは、「Mutation(変化)」を「Observe(監視)」するオブジェクトです。
変化があったとき、ここではreplace_image関数が実行されます。

2.ページに変化があったら、ページの画像部分を抽出してくる

function replace_image() {
    $('div').each(function(){
        if (this.parentNode && (this.parentNode.getAttribute("aria-label")=="画像"||this.parentNode.getAttribute("aria-label")=="Image") && !this.classList.contains('processed')){
            this.classList.add('processed');
            var image_url = this.style.backgroundImage.match(/\"(.+)\"/)[1]
            console.log("loaded:" + image_url);
            // いったん隠す
            this.style.backgroundImage = 'url()';

ページ内で、親ノードのaria-labelが"画像"or"Image"である要素を探します。
この条件に当てはまるノードが、画像へのリンクを持っています。
無駄な処理を避けるため、処理済のelementには'processed'クラスを付与し、繰り返し処理を行わないようにしています。

その後、elementから画像のurlを取得し、一旦画像を隠します。

3.画像をImageNetで学習したMobileNetに入力し、クラス分類する。

            app(image_url).then(
              (answer) =>{
                if(isFood(answer)){
                    this.style.backgroundImage='url(' + chrome.runtime.getURL("replace.jpg") + ')';
                }else{
                    this.style.backgroundImage='url(' + image_url + ')';
                }
              }
            )

次は取得した画像urlをapp関数に入れます。app関数は画像のurlを入力として、予測クラスを返り値とする関数です。

ではここで、app関数を確認してみましょう。

async function app(set_src) {
    
    const model_url = chrome.runtime.getURL("mobilenet_v1_025_224/model.json")

    const classifier = ml5.imageClassifier(model_url, modelLoaded);

    console.log("seted:" + set_src);
    
    // 画像分類器に入れるelementの生成
    let imgEl = document.createElement('img');
    //CORSに引っかからないように
    imgEl.crossOrigin = "anonymous"
    imgEl.src = set_src

    var answer

    await classifier.classify(imgEl)
    .then(results => {
        console.log("classified:"+set_src);
        console.log(results[0].label);
        answer = results[0].label;
    });

    return answer
    
}

まず初めに、ローカルに保存しておいたMobileNetのモデルをロードします。(モデルはこちらからDLできます
次に分類器に入力するためのElementを作成します。ml5.jsでは、imgタグをそのまま入力してあげれば、結果を返してくれます。(便利!)
このElementを分類器に入れればおkです。

4.分類されたクラスが食品なら、画像を置き換える。食品でなければ、そのまま表示

            app(image_url).then(
              (answer) =>{
                if(isFood(answer)){
                    this.style.backgroundImage='url(' + chrome.runtime.getURL("replace.jpg") + ')';
                }else{
                    this.style.backgroundImage='url(' + image_url + ')';
                }
              }
            )

app関数の実行後、予測クラスをisFood関数に入力しています。isFood関数は、予測クラスを入力し、それが食品であるかの真偽値を返す関数です。
isFoodが真であれば、飯テロ画像として、画像のurlを置き換えます。
isFoodが偽であれば、飯テロ画像ではないので、画像のurlを元に戻します。よって、画像は普通に表示されます。

おわりに

機械学習を手軽にWeb開発に組み込める、ml5.js、他にも色々な使い道があって面白そうです。夢が膨らみますね✨

3
1
0

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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?