20210907のPythonに関する記事は19件です。

画像の正規化に関して

はじめに よく、画像の前処理で[0~1]にスケーリングとか[-1,1]にスケーリングとか出てきます。その処理を行うコードも情報によっては書き方が違ったりするし、また画像の正規化や標準化などの言葉も出てきたり、ちょっと混乱してきたのでまとめてみました。 正規化とか標準化って何? そもそもデータセットの特徴量間でスケールが違うことがほとんどです。 身長と体重を例に挙げると、成人男性であれば大体ですけど 身長: 150cm~190cmくらい 体重: 40kg~100kgくらい の範囲の値になる人ばかりです。単位と値の範囲が大きく異なるわけです。 これを考慮せず、モデルに学習させても、比較的取りうる値の大きい身長の方に引っ張られて、うまく学習できません。 そのため特徴量間でスケール(範囲)を揃えてあげる必要があるわけですね。 その揃える方法として正規化と標準化の2つがあります。 正規化とは 正規化は特徴量の値の範囲を一定の範囲内に収めるように変換する処理のこと。 主に0から1,もしくは-1から1にすることが多い。 元データxを正規化する式は以下。 $$ x_{norm} = \frac{x - x_{min}}{x_{max} - x_{min}} $$ $$(x_{norm}: x を正規化した値, x_{min}: x の最小値, x_{max}: x の最大値)$$ 「元の値から最小値を引いて、最大値と最小値の差(値の範囲)で割る」という処理をしている。 標準化とは 標準化は特徴量の平均を0,分散が1になるように変換する処理のこと。 元データxの標準化を式にすると以下。 $$x_{std}=\frac{x−μ}{σ}$$ $$(x_{std}:x を標準化した値, μ:xの平均,σ:xの標準偏差)$$ どっちを使えばいいの? 基本的には標準化。正規化だと外れ値の影響を受けやすいため。 ただ画像データであれば正規化を行うことがほとんどです。 というのも画像データは取りうる値が決まっているからですね。 カラーの画像データであれば3原色である赤、緑、青の色の強さををそれぞれ0~255までの離散整数値で表すことで、画像として表示されています。 要は赤が0~255までの256段階、緑、青も同様ということで、256の3乗=約1677万通りの色を表現できます。 実際に見てみた方が早いので画像をndarray形式で読み込んでみましょう。 以下の桜の画像を使いましょう。 import numpy as np import cv2 img = cv2.imread('aj-McsNra2VRQQ-unsplash.jpg') img 結果 array([[[193, 172, 205], [193, 172, 205], [193, 172, 205], ..., [250, 234, 197], [250, 234, 197], [250, 234, 197]], [[193, 172, 205], [193, 172, 205], [193, 172, 205], ..., [250, 234, 197], [250, 234, 197], [250, 234, 197]], 193とか250とかの値がズラーと並んでますね。0から255までの整数値の組み合わせで画像が表されているわけです。 何度も言いますが、白黒、カラー関わらず、画像データは取りうる値の範囲が決まっています。すなわち最小値は0,最大値は255です。どんな画像データでも大体そうです。 大体と言ったのは、全部黒の画像とかになると最小値0、最大値0になるような例もあるからです。 だた一般的な画像データであれば最小値は0,最大値255と考えていて問題ありません。そのため外れ値に引っ張られることもないので、正規化を行うことがほとんどかと思います。 画像の正規化の種類 基本は2種類。 0から1の範囲の正規化 -1から1の範囲の正規化 正直自分もどっちがいいとかはわかりませんが、コチラの書籍によれば 画像のピクセルごとのスケーリングでは、それらの中心を0に設定した上で、[-1,1]の範囲で尺度を取り直す方法も一般的である。実際のところ、通常はそれでうまくいく。 と書かれています。あまり深く考えず、どちらも「取りうる値の大きさを小さくすることで計算を安定させる」ために行っていると思えばいいかと。 個人的な解釈として、もし使い分けるならCNNモデルの最後の出力の値の範囲で使い分ければいいかと思います。つまり活性化関数で何を使うかで決めるということです。 例えばシグモイド関数であれば取りうる値の範囲は0から1なので入力も[0,1]の範囲に正規化した画像にするべきですし、tanh(双曲線正接関数)であれば-1から1の範囲の値を取るので[-1,1]に正規化すべきだと思います。 まぁ書籍とかだとMNISTの分類で最後の活性化関数がsoftmax関数(0から1の範囲の確率値)なのに[-1,1]に正規化してたりとかもしますが(それでもうまくいっていることの方が多い) あまり厳密になる必要もないのかなと思ったり。 実装例 ここから正規化の実装例を思いつくだけ紹介します。 [0,1]スケーリング まず[0,1]スケーリングから、とは言ってもこれしかないですが、、、 img = cv2.imread('aj-McsNra2VRQQ-unsplash.jpg') img = img / 255 各ピクセル値を255で割ることで0から1の範囲になります。 たまーに、おそらく0から255で256諧調だからか 256で割っているコードも見かけますが、それだと最大値が1にならないので注意です。 正規化しても問題なく表示できます。 import matplotlib.pyplot as plt img = cv2.imread('aj-McsNra2VRQQ-unsplash.jpg') # opencvはカラー画像をBGRモードで読み込むのでRGBに変換 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 正規化 img = img / 255 plt.imshow(img) 3行目の処理に関して詳しくコチラの記事にまとめてますので、良かったら見てください。 表示結果⇩ [-1,1]スケーリング 次は[-1,1]スケーリング。とは言ってもそんなに種類ないです。 例① img = cv2.imread('aj-McsNra2VRQQ-unsplash.jpg') img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = (img - 127.5) / 127.5 GANモデルとかだとよく見ます。255の半分の値の127.5を引いて[-127.5, 127.5]の範囲に。その後127.5で割ることで[-1,1]にしています。 例② img = cv2.imread('aj-McsNra2VRQQ-unsplash.jpg') img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = ((img / 255) - 0.5) * 2 レアケース。まず255で割って[0,1]に。0.5を引いて[-0.5,0.5]。それを2倍することで[-1,1]にしています。 この2つくらいかな。 じゃ[-1,1]スケールした画像を表示してみます。 img = cv2.imread('aj-McsNra2VRQQ-unsplash.jpg') img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = (img - 127.5) / 127.5 plt.imshow(img) Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers). エラーと共に赤色が強い画像が表示されました。 まぁ色の値にマイナスなんてものはないので当たり前ですね。 [-1,1]スケールにした画像を正しく表示したい場合は、float型の[0,1]スケールに戻すか、8ビット整数型の[0,255]スケールに戻す必要があります。 やり方は以下。 [-1,1]→[0,1] img = 0.5 * img + 0.5 0.5をかけて [-0.5, 0.5]。さらに0.5を足すことで[0,1]にしています。 [-1,1]→[0,255] img = 127.5 * img + 127.5 img = img.astype('uint8') 127.5をかけて[-127.5, 127.5]。さらに127.5を足して[0,255]にしています。 ただ[0,255]に戻す場合は、整数値にしなくてはいけませんので8ビット整数型に変える必要があります。 まとめ 画像の正規化についてまとめて見ました。 画像の型と、取りうる値の範囲には常に意識を向けておくことが大事だと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

S3操作をするLambda関数(Python-image)をSAM CLIを使ってデプロイする手順をまとめてみる

はじめに Lambda関数を作成するにあたり、必要な手順をざっくりまとめました。 以下も試しました。 1つのアプリケーションで複数の関数の定義 S3の操作周りをLambdaで行う SAM CLIのローカルテストを試す 開発者のIAMユーザ作成 開発とデプロイで使用します。 あとは、デフォルトのまま作成し、アクセスキー、シークレットアクセスキーを保存 必要な場合アクセス権を追加 ユーザ作成時に追加した「AWSLambda_FullAccess」のみなので必要なものがあれば追加します。 権限 概要 AWSLambda_FullAccess Lambda、CloudWatchなど AmazonS3FullAccess S3 AmazonAPIGatewayAdministrator API Gatewayの作成やデプロイに必要なポリシー AmazonEC2ContainerRegistryFullAccess ECRの作成やデプロイに必要なポリシー  IAMFullAccess AWSCloudFormationの作成やデプロイに必要なポリシー AWSCloudFormationFullAccess AWSCloudFormationの作成やデプロイに必要なポリシー 実行ロールの作成 Lambda関数を実行するロールです。デプロイ時に指定しますのでしばらく使いません。 実行ロールにも必要な場合アクセス権を追加 Lambda実行時の権限で必要なものがあれば設定します。インラインポリシーを使うと最低限のポリシーを設定できます。 例)Lambdaから特定のS3のファイル取得を行う場合 ※実際には、S3アップロードを行う必要があるのでAmazonS3FullAccessをつけています。 まずはLambdaとは関係ないプログラムを書いてみる S3を操作するPythonプログラムのサンプルです。 テスト読み取り用バケットにテスト用画像をアップしておく ローカル実行用にテスト読み取り用バケットとテスト用画像をアップしておきます。 Lambda関数とトリガーで紐づけられるS3は新たに作成する必要があるため、実際にはこのバケットは使いません。 環境はこちらの記事のosイメージをpythonに変えたものですが、なんでも構いません。 aws認証情報には、先ほど作成した開発者のIAMユーザを使います。 必要なライブラリをインストールする $ pip install boto3 単に指定したS3バケットの画像「port.png」を取得してリネームし、書き込み用バケットにアップするプログラムです。 s3example.py import boto3 import tempfile s3 = boto3.resource('s3') s3_write_bucket = '{書き込み用バケット}' def hello(s3_read_bucket, filename): # ファイルの読み込み obj = s3.Object(s3_read_bucket, filename) response = obj.get() tmpdir = tempfile.TemporaryDirectory() fp = open(tmpdir.name + '/' + filename, 'wb') fp.write(response['Body'].read()) fp.close; # ファイル名に.zipをつけてS3にアップロード zipname = tempfile.mkstemp()[1] obj = s3.Object(s3_write_bucket, filename + '.zip') response = obj.put( Body=open(tmpdir.name + '/' + filename, 'rb') ) tmpdir.cleanup() return response if __name__ == '__main__': print(hello("{テスト読み取り用バケット}", "port.png")) 動作確認します。 $ python s3example.py アップされました。 Lambda関数にする lambda_handler関数を追加します。 トリガーから渡されるeventはS3オブジェクトの更新です。 中身については、「ローカルテスト」にて後述します。 s3example.py import boto3 import tempfile s3 = boto3.resource('s3') s3_write_bucket = '{書き込み用バケット}' #循環参照防止のためreadとは別のバケット ############# 追加部分 ############# def lambda_handler(event, context): for rec in event['Records']: filename = rec['s3']['object']['key'] s3_read_bucket = rec['s3']['bucket']['name'] hello(s3_read_bucket, filename) return { "statusCode": 200, } ############# 追加部分 ############# def hello(s3_read_bucket, filename): # ファイルの読み込み obj = s3.Object(s3_read_bucket, filename) response = obj.get() tmpdir = tempfile.TemporaryDirectory() fp = open(tmpdir.name + '/' + filename, 'wb') fp.write(response['Body'].read()) fp.close; # ファイル名に.zipをつけてS3にアップロード zipname = tempfile.mkstemp()[1] obj = s3.Object(s3_write_bucket, filename + '.zip') response = obj.put( Body=open(tmpdir.name + '/' + filename, 'rb') ) tmpdir.cleanup() return response if __name__ == '__main__': print(hello("{テスト読み取り用バケット}", "port.png")) ローカルテスト まず、コンソールのLambdaの「テスト」から「s3-put」のものを取得します。 取得した情報を自身の環境に変更したものをfixtureにし、テストプログラムを作成しました。 tests/unit/test_s3example.py import pytest from hello_world import s3example @pytest.fixture() def apigw_event(): return { "Records": [ { "eventVersion": "2.0", "eventSource": "aws:s3", "awsRegion": "ap-northeast-1", # 変更部分 "eventTime": "1970-01-01T00:00:00.000Z", "eventName": "ObjectCreated:Put", "userIdentity": { "principalId": "EXAMPLE" }, "requestParameters": { "sourceIPAddress": "127.0.0.1" }, "responseElements": { "x-amz-request-id": "EXAMPLE123456789", "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH" }, "s3": { "s3SchemaVersion": "1.0", "configurationId": "testConfigRule", "bucket": { "name": "{テスト読み取り用バケット}", # 変更部分 "ownerIdentity": { "principalId": "EXAMPLE" }, "arn": "arn:aws:s3:::{テスト読み取り用バケット}" # 変更部分 }, "object": { "key": "port.png", # 変更部分 "size": 1024, "eTag": "0123456789abcdef0123456789abcdef", "sequencer": "0A1B2C3D4E5F678901" } } } ] } def test_lambda_handler(apigw_event, mocker): ret = s3example.lambda_handler(apigw_event, "") assert ret["statusCode"] == 200 pytestをインストールし、実行します。 $ pip install pytest pytest-mock --user $ python -m pytest tests/ -v tests/unit/test_handler.py::test_lambda_handler PASSED [ 50%] tests/unit/test_s3example.py::test_lambda_handler PASSED [100%] デプロイ デプロイの準備を進めます。 複数の関数のデプロイを試したかったためこれまで触れていなかったHelloWorldFunctionも含まれます。 hello_world/Dockerfile FROM public.ecr.aws/lambda/python:3.9 COPY app.py s3example.py requirements.txt ./ RUN python3.9 -m pip install -r requirements.txt -t . template.yaml AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > python3.9 Sample SAM Template for lambda-python3.9 # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Resources: MyS3Bucket: Type: AWS::S3::Bucket HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: PackageType: Image #Handler: app.lambda_handler ImageConfig: Command: - "app.lambda_handler" Role: {先の手順で作成したLambda 実行ロールの ARN} Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get Metadata: Dockerfile: Dockerfile DockerContext: ./hello_world DockerTag: python3.9-v1 S3exampleFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: PackageType: Image #Handler: s3example.lambda_handler ImageConfig: Command: - "s3example.lambda_handler" Role: {先の手順で作成したLambda 実行ロールの ARN} Events: S3exampleEvent: Type: S3 Properties: Bucket: !Ref MyS3Bucket Events: s3:ObjectCreated:* Metadata: Dockerfile: Dockerfile DockerContext: ./hello_world DockerTag: python3.9-v1 S3イベントの指定の仕方について参考にさせていただきました。 (samconfig.toml作成済み) $ sam build $ sam deploy デプロイが完了したら動作確認をします。 コンソールからS3サービス画面に行き、作成されているS3バケットでファイルをアップロードします。 書き込み用バケットにzipファイルが作成されました。 おわりに Lambda関数、慣れたら便利ですが、ログがわかりづらく慣れるまで戸惑いがありました。 config情報の環境変数化、レイヤーイメージやライブラリ同梱まで手が回りませんでした。 以下覚書です。 Commandを定義しないと2つ目の関数ハンドラが1つ目になる(関数名は2つ目だがハンドラがDockerfileのCMDにある1つ目になる) HandlerはImageと併用できない Bucketは、同じ定義ファイル内のものを!Refで呼ぶ必要がある Roleは、指定しないと特に権限がない実行ロールが作成され関数に紐づく S3トリガーは、コンソール画面のLambdaからは見えないがS3の「イベント通知」でLambdaと紐づいているのが確認できる S3の「イベント通知」でコンソールから編集(何も変えずOK)するとLambda側のトリガーとして表示される 動作確認は、Lambdaの「テスト」か、本来のイベントを実行しCloudWatch log デプロイ時、おかしくなったらコンソールからCloudFormationの関連スタックを削除 template.yamlを修正したらsam buildからやり直す boto3は、イメージに最初から含まれているのでinstall不要。 お疲れ様でした。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonの環境構築

目次 動作環境
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】ccxtライブラリをmacOSにインストールしてみた

はじめに みなさんmacOSにpythonのライブラリをインストールして活用していますか? 今回はccxtライブラリをインストールする方法を紹介します。 環境 ・python3.7 ・macOS(Catalina 10.15.7) 参考 私は色々なライブラリをインストールしすぎてもう何が入っているかもうわかりません。 そんな時はターミナルで確認ができます。 右上の虫眼鏡マークをクリックし[ターミナル]と入力します。 トップヒットに出てくるターミナルをクリックします。 以下のコマンドを入力して下さい。 $ pip3 list インストールしたライブラリの一覧が表示されます。 プログラム さて、今回はccxtというライブラリをインストールしたいと思います。 ccxtとは複数の仮想通貨取引所のAPI操作が集約されたライブラリです。ccxtを実行することで複数取引所のAPIを容易に呼び出せます。なので仮想通貨の板情報を取得したり、取引を自動化することができます。 私はwindows環境にインストールして情報取得していたのですが、macOS環境にはインストールしていなかったのでインストールしてみたいと思います。 ちなみにccxtをインストールしていない状態でimport ccxtコマンドを打つと以下のようなエラーメッセージが出力されます。 Traceback (most recent call last): File "/Users/hirockio/Desktop/ccxt.py", line 1, in <module> import ccxt ModuleNotFoundError: No module named 'ccxt' ではccxtライブラリをインストールしてみましょう。 と言っても超かんたんです。 1.ターミナルを起動します。 2.以下のコマンドを入力します。 $ pip3 install ccxt 以下のエラーが発生した場合は、インストールの権限がありません。 スーパーユーザで実行する必要があります。 Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/ccxt-1.55.95.dist-info' Consider using the `--user` option or check the permissions. スーパーユーザでコマンドを実行する必要があります。パスワードが聞かれますので入力して下さい。 余談ですが「sudo」は「substitute user(もしくはswitch user) do」の略みたいです。 $ sudo pip3 install ccxt 以下が表示されたらインストール成功です。 Successfully installed ccxt-1.55.95 最後に ccxtの使い方はまた別の記事に書きたいと思います。 ご参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OpenCVのカスケード分類器のパラメータをリアルタイムで変化させて顔認識結果を確認できるアプリを作りました。

はじめに 画像データ扱ってディープラーニングやってみたいとなったら、顔認識は鉄板ですよね。 顔認識やりたいとなった時に、顔の部分だけを切り出した画像を用意しないといけないわけですが、OpenCVのカスケード分類器を使うことが多いと思います。 あれって公式Githubに顔のカスケード分類器だけで4種類もあって、どれ使えば..ってなるし いざ顔認識させようと思ったらdetectMultiscaleのハイパーパラメータ調整に悩んでしまわないですか? ということで4種類の学習済みカスケード分類器と、ハイパーパラメータの値をリアルタイムで変化させて、識別結果を確認できるアプリをStreamlitで作成しました。 また画像を回転させる機能も実装しました。 ハイパーパラメータ調整で悩んでいる方の助けになれば幸いです。 アプリ本体: カスケード分類器シミュレーター ソースコード: Github アプリイメージ⇩ 環境・ツール Anacondaの仮想環境を使用しました。 VScodeでコーディング。 python: 3.9.5 opencv: 4.5.1 streamlit: 0.84.1 Streamlitに関して 個人的にめちゃ推しのライブラリです。 フロントエンドからバックエンドまでpythonファイルだけで完結するし、デプロイも楽という、僕みたいなよわよわエンジニアにはたまらんですね。 もちろんフロントエンドも凝ろうとすると難しいですが、プロトタイプのアプリや、とにかく形にしたいとなった時重宝するんではないかと思います。 後、意外とスペックは高くて驚きます。 コチラの記事で紹介している顔認識アプリもStreamlitで作ったのですが、学習済みモデルの容量が500MB近くでまぁherokuになんてデプロイできないんですよ。 またGCPのApp Engineにもコチラの顔認識アプリをFlaskで実装し直して、デプロイしてみたんですが、一番マックスのインスタンスタイプ(メモリ2GBくらいの)ですらオーバーしてデプロイできないくらい消費メモリもエグいアプリなんですよ。 それをStreamlitはまぁまぁの速度で動かしてくれるんで正直ビビってます。 Streamlitのアプリのギャラリーには他にも「こんなものまで作れるんか!」みたいなアプリもあるので是非見てみてください。 コード紹介 画像の回転処理に関してはコチラの記事を参考にしております。 main.py import streamlit as st import numpy as np import cv2 from PIL import Image # 学習済みカスケードファイル一覧 cascade_alt_tree_path = 'haarcascade_frontalface_alt_tree.xml' cascade_alt_path = 'haarcascade_frontalface_alt.xml' cascade_alt2_path = 'haarcascade_frontalface_alt2.xml' cascade_default_path = 'haarcascade_frontalface_default.xml' # カスケード分類器をインスタンス化 cascade_alt_tree = cv2.CascadeClassifier(cascade_alt_path) cascade_alt = cv2.CascadeClassifier(cascade_alt_path) cascade_alt2 = cv2.CascadeClassifier(cascade_alt2_path) cascade_default = cv2.CascadeClassifier(cascade_default_path) # 辞書化 cascade_dict = { 'alt_tree' : cascade_alt_tree, 'alt' : cascade_alt, 'alt2' : cascade_alt2, 'default' : cascade_default } # タイトル st.title('カスケード分類器シミュレーター') # サイドバー selected_cascade = st.sidebar.selectbox('カスケード分類器を選択してください。', ['alt_tree', 'alt', 'alt2', 'default']) # 識別に使うカスケード分類器 use_cascade = cascade_dict[selected_cascade] selected_scale = st.sidebar.slider(label='scaleFactorの値を設定してください。', min_value=1.01, max_value= 2.0, value = 1.1) selected_min_neighbors = st.sidebar.slider(label='minNeighborsの値を設定してください。', min_value=1, max_value=20, value=2) selected_min_size = st.sidebar.slider(label='minSizeの値を設定してください。', min_value=1, max_value=400, value = 50) selected_angle = st.sidebar.slider(label='回転角の設定(左回転)', min_value= -180, max_value=180, value=0) selected_color_name = st.sidebar.selectbox('描画する四角形の色を選択してください。', ['赤', '白', '緑', '青', '黄色', '黒']) color_dict = { '赤' : (255,0,0), '白' : (255,255,255), '緑' : (0,128,0), '青' : (0,0,255), '黒' : (0,0,0), '黄色' : (255,255,0) } selected_color = color_dict[selected_color_name] # メインコンテンツ col1, col2 = st.columns(2) with col1: st.write('以下の設定で顔認識を行います。') st.text(f'カスケード分類器: {selected_cascade}') st.text(f'scaleFactor: {selected_scale}') st.text(f'minNeighbors: {selected_min_neighbors}') st.text(f'minSize: ({selected_min_size}, {selected_min_size})') if selected_angle == 0: st.text('画像を回転させない') elif selected_angle > 0: st.text(f'画像を左に{selected_angle}° 回転' ) elif selected_angle < 0: st.text(f'画像を右に{-selected_angle}° 回転' ) with col2: uploaded_file = st.file_uploader('画像をアップロードすると識別を開始します。', type=['jpg', 'jpeg', 'png']) # 画像がアップロードされた時 if uploaded_file is not None: img = Image.open(uploaded_file) np_img = np.array(img, dtype =np.uint8) img_gray = cv2.cvtColor(np_img, cv2.COLOR_BGR2GRAY) # 回転処理 if selected_angle != 0: height, width = np_img.shape[:2] size = (height, width) angle_rad = selected_angle / 180.0*np.pi w_rot = int(np.round(height*np.absolute(np.sin(angle_rad))+width*np.absolute(np.cos(angle_rad)))) h_rot = int(np.round(height*np.absolute(np.cos(angle_rad))+width*np.absolute(np.sin(angle_rad)))) size_rot = (w_rot, h_rot) # 元画像の中心を軸にして画像を回転させる center = (width/2, height/2) scale = 1.0 rotation_matrix = cv2.getRotationMatrix2D(center, selected_angle, scale) # 平行移動を加える affine_matrix = rotation_matrix.copy() affine_matrix[0][2] = affine_matrix[0][2] -width/2 + w_rot/2 affine_matrix[1][2] = affine_matrix[1][2] -height/2 + h_rot/2 np_img = cv2.warpAffine(np_img, affine_matrix, size_rot, flags=cv2.INTER_CUBIC) img_gray = cv2.cvtColor(np_img, cv2.COLOR_BGR2GRAY) face_list = use_cascade.detectMultiScale(img_gray, scaleFactor = selected_scale, minNeighbors = selected_min_neighbors, minSize = (selected_min_size, selected_min_size)) face_number = len(face_list) if face_number == 0: st.error('顔が検出されませんでした。') st.image(np_img) if face_number > 0: for rect in face_list: cv2.rectangle(np_img, tuple(rect[0:2]), tuple(rect[0:2]+rect[2:4]), selected_color, thickness = 4) st.image(np_img) 素人なのでコーディングセンス壊滅のコードで見づらいですね...。 すいません。 Streamlitは他の言語で実装するってなると躊躇うような、スライダーやリスト、画像アップローダーなどをめちゃ簡単に実装できてしまうのがたまらんですね。 もっと流行ってほしい。 実際に動かしてみる いつものごとく推しメンの田村保乃ちゃんの画像を使います。 正面のやつだと簡単に認識しちゃうので、斜めの自撮り画像でやってみましょう。 初期の設定のパラメータだとダメですね。 scaleFactorを1.09にしてみます。 ちゃんと認識されましたね。 このままカスケード分類器をalt2にしてみます。 検知してくれませんね。このまま画像回転も試して見ましょう。左に斜めになっているので右回転させます。 おおー認識してくれました。 とこんな感じでいちいちコード上の数値を変えたり、for文で繰り返したりすることなく、リアルタイムでパラメータ変えてシミュレーションできるので、(ニーズがあるかは別として)個人的には満足するものができたと思います。 まとめ 実際に動かしてみて、ちょっとパラメータを変えるだけで検出結果がすぐ変わるので、顔認識のパラメータ調整の大変さを再認識することになりました。 これを画像ごとに自動的に最適なパラメータを設定して認識するようなアプリ、仕組みも作ってみたいですね。 顔認識のパラメータ調整に悩んでいる方の手助けや、Streamlitの魅力が少しでも伝われば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python3でCSVからJSONへ変換する

Python3を使用して、CSVファイルをJSONファイルに変換します。 実行方法 $ python3 csv2json.py -i <入力CSVファイル> -o <出力JSONファイル> --delimiter ',' --header-only 0 オプション 値 -i 入力CSVファイル -o 出力JSONファイル --delimiter CSV区切り文字 --header-only 0: データも含めて出力したい, 1: ヘッダのみを出力したい コード csv2json.py import csv import json import argparse parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', help='Input file name (CSV)', required=True) parser.add_argument('-o', '--output', help='Output file name (JSON)', required=True) parser.add_argument('--delimiter', help='Input CSV Delimiter') parser.add_argument('--header-only', type=int, help='Output only header (Exclude data) 0:True/1:False', choices=[0,1]) args = parser.parse_args() input_file = args.input output_file = args.output header_only = 0 if args.header_only in globals(): header_only = args.header_only csv_delimiter = ',' if args.delimiter in globals(): csv_delimiter = args.delimiter print("Input File:" + input_file) print("Output File:" + output_file) result = [] f_input_file = open(input_file, "r") if header_only == 1: data = csv.reader(f_input_file, delimiter=csv_delimiter, doublequote=True, quotechar='"', skipinitialspace=True) for row in data: for col in row: result.append(col) break else: data = csv.DictReader(f_input_file, delimiter=csv_delimiter, doublequote=True, quotechar='"', skipinitialspace=True) for row in data: result.append(row) f_output_file = open(output_file, "w") f_output_file = json.dump(result, f_output_file, indent=2, ensure_ascii=False)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自社サイトのアクセス状況をネットワーク状に可視化するとかっこよかった話

背景  日頃アクセス解析系のデータ分析をお手伝いさせていただく中で、サイトのざっくりの特徴を一目で分かるビジュアライズが欲しいと考えておりました。 ふと「ネットワーク化したら全体がイメージで掴めて良いのではないか?」という考えが舞い降り、一旦自社データで試してみることにしました。 明確な目的や設計があったわけではないので軽いお遊びの感覚で見ていただけると幸いです。 実現方法 システム構成 一旦最小限の開発で実現するために以下構成で可視化を行いました。 シンプルですが接続先さえ変えれば移植できるので割と実用性もある気がしています。 元データ : GoogleAnalytics4 (Bigquery連携済) 実行環境 : Google Colaboratory 言語 : python ライブラリ : NetworkX 可視化の設計 どのように可視化するかについては個人的に気になる「流入・回遊」がみれるよう設計しました。 円の大きさ : 流入の大きさ 線の向き : 回遊の繋がり 線の大きさ : 回遊の大きさ 結果 グラフ 示唆 円が大きいのに回遊されてない箇所がある 記事としては良いがサイト誘導ができていないため、誘導文言等の修正など検討すべき 回遊してるサイトからユーザー像が浮かび上がってくる 「firebaseやNuxt周りの技術興味ありor相談したい」と「経営者個人を知りたい層」の2つがありそう どこを次に掘ってみたいかがわかりそう 注意点 示唆が「得られそう」とあえてふわっと書いたのですが、 まだまだ以下のようなツッコミポイントは多いので、 安直に信じて良い状態になっているとは言い切れないところです 入口の可視化はできてる?離脱は? 回遊の向きが重要じゃない? pvあってもUUが重要じゃない? 感想 かっこよさを求めて始めた試みですが想像よりも使えそうなものが出て驚きました。 今までの案件でも似た提案をしたことはあったので、 もう少し詳細を詰めれば使えるものになっていくのではないかと思われます。 グラフの直感的わかりやすさに可能性がありそうです。 詳細については以下社内ブログに記載したので気になる方は是非! https://www.sink-capital.com/blogs/access_network/ (数ヶ月後にはブログから自社サイトに向けて太い線が繋がっていることを願ってます...笑)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自社サイトのアクセス状況をネットワーク上に可視化するとかっこよかった話

背景  日頃アクセス解析系のデータ分析をお手伝いさせていただく中で、サイトのざっくりの特徴を一目で分かるビジュアライズが欲しいと考えておりました。 ふと「ネットワーク化したら全体がイメージで掴めて良いのではないか?」という考えが舞い降り、一旦自社データで試してみることにしました。 明確な目的や設計があったわけではないので軽いお遊びの感覚で見ていただけると幸いです。 実現方法 システム構成 一旦最小限の開発で実現するために以下構成で可視化を行いました。 シンプルですが接続先さえ変えれば移植できるので割と実用性もある気がしています。 元データ : GoogleAnalytics4 (Bigquery連携済) 実行環境 : Google Colaboratory 言語 : python ライブラリ : NetworkX 可視化の設計 どのように可視化するかについては個人的に気になる「流入・回遊」がみられるように設計しました。 円の大きさ : 流入の大きさ 線の向き : 回遊の繋がり 線の大きさ : 回遊の大きさ 結果 グラフ 示唆 円が大きいのに回遊されてない箇所がある 記事としては良いがサイト誘導ができていないため、誘導文言等の修正などを検討すべき 回遊しているサイトからユーザー像が浮かび上がってくる 「firebaseやNuxt周りの技術興味ありor相談したい」と「経営者個人を知りたい層」の2つがありそう どこを次に掘ってみたいかがわかりそう 注意点 示唆が「得られそう」とあえてふわっと書いたのですが、 まだまだ以下のようなツッコミポイントは多いので、 安直に信じて良い状態になっているとは言い切れないところです 入口の可視化はできてる?離脱は? 回遊の向きが重要じゃない? pvあってもUUが重要じゃない? 感想 かっこよさを求めて始めた試みですが想像よりも使えそうなものができて驚きました。 今までの案件でも似た提案をしたことはあったので、 もう少し詳細を詰めれば使えるものになっていくのではないかと思われます。 グラフの直感的わかりやすさに可能性がありそうです。 詳細については以下社内ブログに記載したので気になる方は是非! https://www.sink-capital.com/blogs/access_network/ (数ヶ月後にはブログから自社サイトに向けて太い線が繋がっていることを願ってます...笑)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】気象庁のデータから47都道府県の雨温図を生成

背景 ふとしたきっかけで日本全国の雨温図が見たくなったので、Pythonを使って雨温図を作ってみました。 作ったもの 今回は、以下のようなExcelファイルと雨温図を作ります。 環境 Windows 10 Python 3.9.1 pandas 1.24 matplotlib 3.4.1 numpy 1.19.3 作成手順 データの取得 気象庁が過去の気象データを公開しているので、そこから気象データをダウンロードします。 今回は、以下の検索条件を指定しました。 地点 各都道府県の県庁所在地(手動ですべて選択しました) 項目 月平均気温 降水量の月合計 「過去の平均値との比較オプション」の「平均値も表示」 期間 連続した期間で表示(2020年1月 ~ 2020年12月) (指定する年度は任意) 表示オプション 利用上注意が必要なデータの扱い→ 値を表示(格納)しない。 観測環境などの変化の前後で、値が不均質となったデータの扱い→観測環境などの変化前の値を表示(格納)しない。 ダウンロードCSVファイルのデータ仕様→データ表示画面と同様に、数値以外の記号を含む 表示オプションは設定しなくても構いませんが、設定しておくと後のデータの整理が楽になります。 気象データの整理 csvの読み込み import pandas as pd df = pd.read_csv("ダウンロードしたcsvファイルのパス", header = 1, index_col = 0, encoding="cp932") そのまま読み込むと文字化けしてしまったので、この記事1を参考にencoding="cp932"を指定しました。 必要な部分の抽出 length = len(df.columns) df = df.iloc[:, 1:length:2] # 1行飛ばしで抽出 df = df[2:14] 今回作成する雨温図には各項目の過去の平均値を用いることにします。 過去の平均値は1列飛ばしとなっているので、[:, 1:length:2]として抽出しています。 また、上から2行の情報はいらないので必要な行のみを抽出します。 型の変換 df = df.astype("float") 最初に格納されている数値のデータ型はstr型です。このままだとこの後うまくグラフを作ることができないのでデータ型をfloatに変換しておきます。 Excelファイルへの書き出し it = iter(df.columns.tolist()) with pd.ExcelWriter("weathers.xlsx") as writer: for i, j in zip(it, it): sheet_name = i.replace(".1", "") df_new = df[[i, j]] df_new.columns = ["平均気温", "降水量"] df_new.index = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"] df_new.to_excel(writer, index=True, sheet_name=sheet_name) 各県庁所在地の「平均気温」と「降水量」を、それぞれ個別に各県庁所在地名のシートにしてExcelファイルに出力しています。 データフレームから連続する二つの列を抽出する方法については、この記事2を参考にしました。 各県庁所在地名は取得した最初の列名から.1を取り除くことにより取得しています。 また、後からわかりやすいようにに列名と行名を変更しています。 雨温図の作成 Excelファイルの読み取り dfs = pd.read_excel("weathers.xlsx", sheet_name=None) 先ほど作成したExcelファイルを読み込みます。 複数シートの読み込みについてはこの記事3を参考にしました。 このときdfsは、シート名(ここでは「県庁所在地」)がキーkey、シートのデータ(ここでは「平均気温」と「降水量」)が値valueとなる辞書dictとなっています。 雨温図の作成 import matplotlib.pyplot as plt import japanize_matplotlib import numpy as np city_code = 1 for item in dfs.items(): city_name = item[0] df = item[1] df = df.rename(columns={"Unnamed: 0": "月"}) # 各グラフの色を指定 color_temperature = "orangered" color_waterfall = "deepskyblue" # グラフ描画領域を作成 fig,ax1=plt.subplots(figsize=(5,8)) ax2=plt.twinx(ax1) # グラフを描画 plt.title(city_name) ax1.plot(df["月"], df["平均気温"], zorder=100, color=color_temperature, label="平均気温", alpha= 1) ax2.bar(df["月"], df["降水量"], zorder=1, color=color_waterfall, label="降水量", edgecolor='#333', linewidth=1, alpha = 0.5, width=1) ax1.set_ylabel("気温(℃)") ax2.set_ylabel("降水量(mm)") ax1.set_yticks(np.array(range(-10, 41, 10))) ax2.set_yticks(np.array(range(0, 501, 100))) ax1.grid(which = "major", axis = "y", color = "gray", alpha = 0.5, linewidth = 1) ax1.set_axisbelow(True) handler1, label1 = ax1.get_legend_handles_labels() handler2, label2 = ax2.get_legend_handles_labels() # 凡例をまとめて出力 ax1.legend( handler1 + handler2, label1 + label2, loc="upper right", borderaxespad=0, ) plt.savefig(f"./{city_code}_{city_name}.png") city_code += 1 雨温図を作成します。このグラフの作成の大部分はこの記事4を参考にしました。 https://life-freedom888.com/pandas-csv-mojibake/ ↩ https://hk29.hatenablog.jp/entry/2020/10/25/134840 ↩ https://note.nkmk.me/python-pandas-read-excel/ ↩ https://data-anal-ojisan.com/2020/08/26/229/ ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】気象庁のデータから47都道府県庁所在地の雨温図を生成してみる

背景 ふとしたきっかけで急に日本全国の雨温図を自作してみたくなったので、Pythonを使って各県庁所在地の雨温図を作ってみました。 作ったもの 今回は、以下のようなExcelファイルと雨温図を作ります。 Excelファイル 雨温図 環境 Windows 10 Python 3.9.1 pandas 1.24 matplotlib 3.4.1 numpy 1.19.3 作成手順 データの取得 気象庁が過去の気象データを公開しているので、そこから気象データをダウンロードします。 今回は、以下の検索条件を指定しました。 地点 各都道府県の県庁所在地 項目 月平均気温 降水量の月合計 「過去の平均値との比較オプション」の「平均値も表示」 期間 連続した期間で表示(2020年1月 ~ 2020年12月) (指定する年度は任意) 表示オプション 利用上注意が必要なデータの扱い→ 値を表示(格納)しない。 観測環境などの変化の前後で、値が不均質となったデータの扱い→観測環境などの変化前の値を表示(格納)しない。 ダウンロードCSVファイルのデータ仕様→データ表示画面と同様に、数値以外の記号を含む 表示オプションは設定しなくても構いませんが、設定しておくと後のデータの整理が楽になります。 気象データの整理 csvの読み込み import pandas as pd df = pd.read_csv("ダウンロードしたcsvファイルのパス", header = 1, index_col = 0, encoding="cp932") そのまま読み込むと文字化けしてしまったので、この記事1を参考にencoding="cp932"を指定しました。 必要な部分の抽出 length = len(df.columns) df = df.iloc[:, 1:length:2] # 1行飛ばしで抽出 df = df[2:14] 今回作成する雨温図には各項目の過去の平均値を用いることにします。 過去の平均値は1列飛ばしとなっているので、[:, 1:length:2]として抽出しています。 また、上から2行の情報はいらないので必要な行のみを抽出します。 型の変換 df = df.astype("float") 最初に格納されている数値のデータ型はstr型です。このままだとこの後うまくグラフを作ることができないのでデータ型をfloatに変換しておきます。 Excelファイルへの書き出し it = iter(df.columns.tolist()) with pd.ExcelWriter("weathers.xlsx") as writer: for i, j in zip(it, it): sheet_name = i.replace(".1", "") df_new = df[[i, j]] df_new.columns = ["平均気温", "降水量"] df_new.index = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"] df_new.to_excel(writer, index=True, sheet_name=sheet_name) 各県庁所在地の「平均気温」と「降水量」を、それぞれ個別に各県庁所在地名のシートにしてExcelファイルに出力しています。 データフレームから連続する二つの列を抽出する方法については、この記事2を参考にしました。 各県庁所在地名は取得した最初の列名から.1を取り除くことにより取得しています。 また、後からわかりやすいようにに列名と行名を変更しています。 雨温図の作成 Excelファイルの読み取り dfs = pd.read_excel("weathers.xlsx", sheet_name=None) 先ほど作成したExcelファイルを読み込みます。 複数シートの読み込みについてはこの記事3を参考にしました。 このときdfsは、シート名(ここでは「県庁所在地」)がキーkey、シートのデータ(ここでは「平均気温」と「降水量」)が値valueとなる辞書dictとなっています。 雨温図の作成 import matplotlib.pyplot as plt import japanize_matplotlib import numpy as np city_code = 1 for item in dfs.items(): city_name = item[0] df = item[1] df = df.rename(columns={"Unnamed: 0": "月"}) # 各グラフの色を指定 color_temperature = "orangered" color_waterfall = "deepskyblue" # グラフ描画領域を作成 fig,ax1=plt.subplots(figsize=(5,8)) ax2=plt.twinx(ax1) # グラフを描画 plt.title(city_name) ax1.plot(df["月"], df["平均気温"], zorder=100, color=color_temperature, label="平均気温", alpha= 1) ax2.bar(df["月"], df["降水量"], zorder=1, color=color_waterfall, label="降水量", edgecolor='#333', linewidth=1, alpha = 0.5, width=1) ax1.set_ylabel("気温(℃)") ax2.set_ylabel("降水量(mm)") ax1.set_yticks(np.array(range(-10, 41, 10))) ax2.set_yticks(np.array(range(0, 501, 100))) ax1.grid(which = "major", axis = "y", color = "gray", alpha = 0.5, linewidth = 1) ax1.set_axisbelow(True) handler1, label1 = ax1.get_legend_handles_labels() handler2, label2 = ax2.get_legend_handles_labels() # 凡例をまとめて出力 ax1.legend( handler1 + handler2, label1 + label2, loc="upper right", borderaxespad=0, ) plt.savefig(f"./{city_code}_{city_name}.png") city_code += 1 雨温図を作成します。このグラフの作成の大部分はこの記事4を参考にしました。 おまけ せっかく雨温図を作ったので、地域ごとに雨温図を見てみましょう。 北海道 太平洋側 日本海側 中央高地 瀬戸内 南西諸島 おわりに 雨温図を自作することによって、地域ごとの気候の特徴がより分かりやすくなったと思います。ここまで読んでくださった方も、この記事によって少しでも地域ごとの気候に興味を持っていただけら幸いです。 https://life-freedom888.com/pandas-csv-mojibake/ ↩ https://hk29.hatenablog.jp/entry/2020/10/25/134840 ↩ https://note.nkmk.me/python-pandas-read-excel/ ↩ https://data-anal-ojisan.com/2020/08/26/229/ ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GCEにマイクラサーバーを立てた記録

はじめに MineCraft、楽しいですよね。 ステイホームな昨今、仲間内で気軽に集って遊ぶ用にマイクラのサーバーを立てる計画が立ちました。 さくらのVPSやConoHaといった便利なレンタルサーバーもあるようですが、 今回はお勉強も兼ねて自力でGCPで立てることとしました。 前提 GCPコンソールが利用できること。 discordアカウントを持っていること。 要件 好きな時にログインでき、最大10人弱が同時にログインできるような環境が求められてました。 課金額を最小限にするために遊ぶときだけサーバーをオンにしたいですが、筆者以外のメンバーはGCPのGの字も知らないので、誰でも簡単にサーバーオンオフができる仕組みが必要でした。 あと、極力サクッと。。(構築じゃなくて建築がしたいんです) 構成 MineCraftサーバー GCEインスタンスに公式から出ているサーバーソフトウェアを入れて構築します。 また、マイクラに接続するためにudp: 19132のポート開放が必要なため、firewallをかませます。 サーバーのオンオフ 普段ゲーム中の通話ツールとして使用しているdiscordなら馴染みやすいだろうということで、 discordのチャットから、サーバーの起動・停止をするBotを作ることとします。 Botのデプロイ先として、マイクラサーバーとは別のGCEインスタンスを用意します。 また、遊び終わった後のサーバーオフを忘れて課金額がかさむのは悲しいですね。 そんなことがないよう、CloudFunctions + CloudSchedulerで定時にサーバーを必ずオフにする仕組みを作ります。 図で表すとこんな感じ 手順 ここから長くなりますが、各構築手順について細かく説明していきます。 MineCraftサーバー構築 1. インスタンスの作成 「Compute Engine」 → 「VMインスタンス」 → 「インスタンスを作成」でマイクラ用のインスタンスを作りましょう。 各パラメータは以下の通り。特に書いてないやつは任意で大丈夫です。 項目 値 備考 名前 minecraft-server - リージョン asia-northeast1 - ゾーン asia-northeast1-b - マシンタイプ n1-standard-1 スペックが低いとゲームが重くなるので、ある程度は確保したいです ブートディスク Ubuntu 20.04 LTS Ubuntu用の公式サーバーソフトウェアを使うので ラベル キー:env 値:minecraft 最後のCloudScheduler設定で必要になります ネットワークタグ 任意 ファイアウォール設定用に必要なので何かしらつけておきましょう 2. 外部IPアドレスの固定 静的IPアドレスを取得して、先ほど作成したインスタンスに設定します。 「ネットワーキング」 → 「VPCネットワーク」 → 「外部IPアドレス」 → 「静的アドレスを予約」で設定画面へ移り、 各値を入れて「予約」を押下します。 項目 値 備考 名前 任意 適当でOK リージョン asia-northeast1 インスタンスと合わせます 接続先 1で立てたマイクラサーバー名 - 3. ファイアウォールの設定 「ネットワーキング」→「VPCネットワーク」→「ファイアウォール」→「ファイアウォールルールを作成」で設定画面へ移ります。 各値を入れて「作成」を押下します。 項目 値 備考 名前 任意 - ターゲット 指定されたターゲットタグ - ターゲットタグ 1で設定したネットワークタグ - ソースフィルタ IP範囲 - ソースIPの範囲 0.0.0.0/0 - プロトコルとポート 指定したプロトコルとポート - udp 19132 - 4. サーバーの設定 ここから本番。インスタンスにSSH接続して各種設定をしていきます。 4-1. SSH接続 「Compute Engine」 → 「VMインスタンス」でコンソールを開きます。 1で作成したインスタンスを起動したら、SSH接続してください。 4-2. MineCraftのDL 公式からサーバーソフトウェアをDLします。 事前にUbuntu版サーバーソフトウェアのURLをコピーしておきましょう。 #!/bin/bash # 初めの準備 sudo apt update mkdir /home/minecraft cd /home/minecraft # MinecraftサーバーソフトウェアをDL(コピーしたURLを使う) wget https://minecraft.azureedge.net/bin-linux/bedrock-server-1.17.11.01.zip # DLしたzipファイルの解凍 apt install -y zip unzip unzip bedrock-server-1.17.11.01.zip 4-3. MineCraftサーバーの常時稼働 実は4-2終了時点で、クライアント側からマイクラサーバーへの接続はできるようになっています。 が、このままではSSHを切断した時点でサーバーが落ちてしまうので、SSH接続を切ってもサーバーが稼働し続けるようにします。 #!/bin/bash # 実行権限の変更 sudo chmod 755 /home/minecraft/bedrock_server # screenでbedrock serverを起動 LD_LIBRARY_PATH=. screen -dmS bds /home/minecraft/bedrock_server screenコマンドについてはこちらの記事を参考にさせていただきました。 4-4. インスタンスの起動・停止に合わせたサーバーの起動・停止 現時点では、インスタンスを停止後再起動したら、またSSH接続してサーバーを起動しにいかなければいけません。 そんなことは到底面倒くさいので、インスタンスに合わせてサーバーも起動するようにします。 まずはインスタンスを停止してください。 停止したら、「インスタンスの詳細」→「編集」で編集画面に移り、カスタムメタデータの編集を行います。 ①起動用 キー: startup-script 値 LD_LIBRARY_PATH=. screen -dmS bds /home/minecraft/bedrock_server ②停止用 キー: shutdown-script 値 screen -r bds -X stuff 'stop\n' discordBot構築 ここからは、マイクラサーバーの起動・停止を担うdiscordBotを作成していきます。 1. インスタンスの作成 マイクラサーバー用と立て方は同じです。 「Compute Engine」 → 「VMインスタンス」 → 「インスタンスを作成」でインスタンスを作りましょう。 discordBot用はスペックはいらないので、各パラメータは無料枠に収まるようにします。 項目 値 備考 名前 discord-bot - リージョン us-central - ゾーン us-central1-a - マシンタイプ e2-micro 無料枠のスペックは公式ドキュメントを参照しておきましょう ブートディスク Ubuntu 20.04 LTS マイクラサーバーと合わせましたが、何でもいいです ファイアウォール HTTPトラフィックを許可する,HTTPSトラフィックを許可する discordとの通信のために開ける必要があります 2. サーバーの設定 2-1. SSH接続 SSH接続して、必要なものを入れていきます。 「Compute Engine」 → 「VMインスタンス」でコンソールを開いたら、インスタンスを起動してSSH接続してください。 2-2. discord.pyのインストール 今回dicordBotはdiscord.pyを利用して作成します。GCE内にdiscord.py関連を入れていきましょう。 #!/bin/bash # 初めの準備 sudo yum update # pythonのインストール yum install python3l   # discord.pyのインストール python3 -m pip install -U discord.py 2-2. Google Cloud SDK関係のインストール マイクラサーバーのオンオフはGCEの操作になるため、SDKをインストールする必要があります。 こちらは参考にさせていただいたこちらの記事の通りに行えば問題ありません。 ここで必要な作業は下記3点です。 Google Cloud SDKのインストール $ gc![discord.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1957879/8bdb30b0-64ea-d4d7-0274-d7e19a962559.png) loud initによる初期化 Google API Clientのインストール 3. discordの設定 ここではGCPを離れ、discord側を触っていきます。 といっても作業は多くありません。 3-1. サーバー/テキストチャンネル作成 普段使いのサーバーがあればそれを使えば構いません。discordが初めて!という場合だけ、サーバーを作成しましょう。 またBotにチャットを送るように、テキストチャンネルを一つ用意しましょう。 3-2. Bot登録/トークン取得 Discord Developer サイトから、以下を実施します。 - 新規Bot登録 - Bot用トークン取得 具体的な手順はこちらの記事を参考にさせていただきました。 3-3. Botの実装 いよいよBotの実装です。 こちらのbot.pyを参考にさせていただきました。 dsicordBot.py # 各種import import asyncio from time import sleep from googleapiclient import discovery import discord # BOTのアクセストークン TOKEN = '(取得したトークン)' # 接続に必要なオブジェクトを生成 client = discord.Client() # GCEインスタンス情報 PROJECT = '(PROJECT_ID)' ZONE = 'asia-northeast1-b' INSTANCE = '(INSTANCE_NAME)' # Build and initialize google api compute = discovery.build('compute', 'v1') # Bot起動時に動作する処理 @client.event async def on_ready(): print('Logged in as') print(client.user.name) print(client.user.id) print('------') # Discord - GCE間のやりとり @client.event async def on_message(message): # /minecraft から始まる各種コマンド' if message.content.startswith('/minecraft'): command = message.content.split(' ')[1] channel = message.channel # インスタンス起動コマンド' if command == 'start': m = await channel.send('Server starting up...') start_server(PROJECT, ZONE, INSTANCE) await m.edit(content='Success! Server started up.') sleep(10) await m.delete() # インスタンス停止コマンド' elif command == 'stop': m = await channel.send('Server stopping...') stop_server(PROJECT, ZONE, INSTANCE) await m.edit(content='Success! Server stopped.') sleep(10) await m.delete() # インスタンスのstatus確認コマンド' elif command == 'status': status = get_server_status(PROJECT, ZONE, INSTANCE) if status == 'RUNNING': m = await channel.send('Server is running! Please enjoy Minecraft!') sleep(10) await m.delete() elif status in {'STOPPING', 'STOPPED'}: m = await channel.send('Server is stopped. If you play Minecraft, please chat in this channel, `/minecraft start`.') sleep(10) await m.delete() else: m = await channel.send('Server is not running. Please wait for a while, and chat in this channel, `/minecraft start`.') sleep(10) await m.delete() await channel.send(m) # GCE操作の各関数定義 def start_server(project, zone, instance): compute.instances().start(project=project, zone=zone, instance=instance).execute() def stop_server(project, zone, instance): compute.instances().stop(project=project, zone=zone, instance=instance).execute() def get_server_status(project, zone, instance): res = compute.instances().get(project=project, zone=zone, instance=instance).execute() return res['status'] # Botの起動とDiscordサーバーへの接続 client.run(TOKEN) 作成できたら、任意のフォルダに配置しましょう。 3-4. botのサービス化 bot起動のために、サービス化してしまいます。 サービス化についてはこちらの記事等を参照しました。 serviceの作成 sudo su - cd /etc/systemd/system vi ./mc-discord-bot.service serviceの設定 [Unit] Description = Discord bot deamon [Service] User = (ユーザーの名前) ExecStart = (botの配置パス) Restart = always Type = simple [Install] WantedBy = multi-user.target サービス登録出来たら、起動します。 serviceの作成 #!/bin/bash sudo systemctl reload sudo systemctl enable mc-discord-bot.service sudo systemctl start mc-discord-bot.service 3-5. discordBotの稼働確認 ここまでで、discordのチャットからコマンドを入力すると、マイクラサーバーが起動/停止するようになります。 Bot作成時に指定したサーバーのテキストチャンネルから、以下を入力してみましょう。 discordへのBotからの返事+GCEインスタンス操作ができれば成功です。 /minecraft start :マイクラサーバーの起動 /minecraft stop :マイクラサーバーの停止 /minecraft status:マイクラサーバーのステータス確認 定時shutdown処理実装 最後に、定時でマイクラサーバーを停止する処理をCloudFunctions + CloudSchedulerを使って実装していきます。 1. 関数の作成 「Cloud Functions」 → 「関数の作成」から新しい関数を作りましょう。 discordBot用はスペックはいらないので、各パラメータは無料枠に収まるようにします。 項目 値 備考 関数名 stopInstance - リージョン asia-northeast1 - トリガー Cloud Pub/Sub - Cloud Pub/Subトピック選択 トピックを作成する 適当な名前でいいので、トピックを作成してしまいましょう 2. コードの作成 公式ドキュメントを参考に、今回はJavascriptで作成しました。 - ランタイム : Node.js 10 - エントリポイント : stopInstance index.js const Compute = require('@google-cloud/compute'); const compute = new Compute(); /** * Stops Compute Engine instances. * * Expects a PubSub message with JSON-formatted event data containing the * following attributes: * zone - the GCP zone the instances are located in. * label - the label of instances to stop. * * @param {!object} event Cloud Function PubSub message event. * @param {!object} callback Cloud Function PubSub callback indicating completion. */ exports.stopInstancePubSub = async (event, context, callback) => { try { const payload = _validatePayload(event); const options = {filter: `labels.${payload.label}`}; const [vms] = await compute.getVMs(options); await Promise.all( vms.map(async instance => { if (payload.zone === instance.zone.id) { const [operation] = await compute .zone(payload.zone) .vm(instance.name) .stop(); // Operation pending return operation.promise(); } else { return Promise.resolve(); } }) ); // Operation complete. Instance successfully stopped. const message = 'Successfully stopped instance(s)'; console.log(message); callback(null, message); } catch (err) { console.log(err); callback(err); } }; /** * Validates that a request payload contains the expected fields. * * @param {!object} payload the request payload to validate. * @return {!object} the payload object. */ const _validatePayload = event => { let payload; try { payload = JSON.parse(Buffer.from(event.data, 'base64').toString()); } catch (err) { throw new Error('Invalid Pub/Sub message: ' + err); } if (!payload.zone) { throw new Error("Attribute 'zone' missing from payload"); } else if (!payload.label) { throw new Error("Attribute 'label' missing from payload"); } return payload; }; package.json { "name": "cloud-functions-schedule-instance", "version": "0.1.0", "private": true, "license": "Apache-2.0", "author": "Google Inc.", "repository": { "type": "git", "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git" }, "engines": { "node": ">=12.0.0" }, "scripts": { "test": "mocha test/*.test.js --timeout=20000" }, "devDependencies": { "mocha": "^8.0.0", "proxyquire": "^2.0.0", "sinon": "^10.0.0" }, "dependencies": { "@google-cloud/compute": "^2.0.0" } } 3. CloudScheduler設定 「CloudScheduler」 → 「ジョブを作成」から新しいジョブを作ります。 項目 値 備考 名前 stopInstanceEvent - 頻度 0 4 * * * 例えば毎日朝4時に関数を動かしたい場合の設定です タイムゾーン 日本標準時 - ターゲットタイプ Pub/Sub - Cloud Pub/Subトピック選択 1で作成したトピック - メッセージ本文 {"zone":"asia-northeast1-b","label":"env=minecraft"} ここで対象とするインスタンスを指定しています。 最後に 長々と手順を書いてきましたが、ここまで実施すると以下ができるようになっています。 GCE上に立っているマイクラサーバーへの接続 discordからコマンドを打つことでマイクラサーバーの起動/停止 毎朝4時にマイクラサーバーの停止(仲間にはサーバーダウンの時間を周知しておきましょう) 無事遊べますね!ここからWin10版しかりswtich版からサーバーに接続していくことになりますが、 それはまた別のお話で。。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

python3でコーディングテストに受かるための自分メモ[9/7] (二重ループ、内包表記)

今回paizaでまたrun time errorで怒られた。 しかし、今回はうまく解決できた 二重ループ 今回私が書いたプログラムは二重ループであった。 それで処理時間が長いと怒られたのだが、 二重ループ以外でこの問題を解決する方法がわからなかったので、 愚行かと思ったができるだけ書き方のみでプログラムの実行時間を短くできないか取り組んだ。 ループで回す対象をrange(int)からlst 最初はrangeで数字を回し、 二次元配列にindexでアクセスしていた。 これをlistでループを回しアクセスするときは一次元配列にした。 これでだいぶ実行時間が早くなり、エラーが解消された。 ちなみに、listをループを回したのは外側だけであり、 内側はindexのままである。 結論 paizaにrun time errorで怒られた原因は 二重ループが原因だったというより、多次元配列に二重ループでアクセスしたことにより、実行時間が膨らんだことが原因だった模様。 調べてわかった新たな知見 ループでindexを回すのであればできるだけ、配列を回した方が実行時間が早くなる listの初期化では内包表記を使った方が少し早くなる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Cloud Functions(Python) でIP制限を行う

背景 Google Cloud FunctionsでIP制限を行いたい。 VPCSCやCloud Load Balancer経由のアクセスにすることによってIP制限を行う方法があるが、少し面倒。 今回はシンプルにpythonコードでIP制御をすることにした。 実装 Google Cloud FuntionsのPythonはFlaskで実装されている。 Flaskのリクエスト元アドレスは request.remote_addr で取得できる。 import ipaddress def ip_allowed(ip): ip = ipaddress.ip_address(ip) nw = ipaddress.ip_network(ip_range) return (ip in nw) def main(request): if not ip_allowed(request.remote_addr): raise Exception(f"IP not allowed: {request.remote_addr}") return 'IP allowed.' 参考 Get IP address of visitors using Flask for Python python ipaddressモジュールを使ってみたら便利だった話
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【python】IBM watson speech-to-text サンプル動かすときの注意点

音声ストリーミング文字起こしアプリのサンプルを動かす中で 躓いたところがあったので共有の意味も込めて投稿します。 【環境】 mac big sur 11.2.3 venv python3 【参考資料】 youtube: https://www.youtube.com/watch?v=YCyuZM454_I Github(IBM) : https://github.com/IBM/watson-streaming-stt 【躓いたこと】 実行時、 Handshake status 403 Forbidden というエラーが発生し、動作しない。 【原因】 speech to textセービス作成時のロケーション設定の問題。 【解決方法】 サービス作成時に ロケーションを「東京(ja-tok)」にせず「ワシントンDC(us-east)」にする。 それに伴い、 speech.cfg では「region」を speech.cfg apikey = <your API key> # Modify region based on where you provisioned your stt instance region = us-east とする。 日本語を認識させるには、 transcribe.py 175行目 のモデルを変更すればOK transcribe.py def get_url(): config = configparser.RawConfigParser() config.read('speech.cfg') # See # https://console.bluemix.net/docs/services/speech-to-text/websockets.html#websockets # for details on which endpoints are for each region. region = config.get('auth', 'region') host = REGION_MAP[region] return ("wss://{}/speech-to-text/api/v1/recognize" "?model=ja-JP_BroadbandModel").format(host) transcribe.py "?model=ja-JP_BroadbandModel").format(host)                   ↑ここ 他言語のモデルは、 https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models ここで確認できる。 【サンプルアプリの動かし方(簡易説明)】 上記参考資料記載のyoutubeまたは、IBMのGithubの通りに進めていけば簡単に動かすことができますが、流れを簡単に記載します。 ●IBMアカウントを作成し、  上記記載のロケーションに注意してサービスを作成する (https://www.ibm.com/jp-ja/cloud/watson-speech-to-text ) ●git cloneする (https://github.com/IBM/watson-streaming-stt ) git clone https://github.com/IBM/watson-streaming-stt.git ●必要なものをインストールする(pyaudioも必要) pip install -r requirements.txt ●プロジェクトをお好きなエディターで開き、  「speech.cfg.example」 ファイルを編集する ①API key/ region を入力する  *上記参照 ②ファイル名を変更 「speech.cfg.example」→「speech.cfg」   ●音声モデルを変更する *上記参照 ●ターミナルからコマンドを実行 python transcribe.py -t 20 最後の「20」は、プログラムを実行する秒数 マイクに話しかけてみて、ターミナルに話した文字が現れたらOK!! 単純な内容なのに、かなりの時間を使ってしまいました… 自分もこれから、リファレンス読んで色々試していこうと思います。 駆け出しの投稿ですので、お気づきの点ありましたらコメントのほどよろしくお願い致します!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【python】IBM watson speech-to-text サンプル動かすときのエラーHandshake status 403 Forbidden

音声ストリーミング文字起こしアプリのサンプルを動かす中で 躓いたところがあったので共有の意味も込めて投稿します。 【環境】 mac big sur 11.2.3 venv python3 【参考資料】 youtube: https://www.youtube.com/watch?v=YCyuZM454_I Github(IBM) : https://github.com/IBM/watson-streaming-stt 【躓いたこと】 実行時、 Handshake status 403 Forbidden というエラーが発生し、動作しない。 【原因】 speech to textセービス作成時のロケーション設定の問題。 【解決方法】 サービス作成時に ロケーションを「東京(ja-tok)」にせず「ワシントンDC(us-east)」にする。 それに伴い、 speech.cfg では「region」を speech.cfg apikey = <your API key> # Modify region based on where you provisioned your stt instance region = us-east とする。 日本語を認識させるには、 transcribe.py 175行目 のモデルを変更すればOK transcribe.py def get_url(): config = configparser.RawConfigParser() config.read('speech.cfg') # See # https://console.bluemix.net/docs/services/speech-to-text/websockets.html#websockets # for details on which endpoints are for each region. region = config.get('auth', 'region') host = REGION_MAP[region] return ("wss://{}/speech-to-text/api/v1/recognize" "?model=ja-JP_BroadbandModel").format(host) transcribe.py "?model=ja-JP_BroadbandModel").format(host)                   ↑ここ 他言語のモデルは、 https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models ここで確認できる。 【サンプルアプリの動かし方(簡易説明)】 上記参考資料記載のyoutubeまたは、IBMのGithubの通りに進めていけば簡単に動かすことができますが、流れを簡単に記載します。 ●IBMアカウントを作成し、  上記記載のロケーションに注意してサービスを作成する (https://www.ibm.com/jp-ja/cloud/watson-speech-to-text ) ●git cloneする (https://github.com/IBM/watson-streaming-stt ) git clone https://github.com/IBM/watson-streaming-stt.git ●必要なものをインストールする(pyaudioも必要) pip install -r requirements.txt ●プロジェクトをお好きなエディターで開き、  「speech.cfg.example」 ファイルを編集する ①API key/ region を入力する  *上記参照 ②ファイル名を変更 「speech.cfg.example」→「speech.cfg」   ●音声モデルを変更する *上記参照 ●ターミナルからコマンドを実行 python transcribe.py -t 20 最後の「20」は、プログラムを実行する秒数 マイクに話しかけてみて、ターミナルに話した文字が現れたらOK!! 単純な内容なのに、かなりの時間を使ってしまいました… 自分もこれから、リファレンス読んで色々試していこうと思います。 駆け出しの投稿ですので、お気づきの点ありましたらコメントのほどよろしくお願い致します!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【python】IBM watson speech-to-text サンプル動かすときのエラー「Handshake status 403 Forbidden」の原因

音声ストリーミング文字起こしアプリのサンプルを動かす中で 躓いたところがあったので共有の意味も込めて投稿します。 【環境】 mac big sur 11.2.3 venv python3 【参考資料】 youtube: https://www.youtube.com/watch?v=YCyuZM454_I Github(IBM) : https://github.com/IBM/watson-streaming-stt 【躓いたこと】 実行時、 Handshake status 403 Forbidden というエラーが発生し、動作しない。 【原因】 speech to textセービス作成時のロケーション設定の問題。 【解決方法】 サービス作成時に ロケーションを「東京(ja-tok)」にせず「ワシントンDC(us-east)」にする。 それに伴い、 speech.cfg では「region」を speech.cfg apikey = <your API key> # Modify region based on where you provisioned your stt instance region = us-east とする。 日本語を認識させるには、 transcribe.py 175行目 のモデルを変更すればOK transcribe.py def get_url(): config = configparser.RawConfigParser() config.read('speech.cfg') # See # https://console.bluemix.net/docs/services/speech-to-text/websockets.html#websockets # for details on which endpoints are for each region. region = config.get('auth', 'region') host = REGION_MAP[region] return ("wss://{}/speech-to-text/api/v1/recognize" "?model=ja-JP_BroadbandModel").format(host) transcribe.py "?model=ja-JP_BroadbandModel").format(host)                   ↑ここ 他言語のモデルは、 https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models ここで確認できる。 【サンプルアプリの動かし方(簡易説明)】 上記参考資料記載のyoutubeまたは、IBMのGithubの通りに進めていけば簡単に動かすことができますが、流れを簡単に記載します。 ●IBMアカウントを作成し、  上記記載のロケーションに注意してサービスを作成する (https://www.ibm.com/jp-ja/cloud/watson-speech-to-text ) ●git cloneする (https://github.com/IBM/watson-streaming-stt ) git clone https://github.com/IBM/watson-streaming-stt.git ●必要なものをインストールする(pyaudioも必要) pip install -r requirements.txt ●プロジェクトをお好きなエディターで開き、  「speech.cfg.example」 ファイルを編集する ①API key/ region を入力する  *上記参照 ②ファイル名を変更 「speech.cfg.example」→「speech.cfg」   ●音声モデルを変更する *上記参照 ●ターミナルからコマンドを実行 python transcribe.py -t 20 最後の「20」は、プログラムを実行する秒数 マイクに話しかけてみて、ターミナルに話した文字が現れたらOK!! 単純な内容なのに、かなりの時間を使ってしまいました… 自分もこれから、リファレンス読んで色々試していこうと思います。 駆け出しの投稿ですので、お気づきの点ありましたらコメントのほどよろしくお願い致します!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Twintの使い方

はじめに はじめまして、@Herbと申します。 普段はCOBOL,JCLを使用し仕事をしています。 COBOLは扱っていてあまり面白いと思えなかったのでPythonを勉強?しています。 その中で疑問に思ったことや解決に時間がかかったのもなどをメモとしてQiitaに投稿していこうと思います。 Twintとは? TwitterのAPIを使わずに、ツイートを取得することができるライブラリです。 Twintの使い方 Twintをインストールします。 Twint_install.py $ pip install twint ・特定ユーザーのツイートを取得する test.py import twint import nest_asyncio nest_asyncio.apply() # Configure c = twint.Config() #特定のユーザー名 c.Username = "Qiita" #実行日から数えて過去何日分のツイートを取得するか c.Limit = 1 #csv形式で保存するか c.Store_csv = True #保存ファイルの名前 c.Output = "Sample.csv" # Run twint.run.Search(c) ・実行結果 1434874028737564673 2021-09-06 22:40:01 +0900 <Qiita> 900LGTM! | RESTful APIとは何なのか https://t.co/rxOrNpNk2U 1434864160718917633 2021-09-06 22:00:49 +0900 <Qiita> 3200LGTM! | Kaggleに登録したら次にやること ~ これだけやれば十分闘える!Titanicの先へ行く入門 10 Kernel ~ by @upura0 https://t.co/rv0UnMqivX 1434861591623835649 2021-09-06 21:50:36 +0900 <Qiita> 100LGTM! | 3分で理解するG1ガベージコレクション https://t.co/sTZVQk2Nwl 1434859011946467332 2021-09-06 21:40:21 +0900 <Qiita> 2800LGTM! | VSCode に必ず入れておきたい拡張機能 by @ucan_lab https://t.co/t9MyWTPIYk 1434843949953339398 2021-09-06 20:40:30 +0900 <Qiita> 200LGTM! | PlantUMLをMac OS Xで使う by @hako584 https://t.co/vMMFjOcXf7 1434834295324127233 2021-09-06 20:02:08 +0900 <Qiita> 200LGTM! | 動的に生成したDOM要素に対してjQueryでイベントを設定する場合 https://t.co/DdzxOa9Olf 1434818910407249920 2021-09-06 19:01:00 +0900 <Qiita> 100LGTM! | 【Visual Studio Code】JSONを整形する方法 https://t.co/vntIol0FNg 1434816187876134915 2021-09-06 18:50:11 +0900 <Qiita> 100LGTM! | MySQLのデータベースをまるっとお引越し。 (エクスポート/インポート) https://t.co/oeGHvsYAC5 1434813686422675456 2021-09-06 18:40:15 +0900 <Qiita> 1500LGTM! | ログ出力のための print と import logging はやめてほしい by @amedama https://t.co/FN7OwPxFlv 1434801089199624192 2021-09-06 17:50:11 +0900 <Qiita> 800LGTM! | 「次から気をつけます」に対抗する、反省文よりは効果が上がる再発防止、学びの機会 by @e99h2121 https://t.co/uf9OVXmQRa 1434796529617932290 2021-09-06 17:32:04 +0900 <Qiita> 100LGTM! | 【Gatsby.js】「ここだけ押さえれば普通に使える」って知識をまとめてみた by @d0ne1s https://t.co/W86RdgtviL 1434773515090157570 2021-09-06 16:00:37 +0900 <Qiita> 100LGTM! | [Python]matplotlibで左右に2つの軸があるグラフを書く方法 https://t.co/qZLpC2yQ4y 1434760800137273345 2021-09-06 15:10:05 +0900 <Qiita> 100LGTM! | 21卒エンジニア 社会人6ヶ月目の働き方 by @hasehiro0828 https://t.co/2tpJb2VtzX 1434754585831227397 2021-09-06 14:45:24 +0900 <Qiita> @tmknom 最近計算式が新しくなりました!ちなみに内訳はこちらのページでご説明しています。 https://t.co/51NDWr8uYa 1434754457309384711 2021-09-06 14:44:53 +0900 <Qiita> @kabenonakaniiru ご利用ありがとうございます!ちなみに最近では補足のための記法を追加しました。 今後もより使いやすいものをお届けすべく開発していきます! https://t.co/ZJ08SrQP8u 1434750753390972929 2021-09-06 14:30:10 +0900 <Qiita> 200LGTM! | 足し算だけの世界の物語~第一話「鍵共有」 https://t.co/EFzeLHgdnw 1434748221583208449 2021-09-06 14:20:07 +0900 <Qiita> 100LGTM! | Docker Desktopに依存しない、WindowsでのDocker環境 https://t.co/z4D1YqIs7p 1434745706011676674 2021-09-06 14:10:07 +0900 <Qiita> 600LGTM! | OpenAPI (Swagger) 超入門 by @tei_nen https://t.co/W9ZA0rAVFq 1434744884355760128 2021-09-06 14:06:51 +0900 <Qiita> 【9/9開催】Qiita エンジニアフェスタ 2021 Online Meetup? スペシャルゲストはQiita創設者の海野氏。 Qiita立ち上げ〜現在までの10年間における裏話が聞けるかもしれません。当日はQiita初公開情報の解禁もありますので、ぜひご参加ください? 9/9(木)19:00 Zoom開催 https://t.co/d4F9ddTWWS 1434740647144083456 2021-09-06 13:50:01 +0900 <Qiita> 500LGTM! | 「ネットワークがおかしいんですけど」ハンドブック by @tak_hama_ https://t.co/TZaRGygIoQ なぜかわからないのですが、 TwintのGithubにあるテストコードをそのまま実行しようとすると、 ”RuntimeError: This event loop is already running”と出てしまいうまくいきませんでした。 そこで上記にも記載しているライブラリをインポートして実行するとうまくいきました。 参考 Twint_github 無限ループのエラーについて
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python3】Python3エンジニア認定データ分析試験受験記

昨日、一般社団法人Pythonエンジニア育成推進協会が提供しているPython3エンジニア認定データ分析試験を受験した。 結果は、1000点満点中900点(合格最低点:700点)で合格した。 0.筆者のスペック Python経験は1年半ほど 2020年7月 Python3エンジニア認定基礎試験合格 機械学習はほぼ初 1.勉強に使用した教材と費用 A.『Pythonによるあたらしいデータ分析の教科書』(以後公式教材と呼ぶ) B.模試(DIVE INTO CODE) C.難しい模試(プライムストラテジー) 費用 受験費:11000円(学割が効くと5500円) 公式教材:Amazonで2728円※ ※以下サイトの通りに受験宣言をするとキャンペーンで無料でテキストをもらえるそうです。(2021年11月まで) https://www.pythonic-exam.com/archives/news/555camp 2.勉強した期間 試験受験すると決めた1か月前から公式教材を電車の中で読み、わからない単語や用法を調べOneNoteに記した。 試験2週間前に教材を読み終えたので、プライムストラテジーよりも簡単と言われていたDIVE INTO CODEから提供されている模試を解き始めた。 最初は47.5%とかなり低かったが、わからない単語や用法を調べ公式教材のコードを実行しつつ、複数回受験していくうちに合格点を安定して取れるようになった。 試験一週間前からは、プライムストラテジーの方の模試を受験した。 DIVE INTO CODEの模試で合格点を取れていたので、合格点行くだろうと甘く考えていたが、結果は52.5点/100点となった。 この模試でもDIVE INTO CODEの時と同様に、複数回受験していくうちに、合格点を安定して取れるようになった。 3.受けてみて 機械学習の分野が苦手だったため、機械学習の分野(特に、教師あり学習と教師なし学習の違い等)を理解するのに苦労した。 4.感想 公式教材がすごくわかりにくかった。 難易度は模試レベルだった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RaspberryPiでSPI駆動の1.8" TFT液晶(ST7735s)を使って、画像を表示する。

RaspberryPiで1.8" TFT液晶を使う この記事では、1.8" TFT液晶をRaspberryPi上のPython3で駆動します。 Arduinoでの駆動例は多数あり、ライブラリも豊富ですが、Python3での駆動例は少なかったため記載します。 使用する液晶によって、表示上の赤と青が入れ替わる(RGB→BGR)となる場合があります。 私の使用した液晶ではこの症状が発生したため、画像の赤と青を反転させることで対応しています。 解決策をご存じの方がいましたら、コメントしていただけると助かります。 この記事のスクリプトは、以下のページを参考にしました。 配線 スクリプト ライブラリについて 他のサイト等で紹介されている、ST7735s・ST7735のライブラリを用いた駆動方法は、私の環境では上手く行きませんでした。 なお、環境や使用する液晶によってはこちらでも動作する可能性はあると思います。 使用パッケージのインストールと設定 使用パッケージ pip3 adafruit-circuitpython-rgb-display Pillow インストール python3-pilはおそらくインストール済みになると思われます。 sudo apt install python3-pip sudo pip3 install adafruit-circuitpython-rgb-display sudo apt install python3-pil インストールの確認 python3 import PIL import adafruit_rgb_display 以上のパッケージがインポートできれば、インストールが正常に完了しています。 exit()でpython3を終了してください。 SPI通信の有効化 sudo raspi-config これに関しては、たくさん情報がありますのでわからない場合は検索してみてください。 配線 使用する液晶によって、ピンの名前が異なる場合があります。 液晶側 RaspberryPi側 GND GND VCC 3.3v SCL GPIO11 SDA GPIO10 RST GPIO24 DC GPIO25 CS GPIO8 BLK GPIO12 コード この記事では、1.8" TFT液晶(ST7735s)の場合のスクリプトを掲載します。 スクリプト自体は、前述した参考サイトのコードを簡略化したものになります。他の液晶を使用する場合は、参考サイトを参照して対象コードを書き換えてください。 このコードでは、画面サイズと同じサイズの画像(160x128の液晶であれば、160x128の画像)の使用を想定しています。 それ以外の画像を使用する場合は、事前にクロップするか、参考サイトを参照して自動でクロップするスクリプトを追加してください。 tft_display_cont.py # -*- coding: utf-8 -*- """ This program is based on the sample program at Adafruit-Python-Usage. (https://learn.adafruit.com/1-8-tft-display/python-usage) 2021/09/06 var1.0 """ import digitalio import board import RPi.GPIO as GPIO from PIL import Image, ImageDraw from time import sleep import adafruit_rgb_display.st7735 as st7735 cs_pin = digitalio.DigitalInOut(board.CE0) dc_pin = digitalio.DigitalInOut(board.D25) reset_pin = digitalio.DigitalInOut(board.D24) BAUDRATE = 24000000 # 使用する液晶が異なる場合、サイトを参考に以下を書き換えてください。 # ----------ここから---------- disp = st7735.ST7735R( board.SPI(), rotation=270, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, ) # ----------ここまで---------- backlight_pin = 12 GPIO.setmode(GPIO.BCM) GPIO.setup(backlight_pin, GPIO.OUT) class DisplayImage(): def __init__(self, img): self.image = Image.open(img) def show(self): # 画像サイズと液晶サイズが異なると、上手く表示されない可能性があります disp.image(self.image) class DisplayControl(): def __init__(self): self.backlight = GPIO.PWM(backlight_pin, 100) self.backlight.start(0) def on(self): self.backlight.ChangeDutyCycle(100) def off(self): black = Image.new("RGB", (160, 128)) draw = ImageDraw.Draw(black) draw.rectangle((0, 0, 160, 128), outline=0, fill=(0, 0, 0)) disp.image(black) self.backlight.ChangeDutyCycle(0) def pwm(self, value): self.backlight.ChangeDutyCycle(value) if __name__ == "__main__": Image01 = DisplayImage("picture01.jpg") Image02 = DisplayImage("picture02.jpg") DisplayCont = DisplayControl() try: while True: Image01.show() #一枚目を表示 DisplayCont.on() sleep(1) Image02.show() #二枚目を表示 DisplayCont.pwm(50) sleep(1) DisplayCont.off() #表示を消す sleep(1) except KeyboardInterrupt: pass 動作と解説 上記スクリプトをtft_display_cont.pyとして、同じディレクトリに、picture01.jpgとpicture02.jpgを保存します。 以下の画像は、それぞれ160x128の画像ですので、動作確認用にダウンロードしてお使いください。 以下のコマンドを実行し、液晶に表示されることを確認してください。 python3 tft_display_cont.py ライブラリとして使用 使用例 以下のように、ライブラリとしてインポートして使用できます。 Import_test.py import tft_display_cont as tft from time import sleep Image01 = tft.DisplayImage("picture01.jpg") # 任意の画像ファイル Image02 = tft.DisplayImage("picture02.jpg") # 任意の画像ファイル DisplayCont = tft.DisplayControl() DisplayCont.on() # バックライト点灯 while True: Image01.show() # 一枚目を表示 sleep(1) Image02.show() # 二枚目を表示 sleep(1) 解説 以下でインスタンスを生成します。 Import_test.py Image01 = tft.DisplayImage("picture01.jpg") # 任意の画像ファイル Image02 = tft.DisplayImage("picture02.jpg") # 任意の画像ファイル DisplayCont = tft.DisplayControl() Import_test.py Image01.show() # 画像を表示します。 Image02.show() # 画像を表示します。 DisplayCont.on() # バックライトを点灯します。 DisplayCont.off() # バックライトを消灯します。 DisplayCont.pwm(50) # バックライトをPWM制御します。 0~100で指定します。 文字の表示について 参考サイトでは、文字を表示するスクリプト例も紹介されています。 興味があれば閲覧してみてください。 最後に 使用する液晶によって、表示上の赤と青が入れ替わる(RGB→BGR)となる場合があります。 私の使用した液晶ではこの症状が発生したため、画像の赤と青を反転させることで対応しています。 解決策をご存じの方がいましたら、コメントしていただけると助かります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む