dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

JavaScript で画像の各ピクセルの色の取得

2022-12-25 12:17:45 | javascript
JavaScript で画像の各ピクセルの色の取得する方法のメモ。

read_image() で画像を読み込み、画像を読み込み終えたら、
raw_image() でcanvas に画像を描画します。

そして、16 ピクセル x 16 ピクセル単位で色の平均値を計算し、
その色で枠を描画しています。

各ピクセルの r, g, b, a(透明度) は以下で取得することができます。
r = img_data.data[(x + y*w)*4];
g = img_data.data[1 + (x + y*w)*4];
b = img_data.data[2 + (x + y*w)*4];
a = img_data.data[3 + (x + y*w)*4];
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>image processing</title>
  </head>
  <body>
    画像処理
    <div id="img_area"></div>
  </body>
  &;lt;script type="text/javascript">
(() => {
  function draw_image(params) {
    const img_area_obj = document.getElementById(params.img_area);
    const img_obj = params.img_obj;

    const cv_obj = document.createElement('canvas');
    cv_obj.width = img_obj.naturalWidth;
    cv_obj.height = img_obj.naturalHeight;

    const ct = cv_obj.getContext('2d');
    ct.drawImage(img_obj, 0, 0);
    img_area_obj.appendChild(cv_obj);

    const img_data = ct.getImageData(0, 0, img_obj.width, img_obj.height);

    // 枠
    draw_cell_frame(ct, img_data, 16);
  }

  function draw_cell_frame(ct, img_data, size) {
    for (let y = 0; y < img_data.height; y += size) {
      for (let x = 0; x < img_data.width; x += size) {
        let avg_col = avg_cell_color(img_data, x, y, size);
        ct.strokeStyle = `#${avg_col[0]}${avg_col[1]}${avg_col[2]}`;
        ct.strokeRect(x, y, size, size);
      }
    }
  }

  function avg_cell_color(img_data, min_x, min_y, size) {
    const w = img_data.width;
    const h = img_data.height;
    const max_x = min_x + size <= w ? min_x + size : w;
    const max_y = min_y + size <= h ? min_y + size : h;

    let sum_r = 0, sum_g = 0, sum_b = 0;
    let pixels = 0;
    for (let y = min_y; y < max_y; y++) {
      for (let x = min_x; x < max_x; x++) {
        pixels++;
        let r = img_data.data[(x + y*w)*4];
        let g = img_data.data[1 + (x + y*w)*4];
        let b = img_data.data[2 + (x + y*w)*4];

        sum_r += r;
        sum_g += g;
        sum_b += b;
      }
    }

    const avg_r = Math.floor(sum_r / pixels);
    const avg_g = Math.floor(sum_g / pixels);
    const avg_b = Math.floor(sum_b / pixels);

    return [avg_r.toString(16), avg_g.toString(16), avg_b.toString(16)];
  }

  function read_image(params) {
    const img_obj = new Image();
    params.img_obj = img_obj;
    img_obj.onload = (() => {
      draw_image(params);
    });
    img_obj.src = params.img_url;
  }

  read_image({
    img_area: 'img_area',
    img_url: 'test.png',
  });
})();
  </script>
</html>


BigQuery で array にデータを追加

2022-12-15 23:47:44 | python
BigQuery で array にデータを追加する方法のメモ。

■テーブル定義
create table test1.array_test1 (
  id        string,
  features  array<struct<key string, value string>>
);

■データ登録
insert into test1.array_test1 (id, features) values ('id_01', [struct('key_01' as key, 'value_01' as value)]);

■データ更新(array にデータを追加)
update
  test1.array_test1
set
  features = array_concat(features, [struct('new_key_01' as key, 'new_value_01' as value)])
where
  id = 'id_01'
;

■テーブル登録内容確認
id_01    key_01        value_01
         new_key_01    new_value_01

■データ登録
insert into test1.array_test1 (id) values ('id_02');
■データ更新
select ndores = array_concat(ifnull(features, []), [struct('new_key_02' as key, 'new_value_02' as value)])
where
  id = 'id_02'
;

■テーブル登録内容
id_01    key_01        value_01
         new_key_02    new_value_01
id_02    new_key_02    new_value_02


Elasticsearch で数値のフィールドの値によるスコアリング

2022-12-11 13:46:35 | elasticsearch
Elasticsearch で数値のフィールドの値によるスコアリングのメモ。
value フィールドの値の重みを変更してスコアがどう変わるかを確認します。

■インデックス定義
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "id": {"type": "keyword", "store": "true"},
      "title": {"type": "text", "store": "true"},
      "body": {"type": "text", "store": "true"},
      "value": {"type": "float", "store": "true"}
    }
  }
}

■クエリパターン
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "should": [
            {"match": {"title": {"query": "abc", "boost": 【title_boost】}}},
            {"match": {"body": {"query": "abc", "boost": 【body_boost】}}}
          ]
        }
      },
      "functions": [
        {"field_value_factor": {
          "field": "value",
          "modifier": "none",
          "factor": 【value_factor】
        }}
      ],
      "score_mode": "sum",
      "boost_mode": "sum"
    }
  },
  "_source": ["id", "title", "score"]
}

■title_boost: 1.0、body_boost: 1.0、value_factor: 0.0 の場合
    "hits" : [
      {
        "_index" : "idx2",
        "_id" : "doc_01",
        "_score" : 2.059239,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品1 abc社"
        }
      },
      {
        "_index" : "idx2",
        "_id" : "doc_02",
        "_score" : 2.059239,
        "_source" : {
          "id" : "doc_02",
          "title" : "商品2 abc社"
        }
      }
    ]

■title_boost: 1.0、body_boost: 1.0、value_factor: 1.0 の場合
doc_01 の value の値(1.0)、doc_02 の value の値(2.0)が加算されています。
    "hits" : [
      {
        "_index" : "idx2",
        "_id" : "doc_02",
        "_score" : 4.059239,
        "_source" : {
          "id" : "doc_02",
          "title" : "商品2 abc社"
        }
      },
      {
        "_index" : "idx2",
        "_id" : "doc_01",
        "_score" : 3.059239,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品1 abc社"
        }
      }
    ]

■title_boost: 1.0、body_boost: 1.0、value_factor: 10.0 の場合
doc_01 の value の値(1.0)、doc_02 の value の値(2.0)の 10倍の値が加算されています。
    "hits" : [
      {
        "_index" : "idx2",
        "_id" : "doc_02",
        "_score" : 22.059238,
        "_source" : {
          "id" : "doc_02",
          "title" : "商品2 abc社"
        }
      },
      {
        "_index" : "idx2",
        "_id" : "doc_01",
        "_score" : 12.059238,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品1 abc社"
        }
      }
    ]


Elastcisearch でフィールド毎に重みづけしたスコアリング

2022-12-10 23:43:00 | elasticsearch
Elastcisearch でフィールド毎に重みづけして検索を行う方法のメモ。
■検索クエリパターン
title、body の各フィールドに対して、スコアにそれぞれ title_boost、body_boost を掛け、その結果を加算したものが最終的なスコアとなります。
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "should": [
            {"match": {"title": {"query": "abc", "boost": 【title_boost】}}},
            {"match": {"body": {"query": "abc", "boost": 【body_boost】}}}
          ]
        }
      },
      "score_mode": "sum",
      "boost_mode": "sum"
    }
  }
}

■title_boost: 0.0、body_boost: 0.0 での検索結果
スコアは 0.0 となっています。
    "hits" : [
      {
        "_index" : "idx1",
        "_id" : "doc_01",
        "_score" : 0.0,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品 abc"
        }
      }
    ]

■title_boost: 1.0、body_boost: 0.0 での検索結果
スコアは 1.540445 となっていて、これが title にマッチした場合のスコアとなります。
    "hits" : [
      {
        "_index" : "idx1",
        "_id" : "doc_01",
        "_score" : 1.540445,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品 abc"
        }
      }
    ]

