Help us understand the problem. What is going on with this article?

カラーコードによる自己組織化マップをVue.jsで実装してみた

More than 1 year has passed since last update.

池谷裕二さんの「単純な脳、複雑な「私」」を読みました。
この本の最後のほうで、自己組織化マップについての話があったので、Vue.jsを使って実装してみました。
ソースコード、およびWebページはGithubで公開しています。

image.png

w(幅)、h(高さ)を指定してinitボタンで初期化。
step(処理回数)を指定してexecuteボタンを押すと指定回数処理を繰り返した結果を表示します。
10×10で1000ステップくらい実行するとグラデーションっぽい感じになる。つまり、近い色が集まるようになります。
マップサイズやステップ数が大きくなると処理に時間がかかります。

image.png

自己組織化マップとは

わかりやすい解説は池谷さんのWebページで見ることができます。
アルゴリズム的には4つのステップに分かれています。

0.初期化。ランダムにマップを配置
1.選択。ランダムに色を決定
2.検索。マップの中から1で決めた色に一番近いセルを検索。
3.暴露。2で見つかったセルとその8近傍のセルに色を混ぜる。

1~3を繰り返す。

ソースコード(抜粋)

Map.vue
export default {
  data () {
    return {
      width: 10,
      height: 10,
      count: 1000,
      cells: []
    };
  },
  created () {
    this.init();
  },
  methods: {
    init: function () { //0.初期化
      this.cells = [];
      for (let y = 0; y < this.height; y++) {
        this.cells.push([]);
        for (let x = 0; x < this.width; x++) {
          this.cells[y].push(new Cell());
        }
      }
    },
    execute: function () { //1~3を指定回数実行する
      for (let i = 0; i < this.count; i++) {
        // 1.選択
        let r = Math.floor(Math.random() * 255);
        let g = Math.floor(Math.random() * 255);
        let b = Math.floor(Math.random() * 255);
        let bmu = this.searchBMU(r, g, b);
        this.expose(bmu, r, g, b);
      }
    },
    searchBMU: function (r, g, b) { //2.検索
      let bmu = {
        x: 0,
        y: 0,
        distance: this.cells[0][0].calcColorDistance(r, g, b)
      };
      for (let y = 0; y < this.height; y++) {
        for (let x = 0; x < this.width; x++) {
          let distance = this.cells[y][x].calcColorDistance(r, g, b);
          if (distance < bmu.distance) {
            bmu.x = x;
            bmu.y = y;
            bmu.distance = distance;
          }
          if (distance === 0) {
            break;
          }
        }
      }
      return bmu;
    },
    expose: function (bmu, r, g, b) { // 3.暴露
      for (let h = -1; h <= 1; h++) {
        for (let w = -1; w <= 1; w++) {
          let x = Math.min(Math.max(bmu.x + w, 0), this.width - 1);
          let y = Math.min(Math.max(bmu.y + h, 0), this.height - 1);
          this.cells[y][x].mixColor(r, g, b, 0.1); // 色の混合比率は0.1
        }
      }
    }
  }
};
Cell.js
export default class Cell {
  constructor () {
    this.r = Math.floor(Math.random() * 255);
    this.g = Math.floor(Math.random() * 255);
    this.b = Math.floor(Math.random() * 255);
  }
  /**
   * スタイルオブジェクトの取得(背景色)
   * @return Object スタイルオブジェクト
   */
  getStyle () {
    return {
      'background-color': `rgb(${this.r},${this.g},${this.b})`
    };
  }

  /**
   * セルの色と引数の色との距離を計算する
   * @param  Number r red
   * @param  Number g green
   * @param  Number b blue
   * @return Number   色距離
   */
  calcColorDistance (r, g, b) {
    return Math.pow((this.r - r), 2) +
           Math.pow((this.g - g), 2) +
           Math.pow((this.b - b), 2);
  }

  /**
   * 現在のセルの色に指定色を混ぜる
   * @param  Number r     red
   * @param  Number g     green
   * @param  Number b     blue
   * @param  Number ratio 混色比率(0~1.0)
   * @return void
   */
  mixColor (r, g, b, ratio) {
    this.r = Math.floor(this.r * (1 - ratio) + r * ratio);
    this.g = Math.floor(this.g * (1 - ratio) + g * ratio);
    this.b = Math.floor(this.b * (1 - ratio) + b * ratio);
  }
}

frost_star
まだまだ半人前プログラマー。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした