GIS奮闘記

元GISエンジニアの技術紹介ブログ。主にPythonを使用。

スポンサーリンク

Tableau の空間関数を使ってみよう!

さて、本日も前回のエントリーに続き Tableau について書いてみようと思います。以下のエントリーで Tableau を使って地図データを可視化してみましたが、今回はもう一歩踏み込んで空間関数を使ってみようと思います。

www.gis-py.com

使用するデータ

ESRIジャパンさんが主催した「ArcGIS 開発者のための最新アプリ開発塾 2020」で使用された 各店舗売上.csvを使用します。

community.esri.com

環境

Windows10 64bit
Tableau Desktop Public Edition 2021.1.0 64bit

使用する空間関数

  • MakePoint・・・緯度経度からポイントを作成
  • MakeLine・・・二つのポイントからラインを作成
  • Distance・・・2 つのポイント間の距離を計測
  • バッファー・・・ポイントのバッファーを作成

バッファーを作れるなんて素晴らしいですね!そして Tableau 恐るべしです。

MakePoint

緯度経度からポイントを作成します。

1.分析>計算フィールドの作成 f:id:sanvarie:20210422204157p:plain

2.MAKEPOINT([緯度],[経度]) と入力>OK f:id:sanvarie:20210422204332p:plain

左側のデータ欄に「ポイント」が作成されたことがわかります。 f:id:sanvarie:20210422204413p:plain

3.「ポイント」をダブルクリック ポイントが可視化されました。

f:id:sanvarie:20210422204511p:plain

MakeLine

二つのポイントからラインを作成します。ここでは「蒲田駅」から「横須賀中央駅」の距離を計測してみようと思います。それぞれの緯度経度は以下です。

  • 蒲田駅
    • 緯度 35.562479
    • 経度 139.716073
  • 横須賀中央駅
    • 緯度 35.278699
    • 経度 139.670040

1.分析>計算フィールドの作成 f:id:sanvarie:20210422204157p:plain

2.MAKELINE(MAKEPOINT(35.562479,139.716073),MAKEPOINT(35.278699,139.670040))>OK

f:id:sanvarie:20210422204837p:plain

左側のデータ欄に「ライン」が作成されたことがわかります。 f:id:sanvarie:20210422204902p:plain

3.「ライン」をダブルクリック
蒲田駅~横須賀中央駅間でラインが可視化されました。

f:id:sanvarie:20210422205016p:plain

拡大してみましたが、駅が確認できません。

f:id:sanvarie:20210422205106p:plain

しかし、Tableau は以下のような手順で背景図を選ぶことができます。素晴らしいですね。

f:id:sanvarie:20210422205158p:plain

f:id:sanvarie:20210422205259p:plain

このように作成したラインが本当に蒲田駅~横須賀中央駅かどうか確認することができました。

f:id:sanvarie:20210422205525p:plain

f:id:sanvarie:20210422205553p:plain

Distance

2点間の距離を測ります。

1.分析>計算フィールドの作成 f:id:sanvarie:20210422204157p:plain

2.DISTANCE(MAKEPOINT(35.562479,139.716073),MAKEPOINT(35.278699,139.670040),"km")と入力>OK

f:id:sanvarie:20210422205910p:plain

左側のデータ欄に「距離」が作成されたことがわかります。 f:id:sanvarie:20210422205928p:plain

3.「距離」を「ラベル」にドラッグアンドドロップします。 f:id:sanvarie:20210422210217p:plain

4.ラベル>フォント>フォントサイズを24にします。

f:id:sanvarie:20210422210319p:plain

「距離」が表示されました。しかし、数値がおかしい気がします。蒲田駅~横須賀中央駅間は3049kmもありませんね・・・

5.合計(距離)>メジャー(合計)>平均を押下します。 f:id:sanvarie:20210422210702p:plain

以下のエントリーと同じく蒲田駅~横須賀中央駅間は31.76kmという結果になりました。

www.gis-py.com

f:id:sanvarie:20210422210809p:plain

バッファー

ポイントに対して300mのバッファーを作ります。

1.分析>計算フィールドの作成 f:id:sanvarie:20210422204157p:plain

2.BUFFER([ポイント],300,"m")と入力>OK f:id:sanvarie:20210422211232p:plain

左側のデータ欄に「バッファー」が作成されたことがわかります。 f:id:sanvarie:20210422211253p:plain

3.「バッファー」をダブルクリック
バッファーが作成されたことがわかります。 f:id:sanvarie:20210422211404p:plain

さいごに

まさか Tableau でバッファーまで作れるとは思ってなかったので、これは意外な発見でした。まだまだ知らない機能がありそうなので、引き続き色々触って勉強してみようと思います。本日は以上です。

Tableau を使って地図データを可視化してみよう!

さて、本日は Tableau を使って地図データを可視化してみようと思います。Tableau と言えば BI ツールとして有名だと思いますが、なんと これで地図データも可視化できるようです。ちょっと地図データを可視化したいくらいだったら GIS を導入しなくても BI ツールで対応できてしまうということですね。おそらく地図関係の機能もどんどん強化されていくでしょうし、GIS 関係の会社さんは戦々恐々としているのではないでしょうか。

Tableau とは

Tableauは、世界的に人気な BI ツールです。誰でも簡単にデータ分析や可視化を行うことができます。

Tableau Desktop をインストールしてみる

Tableau は色々な製品があるのですが、今回はTableau Desktop Public Edition という無料で使える製品を使ってみます。以下のサイトからインストーラーをダウンロードします。

public.tableau.com

インストーラーを起動してインストールを進めます。

f:id:sanvarie:20210415134436p:plain

インストール完了後、Tableau を起動してみます。機能は少し制限されているそうなのですが、少しつかうくらいだったらこれで十分だと思います。

f:id:sanvarie:20210415135133p:plain

使用するデータ

  • 全国市区町村界・・・ESRIジャパンさんが公開しているデータです。以下関連エントリーなので、興味がある方はぜひ読んでみてください。

www.gis-py.com

データを可視化してみる

空間ファイルを選択します。

f:id:sanvarie:20210415140216p:plain

全国市区町村界データを読み込むとこのような画面になります。「シート1」をクリックします。

f:id:sanvarie:20210415140819p:plain

このような表示になります。「ジオメトリ」をダブルクリックします。

f:id:sanvarie:20210415141006p:plain

おぉー全国市区町村界データが表示されました。背景には Mapbox の地図を使っていますね。

f:id:sanvarie:20210415141049p:plain

次に「KEN」を「ラベル」にドラッグアンドドロップします。

f:id:sanvarie:20210415162252p:plain

県名がラベリングされました。

f:id:sanvarie:20210415162335p:plain

同じように「KEN」を「色」にドラッグアンドドロップするとこのように県ごとの色分けが行われます。

f:id:sanvarie:20210415162909p:plain

こんな感じで属性テーブルも使うことができますね。

f:id:sanvarie:20210415163213p:plain

さいごに

やはり 地図機能に関しては GIS 製品と比べると見劣りするかなという感じでしたが、ちょっと地図データを可視化させてみたいという場合は Tableau で十分かなと思いました。位置情報に関する重要性が年々増してきているかと思うので、これから Tableau の地図機能はさらに充実してくるのではと思っています。私も仕事で Tableau を使うようになったのでこれを機に本ブログで Tableau について色々紹介できればと思います。本日は以上です。

Elasticsearch と Kibana を使って地図データを可視化してみよう!

さて、本日は Elasticsearch と Kibana を使って地図データを可視化してみようと思います。ただ、Elasticsearch と Kibana のインストールや使い方については本エントリーでは紹介はしませんので、興味のある方は公式ドキュメントを読んでみてください。

www.elastic.co

Elasticsearch とは

Elasticsearch は Apache Lucene をベースにしたオープンソースの検索エンジンです。近年では利用者が急増して、現在では最も人気のある検索エンジンとなっています。Elasticsearch は元々全文検索の用途で開発されましたが、それ以外にもログ収集・解析の用途としても多く利用されています。

Elasticsearch の特徴
  • 分散配置による高速化と高可用性
  • REST API によるアクセス
  • JSON フォーマットに対応したドキュメント志向データベース
  • ログ収集・可視化などの多様な関連ソフトウエアとの連携

Kibana とは

Kibana は Elasticsearch に格納されているデータをブラウザを用いて可視化、分析するためのツールです。グラフ、ダッシュボード、地図などを使ってデータを可視化することができます。

環境

CentOS 7
Elasticsearch7.6
Kibana7.6

手順

  1. データ作成
  2. データ可視化
データ作成

今回は2つデータを作成しました(駅名とそこの緯度経度を持つデータ)。curl コマンドか Kibana コンソールを使ってデータを作成できるので、両方のやり方を紹介します。

1.curl コマンド

curl -XPUT "http://localhost:9200/test_index" -H 'Content-Type: application/json' -d'{  "mappings": {    "properties": {      "location": {        "type": "geo_point"      }    }  }}'
curl -XPUT "http://localhost:9200/test_index/_doc/1" -H 'Content-Type: application/json' -d'{  "text": "蒲田駅",  "location": {     "lat": 35.562479,    "lon": 139.716073  }}'
curl -XPUT "http://localhost:9200/test_index/_doc/2" -H 'Content-Type: application/json' -d'{  "text": "横須賀中央駅",  "location": {     "lat": 35.278699,    "lon": 139.670040  }}'
curl -XGET "http://localhost:9200/test_index/_search"

2.Kibana コンソール

PUT test_index
{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      }
    }
  }
}

PUT test_index/_doc/1
{
  "text": "蒲田駅",
  "location": { 
    "lat": 35.562479,
    "lon": 139.716073
  }
}

PUT test_index/_doc/2
{
  "text": "横須賀中央駅",
  "location": { 
    "lat": 35.278699,
    "lon": 139.670040
  }
}

GET test_index/_search

このような形でデータが格納されていることがわかります。

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "text" : "蒲田駅",
          "location" : {
            "lat" : 35.562479,
            "lon" : 139.716073
          }
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "text" : "横須賀中央駅",
          "location" : {
            "lat" : 35.278699,
            "lon" : 139.67004
          }
        }
      }
    ]
  }
}
データ可視化

まずはKibana のマップを表示させてみました。続いて作成したデータを Kibana で可視化してみようと思います。

f:id:sanvarie:20210206222840p:plain

ポイントが二つプロットされていることがわかります。それぞれ拡大して確認してみようと思います。

f:id:sanvarie:20210206223508p:plain

蒲田駅と横須賀中央駅にそれぞれポイントがプロットされていることがわかります

f:id:sanvarie:20210206223559p:plain

f:id:sanvarie:20210206223644p:plain

さいごに

ものすごく簡単にでしたが Elasticsearch と Kibana を使って地図データの可視化に成功しました。データの表示だけではなくデータの分析もできるっぽいので、もう少し使い方を覚えたらそれについても紹介したいと思います。Elasticsearch に関しては今後ますます人気が高まるでしょうし、興味のある方はぜひ使ってみてください。本日は以上です。

Python で2点の緯度経度から距離を計測する方法

さて、本日は2点の緯度経度から距離を計測する方法について紹介しようと思います。平面上の単純な2点間の距離計測などは簡単にできるかと思いますが、地球は回転楕円体なため(実は地球は完全な球体というわけではありません)、その丸みを考慮した計算が必要になります。

地球の形については国土地理院さんが公開しているサイトをご参照ください。

距離計算方法

ヒュベニの公式というものがあり、こちらであれば簡易的に距離計測をすることができますので、今回はこちらを使ってみます。 公式については以下をご参照ください。

ヒュベニの公式

2点間の距離計測式 D = SQRT((Ay * M)^2 + (Ax * N * cos(P))^2)

Ax:2点の経度の差
Ay:2点の緯度の差
P:2点の緯度の平均

M = Rx (1 - e^2 )/W3:子午線曲率半径
N = Rx/W:卯酉線曲率半径
W = SQRT(1 - E^2*sin(P)2):子午線・卯酉線曲率半径の分母

e = SQRT((Rx2 - Ry2)/Rx2):第1離心率
Rx:長半径(赤道半径)
Ry:短半径(極半径)
E2 = e2:第2離心率

長半径(赤道半径)、短半径(極半径) という見慣れない単語がありますが、こちらに関しては Wikipediaを参照してください。そういう固定値を使うという認識でまずは大丈夫だと思います。

f:id:sanvarie:20210116195907p:plain

色々調べてみると他には以下のような計算方法があるようです。国土地理院さんが公開している計算方法は複雑すぎて私の頭では理解できないですね・・・

距離計測する区間

「蒲田駅」から「横須賀中央駅」の距離を計測してみようと思います。それぞれの緯度経度は以下です。

  • 蒲田駅
    • 緯度 35.562479
    • 経度 139.716073

f:id:sanvarie:20210116143305p:plain

  • 横須賀中央駅
    • 緯度 35.278699
    • 経度 139.670040

f:id:sanvarie:20210116143410p:plain

国土地理院さんのサイトで確認したら「31.761253km」という計測結果が出ました。今回の結果がこの数値にどれだけ近づけるかのでしょうか。楽しみです。

f:id:sanvarie:20210116151537p:plain

実行環境

Windows 10 64bit
Python 3.6.6

サンプルコード

# -*- coding: utf-8 -*-
import math

pole_radius = 6356752.314245                  # 極半径
equator_radius = 6378137.0                    # 赤道半径
latlon_kamata = (35.562479, 139.716073)       # 蒲田駅の緯度経度
latlon_yokosukachuo = (35.278699, 139.670040) # 横須賀中央駅の緯度経度

def cal_distance():

    # 緯度経度をラジアンに変換
    lat_kamata = math.radians(latlon_kamata[0])
    lon_kamata = math.radians(latlon_kamata[1])
    lat_yokosukachuo = math.radians(latlon_yokosukachuo[0])
    lon_yokosukachuo = math.radians(latlon_yokosukachuo[1])

    lat_difference = lat_kamata - lat_yokosukachuo       # 緯度差
    lon_difference = lon_kamata - lon_yokosukachuo       # 経度差
    lat_average = (lat_kamata + lat_yokosukachuo) / 2    # 平均緯度

    e2 = (math.pow(equator_radius, 2) - math.pow(pole_radius, 2)) \
            / math.pow(equator_radius, 2)  # 第一離心率^2

    w = math.sqrt(1- e2 * math.pow(math.sin(lat_average), 2))

    m = equator_radius * (1 - e2) / math.pow(w, 3) # 子午線曲率半径

    n = equator_radius / w                         # 卯酉線曲半径

    distance = math.sqrt(math.pow(m * lat_difference, 2) \
                   + math.pow(n * lon_difference * math.cos(lat_average), 2)) # 距離計測

    print(distance / 1000)

if __name__ == '__main__':
    cal_distance()

以下のような結果になりました。

f:id:sanvarie:20210116151941p:plain

31.7612541505034km」という計測結果が出ました。国土地理院さんのサイトで計測した「31.761253km」とほぼ同じ値になりました。

さいごに

少し複雑な計算式でしたが、蒲田駅~横須賀中央駅間の距離計測に成功しました。今度は球面三角法など他の計算方法も試してみたいですね。

また、ライブラリなどを使用すればこのような計算をしなくてもいいのですが、今回のエントリーを書くにあたって色々調査をする中で勉強になることがたくさんありました。私は GIS 歴はけっこう長いのですが地理的な知識に関してはあまりなく、GIS に携わるものとして地理の基礎的な勉強をもっとしなければいけないなと実感しました。本日は以上です。

参考サイト

https://www.trail-note.net/tech/calc_distance/
http://hp.vector.co.jp/authors/VA002244/yacht/geo.htm

Python と OpenCV で画像の幾何学変換をしてみよう

さて、本日は画像の幾何学変換について書いてみようと思います。以下エントリーと同様に OpenCV を使ってみようと思います。

www.gis-py.com

幾何学変換とは

幾何学変換と聞くだけで頭が痛くなりそうな気がしますがそんなに難しく考える必要はありません。まずは画像を拡大・縮小、回転、スキュー(画像を傾けるような処理)するもの、くらいに捉えておけば大丈夫かと思います(もちろん専門的に勉強するならこれだと足りないと思いますが)。

今回試すこと

  1. 拡大・縮小
  2. 移動
  3. 回転
  4. アフィン変換
  5. 射影変換

使用する画像

大田区公式PRキャラクターの「はねぴょん」の画像を使用します。

f:id:sanvarie:20210111155935p:plain

実行環境

Windows 10 64bit
Python 3.6.6

サンプルコード

拡大・縮小

はねぴょんを横に1.5倍、縦に3倍拡大させてみます。cv2.resize の引数の fx、fyを設定することで拡大縮小の調整ができます。

# -*- coding: utf-8 -*-
import cv2

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")

    res = cv2.resize(img, None, fx=1.5, fy=3,         # 横に1.5倍、縦に3倍にする
                     interpolation = cv2.INTER_CUBIC) # 補間方法(縮小する場合はcv2.INTER_AREA)

    cv2.imshow("res", res)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このようにはねぴょんが拡大されたことがわかります。

f:id:sanvarie:20210113150749p:plain

移動

はねぴょんを移動させます。

# -*- coding: utf-8 -*-
import cv2
import numpy as np

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")

    rows, cols, _ = img.shape

    M = np.float32([[1,0,100],[0,1,50]]) # X移動100,Y移動50
    dst = cv2.warpAffine(img, M, (cols,rows))

    cv2.imshow("dst", dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように画像が移動したことがわかります。

f:id:sanvarie:20210113151952p:plain

回転

はねぴょんを180度回転させます。

# -*- coding: utf-8 -*-
import cv2
import numpy as np

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
    rows, cols, _ = img.shape

    M = cv2.getRotationMatrix2D((cols / 2, rows / 2), 180, 1)
    dst = cv2.warpAffine(img, M, (cols, rows))

    cv2.imshow("dst", dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように画像が180度回転したことがわかります。

f:id:sanvarie:20210116090245p:plain

アフィン変換

アフィン変換は線形変換(拡大や縮小,回転など)と平行移動を組み合わせた変換です。アフィン変換を行うには入力画像と出力画像の対応点の座標が少なくとも3組必要です。今回は以下のように対応点を設定してみました。

f:id:sanvarie:20210116092836p:plain

# -*- coding: utf-8 -*-
import cv2
import numpy as np

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
    rows, cols, _ = img.shape

    pts1 = np.float32([[16,36],[138,36],[16, 130]])
    pts2 = np.float32([[34,67],[154,84],[63,175]])

    M = cv2.getAffineTransform(pts1,pts2)

    dst = cv2.warpAffine(img, M, (cols, rows))

    cv2.imshow("dst", dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

出力画像の対応点にアフィン変換された結果になりました。

f:id:sanvarie:20210116093405p:plain

射影変換

任意の四角形を任意の四角形に変形することができる変換が射影変換です。はねぴょんの画像では少しわかりにくいので、射影変換に関しては以下の画像を使用します。

f:id:sanvarie:20210116094427p:plain

射影変換を使うことで雑誌を真上から見たように補正することができます。射影変換を行うには入力画像と出力画像の対応点の座標が少なくとも4組必要です。今回は以下のように対応点を設定してみました。

f:id:sanvarie:20210116095309p:plain

# -*- coding: utf-8 -*-
import cv2
import numpy as np

def main():
    img = cv2.imread(r"D:\blog\data\opencv\book.jpg")
    rows, cols, _ = img.shape

    pts1 = np.float32([[765,521],[3135,551],[167, 2023],[4025, 1849]])
    pts2 = np.float32([[0,0],[cols,0],[0,rows],[cols, rows]])

    M = cv2.getPerspectiveTransform(pts1,pts2)

    dst = cv2.warpPerspective(img, M, (cols, rows))
    cv2.imwrite(r"D:\blog\data\opencv\book2.jpg", dst) # 保存

if __name__ == '__main__':
    main()

文字はぼやけてしまっていますが、雑誌を真上から見たように補正することができました。

f:id:sanvarie:20210116103858p:plain

さいごに

実は意外と GIS をつかっていると画像を幾何学変換する機会はあるかと思います。私の場合は地図上に水道の図面を幾何学変換させていました。その図面を下図に水道管などを作図するイメージですかね。まだ基本的なことしか紹介していませんが、OpenCV を使えば簡単に画像の幾何学変換を行うことができます。興味のある方はぜひ試してみてください。

Python の認証プロキシ設定について

さて、本日は Python の認証プロキシ設定について書いてみようと思います。社内環境で WebAPI などを叩こうと思ったときに認証プロキシにひっかかることがあるかと思います。今回は認証プロキシの突破方法について書いてみようと思います。

実行環境

Windows 10 64bit
Python 3.6.6

認証プロキシ設定方法

  1. 環境変数を設定する
  2. プログラム内で環境変数を定義

環境変数を設定する

環境変数を設定することで認証プロキシを通過することができます。

set HTTP_PROXY=http://user:pass@server:port

例えば、以下のような設定の場合、環境変数に設定する値は「http://gis:gis2021@hoge:8080」のようになります。

  • ユーザ:gis
  • パスワード:gis2021
  • サーバー名:hoge
  • ポート:8080

プログラム内で環境変数を定義

環境変数を設定したくない場合、以下のようにプログラム内で環境変数を定義すれば認証プロキシを通過することができます。

import os
os.environ["http_proxy"] = "http://user:pass@server:port"

さいごに

認証プロキシにお困りの方はぜひ参考にしてみてください。短いですが、本日は以上です。

Python と OpenCV で画像処理をしてみよう!

さて、本日は OpenCV を使って画像処理をしてみようと思います。私は最近画像を扱うことが多く、OpenCV を使ってもう少し画像関連の知識の幅を広げようと思っています。

今回のテーマは GIS とは直接は関係ないのですが、GIS の世界では航空写真など多くの画像を扱います。GIS のお仕事に興味がある方は画像の扱いにも慣れておくことをおすすめします。

画像関連のエントリーをいくつか書いていますので、興味のある方はぜひ読んでみてください。

www.gis-py.com

www.gis-py.com

www.gis-py.com

OpenCV とは?

オープンソースのコンピュータビジョン向けのライブラリですね。要するに画像や動画用のライブラリですね。OpenCV は元々 C/C++ で使えるライブラリでしたが、Python でも動作するようになりました。ありがたい話です。

今回試すこと

まずは以下の基本的な機能を試してみたいと思います。

  1. 画像を読み込む
  2. 興味領域(ROI)の抽出
  3. 画像のブレンド
  4. 画像の重ね合わせ
  5. 画像から顔と目を検出

実行環境

Windows 10 64bit
Python 3.6.6

使用する画像

大田区公式PRキャラクターの「はねぴょん」の画像を使用します。

f:id:sanvarie:20210111155935p:plain

サンプルコード

画像を読み込む
# -*- coding: utf-8 -*-
import cv2

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg", 1) # カラーで読込
    cv2.imshow("test", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このようにはねぴょんの画像が読み込まれたことが確認できました。

f:id:sanvarie:20210111160141p:plain

興味領域(ROI)の抽出

ROIとは、Region of Interestの略で、処理対象とする領域のことですね。以下を ROI としてみます。「ペイント」アプリを使えば ROI とする座標がわかります。

f:id:sanvarie:20210111162318p:plain

# -*- coding: utf-8 -*-
import cv2

def main():
    img = cv2.imread(r"D:\blog\data\opencv\hane.jpg", 1) # カラーで読込
    roi = img[68:128, 35:143] # ROI領域
    cv2.imwrite(r"D:\blog\data\opencv\hane_roi.jpg", roi) # 保存

if __name__ == '__main__':
    main()

このように ROI を抽出することができました。 f:id:sanvarie:20210111163959p:plain

画像のブレンド

以下の画像をはねぴょんの画像にブレンディングします(はねぴょんの画像の重みを0.7、上の画像の重みを0.3に設定)。

f:id:sanvarie:20210111171544p:plain

# -*- coding: utf-8 -*-
import cv2

def main():
    img1 = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
    img2 = cv2.imread(r"D:\blog\data\opencv\opencv_logo.png")

    # 画像の大きさをあわせる
    img1 =cv2.resize(img1,(200,200))
    img2 =cv2.resize(img2,(200,200))

    img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
    img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

    blended = cv2.addWeighted(src1=img1,alpha=0.7,src2=img2,beta=0.3,gamma=0)

    cv2.imshow("blended",blended)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように画像がブレンドされたことがわかります。

f:id:sanvarie:20210111171929p:plain

画像の重ね合わせ

今度はブレンドではなく、画像を重ね合わせてみようと思います。

# -*- coding: utf-8 -*-
import cv2

def main():
    img1 = cv2.imread(r"D:\blog\data\opencv\hane.jpg")
    img2 = cv2.imread(r"D:\blog\data\opencv\opencv_logo.png")

    # 片方の画像を小さくする
    img2 =cv2.resize(img2,(100,100))

    #img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
    #img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

    large_img = img1
    small_img = img2

    large_img[0:small_img.shape[0], 0:small_img.shape[1]] = small_img

    cv2.imshow("large_img", large_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように画像が重なったことがわかります。 f:id:sanvarie:20210111172544p:plain

画像から顔と目を検出

OpenCV では顔,目,笑顔などを検出することができます(検出させるものを学習させることも可能です)。今回は顔と目を検出してみようと思いますが、はねぴょんでは検出ができないので以下の画像を使用します。

f:id:sanvarie:20210111173628j:plain

# -*- coding: utf-8 -*-
import os
import cv2

# OpenCVのディレクトリ
opencv_path = r"C:\Python\Lib\site-packages\cv2\data"

def main():

    # 顔検出用データ
    face_cascade = cv2.CascadeClassifier(os.path.join(opencv_path,
                                         "haarcascade_frontalface_default.xml"))

    # 目検出用データ
    eye_cascade = cv2.CascadeClassifier(os.path.join(opencv_path,
                                        "haarcascade_eye.xml"))

    # 画像読込
    img = cv2.imread(r"D:\blog\data\opencv\CR7.jpg")
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 顔検出
    faces = face_cascade.detectMultiScale(gray,
                                          scaleFactor=1.3,
                                          minNeighbors = 5,
                                          minSize=(30, 30))
    for (x,y,w,h) in faces:
        # 顔検出した部分に枠を描画
        img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
        roi_gray = gray[y:y+h, x:x+w]
        roi_color = img[y:y+h, x:x+w]

        # 目検出
        eyes = eye_cascade.detectMultiScale(roi_gray)
        for (ex,ey,ew,eh) in eyes:
            # 目検出した部分に枠を描画
            cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

    cv2.imshow("img", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == '__main__':
    main()

このように顔と目を検出することができることがわかります。 f:id:sanvarie:20210111181036p:plain

さいごに

まだまだ OpenCV の基本機能を触れただけですが、簡単なコードで画像から顔と目を検出できたり非常に便利なライブラリということがわかりました。OpenCV はすごく多機能なライブラリのため、次回以降でもOpenCV の紹介をしていこうと思います。本日は以上です。