■title_boost: 0.0、body_boost: 1.0 での検索結果
スコアは 1.4916282 となっていて、これが body にマッチした場合のスコアとなります。
    "hits" : [
      {
        "_index" : "idx1",
        "_id" : "doc_01",
        "_score" : 1.4916282,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品 abc"
        }
      }
    ]

■title_boost: 10.0、body_boost: 0.0 での検索結果
スコアは 15.404451 で、title_boost: 1.0 の場合(1.540445)の 10倍の値となっています。
    "hits" : [
      {
        "_index" : "idx1",
        "_id" : "doc_01",
        "_score" : 15.404451,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品 abc"
        }
      }
    ]

■title_boost: 10.0、body_boost: 1.0 での検索結果
スコアは 16.89608 で、title_boost: 10.0、body_boost: 0.0 の場合のスコア(15.404451)と、title_boost: 0.0、body_boost: 1.0 の場合のスコア(1.4916282)の和となっています。
    "hits" : [
      {
        "_index" : "idx1",
        "_id" : "doc_01",
        "_score" : 16.89608,
        "_source" : {
          "id" : "doc_01",
          "title" : "商品 abc"
        }
      }
    ]


Elasticsearch で aggs を用いた facet 検索

2022-12-04 11:54:28 | elasticsearch
Elasticsearch で aggs を用いた facet 検索

Elasticsearch で特定の属性を指定せずに aggs でファセット検索を行う方法のメモ。
features に属性毎に key、value を持たせていますが、
検索する際にはファセットを表示する際の属性名(name)、選択肢(option)を使用します。

■インデックス定義
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "id": {
        "type": "keyword",
        "store": "true"
      },
      "features": {
        "type": "nested",
        "properties": {
          "key": {"type": "keyword"},
          "name": {"type": "keyword"},
          "value": {"type": "keyword"},
          "option": {"type": "keyword"}
        }
      }
    }
  }
}

■データ例
{ 
  "id": "doc_1",
  "features": [
    {"key": "maker",
     "value": "aaa",
     "name": "メーカー",
     "option": "AAA社"},
    {"key": "material",
     "value": "gold",
     "name": "材質",
     "option": "ゴールド"},
    {"key": "price",
     "value": "2500",
     "name": "価格",
     "option": "2,001円 ~ 3,000円"}
  ]
}

■検索
{
  "size": 0,
  "aggs": {
    "keys": {
      "nested": {
        "path": "features"
      },
      "aggs": {
        "by_name": {
          "terms": {
            "field": "features.name",
            "size": 5
          },
          "aggs" : {
            "by_option": {
              "terms": {
                "field": "features.option",
                "size": 5
              }
            }
          }
        }
      }
    }
  }
}

■検索結果
{
  ...,
  "aggregations" : {
    "keys" : {
      "doc_count" : 18,
      "by_name" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 0,
        "buckets" : [
          {
            "key" : "メーカー",
            "doc_count" : 6,
            "by_option" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "AAA社",
                  "doc_count" : 2
                },
                {
                  "key" : "BBB社",
                  "doc_count" : 2
                },
                {
                  "key" : "CCC社",
                  "doc_count" : 2
                }
              ]
            }
          },
          {
            "key" : "価格",
            "doc_count" : 6,
            "by_option" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "1,001円 ~ 2,000円",
                  "doc_count" : 3
                },
                {
                  "key" : "2,001円 ~ 3,000円",
                  "doc_count" : 2
                },
                {
                  "key" : "~ 1,000円",
                  "doc_count" : 1
                }
              ]
            }
          },
          {
            "key" : "材質",
            "doc_count" : 6,
            "by_option" : {
              "doc_count_error_upper_bound" : 0,
              "sum_other_doc_count" : 0,
              "buckets" : [
                {
                  "key" : "ゴールド",
                  "doc_count" : 2
                },
                {
                  "key" : "シルバー",
                  "doc_count" : 2
                },
                {
                  "key" : "スチール",
                  "doc_count" : 1
                },
                {
                  "key" : "ブロンズ",
                  "doc_count" : 1
                }
              ]
            }
          }
        ]
      }
    }
  }
}