ソースに絡まるエスカルゴ

貧弱プログラマの外部記憶装置です。

【Raspberry Pi】キーボードショートカットを設定する

 Raspberry Piを色々いじっていて、主にスクショなどをやるのに一々コマンドを叩くのが面倒だったのでキーボードショートカットを設定したくなってきました。

 調べると、設定ファイルに記述すれば任意のキーボードショートカットを追加できることがわかったのでその備忘録です。

 参考資料に上げたページ様の内容そのままですが、一応記事にした次第です。詳しい内容は参考資料を見ていただければと思います。

 では始めます。


・キーボードショートカットの設定方法
 ラズパイの場合、キーボードショートカットを設定するには「/etc/xdg/openbox/lxde-pi-rc.xml」というファイルを修正します。

 LXTerminalを立ち上げ、以下のようにsudoつきで設定ファイルをエディタで開きます。

$ sudo mousepad /etc/xdg/openbox/lxde-pi-rc.xml

 ファイルを開くと警告文が表示されますが、気にせずに252行目辺りにある「Keybindings for running applications」とコメントされているところに移動します。
f:id:rikoubou:20200727142827p:plain

 この部分にキーボードショートカットを設定していきます。

 デフォルトで以下の記述がすでに設定されているかと思います。

    <keybind key="Print">
      <action name="Execute">
        <command>scrot</command>
      </action>
    </keybind>

 これを少し解説すると、「keybind key」がキーの設定でここでは「Print」キーを押した時のショートカットになります。「action name="Execute"」は「command」タブに書かれたコマンドを起動させるという意味です。「command」タブには「scrot」とだけ書かれているので、このショートカットは「Printキーを押すと、scrotコマンドを起動させる」ように設定してあることになります。

 書き方がわかったので、フォーカスのあるものだけスクショするショートカット(scrot -u)とマウスで指定した四角の範囲だけスクショするショートカット(scrot -s)を設定していきます。

 ちなみに自分は以下のように「Alt + Print」キーでフォーカスのスクショ、「Ctrl + Shift + Print」キーでマウスで指定した四角の範囲だけスクショに設定しました。

    <!-- Keybindings for running applications -->
    <keybind key="Print">
      <action name="Execute">
        <command>scrot</command>
        <!-- Print key all screen shot-->
      </action>
    </keybind>
    <keybind key="A-Print">
      <action name="Execute">
        <command>scrot -u</command>
        <!-- Alt+Print key forcus screen shot-->
      </action>
    </keybind>
    <keybind key="C-S-Print">
      <action name="Execute">
        <command>scrot -s</command>
        <!-- Ctrl+Shift+Print key square screen shot-->
      </action>
    </keybind>

 記述できたら上書き保存し、ラズパイを再起動させます。再起動すると変更が反映されています。


 以上がRaspberry Piにキーボードショートカットを設定する方法です。

 今回はスクショだけでしたが、任意に色々と設定できるようなのでWindowsMacなどと合わせたいといったときには便利だと思います。


・参考資料

【Windows10/PHP/Apatch】Windows10にPHPとApacheを入れる

 今までPHPとかを触ってこなかったのですが、なんとなく「触ってみるか」という気持ちになったのでWindows10 Homeに環境構築してみた次第です。

 色々と間違ってたり足りない部分もあるような気がしますが、Apacheを起動させてPHPファイルの内容も表示できるところまではいったのでその備忘録です。

 もっとこうした方がいいなどあればコメントをお願いします。

 では、始めます。


1:Visual Studioのインストール
 後々にC++コンパイラが必要になるので、先にVisual Studio経由でC++コンパイラを入れます。

 以下のページを開きます。

 個人利用なのでCommunityを選択してダウンロードします。
f:id:rikoubou:20200717151816p:plain

 ダウンロードしたインストーラを起動させて指示通りに進めていきます。進めていくと途中で以下のような画面になりますが、コンパイラさえ入ればいいので「C++によるデスクトップ開発」にのみチェックを入れてインストールします。
f:id:rikoubou:20200717151855p:plain
 
 これでVisual Studio 2019のコンパイラが入ります。


2:phpのインストール
 以下のphpのダウンロードページを開きます。

 32bit用(x86)や64bit(x64)、その他にもバージョンや「Non Thread Safe」、「Thread Safe」という種類が多くあります。ちなみに「Non Thread Safe」と「Thread Safe」の違いはどうやら以下のような意味だそうです。

  • Non Thread Safe:マルチスレッド非対応(Apache1系のみ)
  • Thread Safe  :マルチスレッド対応(Apache2系も対応)

 なので基本的にはThread Safeを選択することになると思います。

 今回自分の環境はWindows10の64bitでバージョンは最新のものを入れたいので、以下の赤枠で囲っている「VC15 x64 Thread Safe」のzipファイルをダウンロードします。
f:id:rikoubou:20200717153005p:plain

 ダウンロードしたzipファイルをzipファイルのそのままの名前のフォルダである「php-7.4.8-Win32-vc15-x64」に解凍します。解凍したらフォルダ「php-7.4.8-Win32-vc15-x64」をCドライブ直下に移動させます。
f:id:rikoubou:20200717153558p:plain

 移動させたら「php-7.4.8-Win32-vc15-x64」フォルダ内にある「php.ini-development」ファイルをコピーして「php.ini」に変更します。
f:id:rikoubou:20200717154603p:plain

 作成した「php.ini」ファイルをテキストエディタで開き、以下の部分を変更します。

・755行目あたり変更前

; Directory in which the loadable extensions (modules) reside.
; http://php.net/extension-dir
;extension_dir = "./"
; On windows:
;extension_dir = "ext"


・755行目あたり変更後

; Directory in which the loadable extensions (modules) reside.
; http://php.net/extension-dir
extension_dir = "C:\php-7.4.8-Win32-vc15-x64\ext"
; On windows:
extension_dir = "C:\php-7.4.8-Win32-vc15-x64\ext"


・838行目あたり変更前

; Temporary directory for HTTP uploaded files (will use system default if not
; specified).
; http://php.net/upload-tmp-dir
;upload_tmp_dir =


・838行目あたり変更後

; Temporary directory for HTTP uploaded files (will use system default if not
; specified).
; http://php.net/upload-tmp-dir
upload_tmp_dir = "C:\php-7.4.8-Win32-vc15-x64\tmp"


・955行目あたり変更前

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
;date.timezone =


・955行目あたり変更後

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = Asia/Tokyo


・1317行目あたり変更前

; The path can be defined as:
;
;     session.save_path = "N;/path"


・1317行目あたり変更後

; The path can be defined as:
;
session.save_path = "C:\php-7.4.8-Win32-vc15-x64\tmp"

 これらの部分を変更して保存します。

 php.iniの変更が終わったら、phpを使えるように環境変数を設定します。

 エクスプローラーの左側にある「PC」を右クリックして「プロパティ」を選択します。
f:id:rikoubou:20200717160832p:plain

 以下のような画面になるので「システム詳細設計」をクリックします。
f:id:rikoubou:20200717161003p:plain

環境変数」ボタンをクリックします。
f:id:rikoubou:20200717161058p:plain

 システム環境変数の「Path」を選択した状態で「編集」ボタンをクリックします。
f:id:rikoubou:20200717161304p:plain

「新規」ボタンをクリックして「C:\php-7.4.8-Win32-vc15-x64」と入力して追加します。追加したら「OK」ボタンをクリックします。
f:id:rikoubou:20200717161509p:plain

 これでphpは使えるようになっているはずなので、コマンドプロンプトPowerShellを起動させて「php -v」とコマンドを入力します。

$ php -v
PHP 7.4.8 (cli) (built: Jul  9 2020 11:30:39) ( ZTS Visual C++ 2017 x64 )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies

 
 エラーが発生せず、PHPのバージョンが表示されていればPHPが使えるようになっています。


3:Apacheのインストール
 続いてApacheを入れていきます。

 以下のダウンロードページを開きます。

 今回自分の環境はWindows10の64bitなので、64bitの方をダウンロードします。
f:id:rikoubou:20200717165017p:plain

 ダウンロードしたzipファイルを解凍した中に「Apache24」というフォルダがあるので、そのフォルダをphpの時と同じようにCドライブ直下に移動させます。
f:id:rikoubou:20200717165537p:plain

 移動させたら「Apache24」フォルダの中にある「conf」フォルダを開きます。「httpd.conf」ファイルをコピーして「httpd_bk.conf」としてバックアップとして元ファイルを残しておき、「httpd.conf」ファイルの方を変更していきます。
f:id:rikoubou:20200717165859p:plain

httpd.conf」ファイルをテキストエディタで開いて以下の変更を行います。

・185行目あたり変更前

#LoadModule watchdog_module modules/mod_watchdog.so
#LoadModule xml2enc_module modules/mod_xml2enc.so


・185行目あたり変更後(一番下の行を追加)

#LoadModule watchdog_module modules/mod_watchdog.so
#LoadModule xml2enc_module modules/mod_xml2enc.so
LoadModule php7_module "C:\php-7.4.8-Win32-vc15-x64\php7apache2_4.dll"


226行目あたり変更前

# If your host doesn't have a registered DNS name, enter its IP address here.
#
# ServerName www.example.com:80


226行目あたり変更後(コメントアウトを外す)

# If your host doesn't have a registered DNS name, enter its IP address here.
#
ServerName www.example.com:80


・235行目あたり変更前

<Directory />
    AllowOverride none
    Require all denied
</Directory>


・235行目あたり変更後

<Directory />
    AllowOverride All
    Require all granted
</Directory>


・266行目あたり変更前

    Options Indexes FollowSymLinks


・266行目あたり変更後

    Options Indexes FollowSymLinks ExecCGI
    Options +Includes


・408行目あたり変更前

    #
    TypesConfig conf/mime.types


・408行目あたり変更後(下4行を追加)

    #
    TypesConfig conf/mime.types

    AddType application/x-httpd-php .php
    AddType application/x-httpd-php-source .phps
    AddType application/x-httpd-cgi .cgi
    AddType application/x-httpd-cgi .pl


・439行目あたり変更前

    # To use CGI scripts outside of ScriptAliased directories:
    # (You will also need to add "ExecCGI" to the "Options" directive.)
    #
    #AddHandler cgi-script .cgi

    # For type maps (negotiated resources):
    #AddHandler type-map var

    #
    # Filters allow you to process content before it is sent to the client.
    #
    # To parse .shtml files for server-side includes (SSI):
    # (You will also need to add "Includes" to the "Options" directive.)
    #
    #AddType text/html .shtml
    #AddOutputFilter INCLUDES .shtml


・439行目あたり変更後

    # To use CGI scripts outside of ScriptAliased directories:
    # (You will also need to add "ExecCGI" to the "Options" directive.)
    #
    AddHandler cgi-script .cgi .pl
    AddHandler php7-script .php

    # For type maps (negotiated resources):
    #AddHandler type-map var

    #
    # Filters allow you to process content before it is sent to the client.
    #
    # To parse .shtml files for server-side includes (SSI):
    # (You will also need to add "Includes" to the "Options" directive.)
    #
    AddType text/html .shtml
    AddOutputFilter INCLUDES .shtml


・最後の行に追加

PHPIniDir "C:\php-7.4.8-Win32-vc15-x64"


 ここまでの変更ができたら上書き保存します。

 Apacheの起動は「Apache24」フォルダの中にある「bin」フォルダを開きます。その中にある「httpd.exe」をダブルクリックすることで起動できます。
f:id:rikoubou:20200717171623p:plain

 ダブルクリックすると以下のような黒い画面が立ち上がります。
f:id:rikoubou:20200717171703p:plain

 この状態でブラウザを開いて「http://localhost/」のアドレスにアクセスすると「It works!」という文字だけ書かれたページが表示されます。
f:id:rikoubou:20200717171847p:plain

 Apacheを起動させている黒い画面をウインドウ右上の「×」ボタンで閉じてから、更新したり改めて「http://localhost/」のアドレスにアクセスすると以下のようにページは表示されません。
f:id:rikoubou:20200717172040p:plain

 これで「httpd.exe」でApacheを起動してないとページが表示されていないことがわかったので、Apacheがちゃんと動いていることが確認できました。


4:PHPファイルの実行
 PHPApacheの準備ができたので、今度はブラウザからPHPのファイルが実行できているかを確認します。

「Apache24」フォルダ中にある「htdocs」フォルダを開いて「test.php」の空のテキストファイルを作成します。
f:id:rikoubou:20200717172543p:plain

 test.phpファイルをテキストエディタで開き、以下のように記述して上書き保存します。

・test.pnp

<?php
phpinfo()
?>

 保存できたら「httpd.exe」でApacheを起動させ、「http://localhost/test.php」のアドレスにアクセスすると、以下のようにPHPの情報が色々と載っているページが表示されます。
f:id:rikoubou:20200717172936p:plain

 これでPHPで記述した部分も動いていることが確認できました。


 以上がWindows10にPHPApacheを入れる方法です。

 ApachePHPも初心者なので足りない部分や間違っている部分もあるかと思いますが、自分のところではこの方法で環境構築できたのでとりあえずは目的達成です。

 ただ2020年という時代に環境構築にここまで手間が必要というのはどうなんだ? という個人的な疑問は浮かびました……。

 とはいえ環境はできたので、PHPの勉強も暇なときはやっていきたいかなと思っています。


・参考資料

【Raspberry Pi/python】Raspberry Pi 4にTensorFlow環境を作ってサンプルを動かしてみる

 色々と耳にしてはいましたが、今まで一切触れてこなかったTensorFlowなるものをRaspberry Pi 4に入れてみようと思って入れてみました。

 一応サンプルが動くまではいったのですが、よくわからないエラーやWARNINGなどが出るのと処理が結構遅かったりするのでどこかおかしいのかもしれないという状態ですが、自分がやった一通りの手順をメモしておきたかったので記事にした次第です。

 間違ってるところなどありましたら、コメントで指摘していただけると幸いです。

 では、始めます。


0:前提
 Raspberry Pi 4でOpenCVが動く環境まで持っていっている状態から始めています。

 OpenCVをまだ入れてない状態であれば、以下の記事を参考にしてOpenCVが入っている状態まで進めてください。


1:TensorFlowのインストール
 まずはTensorFlowをインストールするために、以下のコマンドを実行します。

$ sudo apt-get update
$ sudo apt-get upgrade
$ pip3 install tensorflow

 最後のpip3 install tensorflowの途中で以下のような赤文字が出て正常にインストールできずに終わる場合があります。

tensorboard 2.0.2 has requirement setuptools>=41.0.0, but you'll have setuptools 40.8.0 which is incompatible.

 その場合は以下のコマンドで一度tensorflowをアンインストールしてから、--upgradeオプションを付けてもう一度インストールを実行します。

$ pip3 uninstall tensorflow
$ pip3 install --upgrade tensorflow

 TensorFlowがインストールできているかはpythonを起動させて確認します。

$ python3
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
2020-07-15 17:10:19.083737: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory
>>> tf.__version__

 
 最後の行でのバージョンが表示されていればOKです。
 ちなみに「E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory」というエラーが出ていますが、これが出ていてもどうやら問題ないようなので無視しても大丈夫なようです(※詳しく調べ切れてはいませんが、とりあえずサンプルを動かすのは問題なかったです)


2:Kerasのインストール
 次にKerasというのをインストールします。

 インストールコマンドは以下の通りです。

$ pip3 install keras

 Kerasがインストールできているかはpythonを起動させて確認します。

$ python3
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import keras
Using TensorFlow backend.
2020-07-15 17:18:16.884242: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory
>>> keras.__version__

 TensorFlowの時と同じように、出ているエラーは気にせずに最後の行でのバージョンが表示されていればOKです。

 import kerasの実行した際に以下のようなエラーが出ることがあります。

ImportError: Keras requires TensorFlow 2.2 or higher. Install TensorFlow via `pip install tensorflow`

 これはTensorFlowとKerasのバージョンが合っていないというエラーになります。
 解決方法としてはKerasのダウングレードしかないようだったので、以下のコマンドを実行して本記事執筆時点でTensorFlowに合ったKerasのバージョンをインストールします。

$ pip3 uninstall keras
$ pip3 install keras==2.3.1

 インストールが終わったら再度pythonでインポートしてエラーがなければOKです。


3:サンプルの実行
 これでようやくサンプルを動かす環境ができたのでサンプルを実行していきます。

 適当なディレクトリを作成してそこに移動し、以下のgitコマンドを実行してサンプルをcloneしてきます。

$ git clone https://github.com/fchollet/deep-learning-models.git

 cloneが終わると「deep-learning-models」というディレクトリができているので移動します。

$ cd deep-learning-models

 解析するためのサンプル画像ですが、以下のものを使用するので「deep-learning-models」ディレクトリの中に「bench.png」として保存してください。
・bench.png
f:id:rikoubou:20200715174556p:plain

 この画像を解析するために「deep-learning-models」ディレクトリの中にある「inception_v3.py」を編集していきます。

 inception_v3.pyをエディタで開いて以下のように書き換えます。

・35行目「.を_に変更」
 修正前:from keras.applications.imagenet_utils import _obtain_input_shape
 修正後:from keras_applications.imagenet_utils import _obtain_input_shape

・157行目「include_topをrequire_flattenに変更」
 修正前:include_top=include_top
 修正後:require_flatten=include_top

・401行目「解析するファイル名を変更」
 修正前:img_path = 'elephant.jpg'
 修正後:img_path = 'bench.png'

 編集が済んだら上書き保存し、inception_v3.pyを実行してみます。

$ python3 inception_v3.py
Using TensorFlow backend.
2020-07-15 17:47:15.269213: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory
WARNING:tensorflow:From /home/pi/.local/lib/python3.7/site-packages/tensorflow_core/python/ops/resource_variable_ops.py:1630: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
WARNING:tensorflow:From /home/pi/.local/lib/python3.7/site-packages/keras/backend/tensorflow_backend.py:4070: The name tf.nn.max_pool is deprecated. Please use tf.nn.max_pool2d instead.

WARNING:tensorflow:From /home/pi/.local/lib/python3.7/site-packages/keras/backend/tensorflow_backend.py:4074: The name tf.nn.avg_pool is deprecated. Please use tf.nn.avg_pool2d instead.

WARNING:tensorflow:From /home/pi/.local/lib/python3.7/site-packages/keras/backend/tensorflow_backend.py:422: The name tf.global_variables is deprecated. Please use tf.compat.v1.global_variables instead.

Predicted: [[('n03891251', 'park_bench', 0.9735911), ('n04208210', 'shovel', 0.0012295641), ('n02747177', 'ashcan', 0.0010040886), ('n03388043', 'fountain', 0.00087099895), ('n02892201', 'brass', 0.00074983406)]]

 色々とエラーやWARNINGが出ていますが、最後の結果としては「'park_bench', 0.9735911」と公園のベンチが97%ほどという結果となり、ちゃんと画像の解析ができています。

 以上がRaspberry Pi 4にTensorFlow環境を作ってサンプルを動かしてみるまでの方法です。

 実行してみると結果が出るまでかなり時間がかかるので、リアルタイムで判別というのは難しそうです。また動いているとはいえ、エラーやWARNINGが出まくっているのでその辺りも気持ちが悪いです。
 なので環境の問題点がわかる方はコメントいただければと思います。

 TensorFlowにはLiteという軽いものもあるようなので、そっちも機会があれば試してみたいです。


・参考資料

【python】pygameでスプライトアニメーションと画像の変形、回転

 以前にpygameでタッチパネルを使う簡単なサンプルの記事を書きました。

 今回はもうちょっとpygameをちゃんと使ってみようと思い、タイトルにあるようにスプライトアニメーションと画像の変形、回転についての記事です。
 本記事で作った画像素材やサンプルコードをまとめて公開しておくので、気になったり素材が欲しい方は以下のリンクからダウンロードしてください。

 では、始めます。


1:スプライトアニメーション
 スプライトアニメーションとは画像を一枚ずつ読み込み、それを切り替えていくことでアニメーションさせる方法です。
 複数枚画像を用意する必要はありますが、パラパラ漫画のような要領で作っていくことができるので直感的でわかりやすいと思います。

 やり方としては、以下のようにスプライトクラスを作成して実現します。

import pygame

# スプライトアニメーションさせるクラス
class MySprite(pygame.sprite.Sprite):
    # コンストラクタ
    def __init__(self):
        super(MySprite, self).__init__()

        # 画像をリストで読み込み
        self.images = list()
        self.images.append(pygame.image.load('hoge0001.png'))
        self.images.append(pygame.image.load('hoge0002.png'))
        self.images.append(pygame.image.load('hoge0003.png'))
        # 以下略…で画像を全て読み込む

        # 画像はindexで管理すると楽
        self.index = 0
        self.image = self.images[self.index]
        self.rect = self.image.get_rect() # 描写範囲(必須)

    # 1フレーム事に実行される関数
    def update(self):
        # ループ処理
        if self.index >= len(self.images):
            self.index = 0

        self.image = self.images[self.index]
        self.index += 1

 基本的にはコンストラクタで画像を読み込み、update関数で画像を切り替えていくという感じです。

 例としてimageフォルダを作成してその中に「fish_0000.png」~「fish_0015.png」までの連番画像を入れたものを24fpsでアニメーションさせてみたサンプルが以下になります。

・sprite_test.py

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

WINDOW_SIZE = WIDTH, HEIGHT = 600, 400 # ウインドウサイズ
BACKGROUND_COLOR = (0,0,0) # 背景色(黒)
FPS = 24 # フレームレート

# スプライトアニメーションさせるクラス
class FishSprite(pygame.sprite.Sprite):
    # コンストラクタ
    def __init__(self):
        super(FishSprite, self).__init__()

        # 画像をリストで読み込み
        self.images = list()
        for i in range(0, 15):
            number_str = str(i)
            if len(number_str) == 1:
                number_str = '0' + number_str
            self.images.append(pygame.image.load('./image/fish_00' + number_str + '.png'))

        self.index = 0
        self.image = self.images[self.index]
        self.rect = self.image.get_rect() # 描写範囲(必須)

    # 1フレーム事に実行される関数
    def update(self):
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]
        self.index += 1

def main():
    pygame.init()
    screen = pygame.display.set_mode(WINDOW_SIZE) # ウインドウサイズの設定

    # スプライトのオブジェクトを作ってグループ化
    fish = FishSprite()
    my_group = pygame.sprite.Group(fish)

    screen.fill(BACKGROUND_COLOR) # 背景色を設定
    clock = pygame.time.Clock()   # クロックを開始

    while True:
        for event in pygame.event.get():
            # ESCキーが押されたら終了
            if (event.type == pygame.KEYDOWN) and (event.key == pygame.K_ESCAPE):
                pygame.quit()
                quit()

        # 背景色で塗りつぶし
        screen.fill(BACKGROUND_COLOR)

        # 画像を更新して描写
        my_group.update()
        my_group.draw(screen)

        # 表示全体を更新
        pygame.display.update()
        clock.tick(FPS) # フレームレート分待機

if __name__ == '__main__':
    main()

 実行すると以下のように魚っぽいシルエットがお尻を振り振りしているアニメーションが表示されます。「ESCキー」を押すと終了します。
f:id:rikoubou:20200710164347g:plain


2:画像の変形、回転
 スプライトアニメーションができたので、今度はこの画像を拡大縮小して変形させたり、回転させたりしてみます。

 先ほどのスプライトアニメーションのクラスに、以下のようにchange_image_scale関数とrotate_center_image関数を追加すればいけます。

# スプライトアニメーションさせるクラス
class FishSprite(pygame.sprite.Sprite):
    # コンストラクタ
    def __init__(self, width_rate, height_rate, position):
        super(FishSprite, self).__init__()

        # 画像をリストで読み込み
        self.images = list()
        # self.images.append(pygame.image.load('./image/test.png')) # テスト用の画像
        for i in range(0, 15):
            number_str = str(i)
            if len(number_str) == 1:
                number_str = '0' + number_str
            self.images.append(pygame.image.load('./image/fish_00' + number_str + '.png'))

        self.index = 0
        self.image = self.images[self.index]
        self.rect = self.image.get_rect() # 描写範囲(必須)

        self.width_rate = width_rate
        self.height_rate = height_rate
        self.image_center_position = position

        self.image_angle = 0

    # 1フレーム事に実行される関数
    def update(self):
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]
        self.index += 1

        self.change_image_scale()  # 画像サイズを変更
        self.rotate_center_image() # 画像を回転

    # 画像のサイズを変更する関数
    def change_image_scale(self):
        x_size = self.image.get_width()  * self.width_rate
        y_size = self.image.get_height() * self.height_rate
        self.image = pygame.transform.scale(self.image, (int(x_size), int(y_size)))

    # 画像の中心で回転させる関数
    def rotate_center_image(self):
        # 画像の傾きを設定
        self.image_angle -= 10
        if self.image_angle <= -360:
            self.image_angle = 0

        # 画像を回転
        rot_image = pygame.transform.rotate(self.image, self.image_angle)
        rot_rect = rot_image.get_rect()
        rot_rect.center = self.image_center_position # 中心位置を設定(移動)

        # 結果を格納
        self.image = rot_image
        self.rect = rot_rect

 コンストラクタの引数が色々と増えていますが、画像の縦横の比率と画像を表示させる位置を設定できるようにしてあります。

 実際のサンプルコードは以下になります。

・transform_rotate_test.py

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

WINDOW_SIZE = WIDTH, HEIGHT = 600, 400 # ウインドウサイズ
BACKGROUND_COLOR = (0,0,0) # 背景色(黒)
FPS = 24 # フレームレート

# スプライトアニメーションさせるクラス
class FishSprite(pygame.sprite.Sprite):
    # コンストラクタ
    def __init__(self, width_rate, height_rate, position):
        super(FishSprite, self).__init__()

        # 画像をリストで読み込み
        self.images = list()
        # self.images.append(pygame.image.load('./image/test.png')) # テスト用の画像
        for i in range(0, 15):
            number_str = str(i)
            if len(number_str) == 1:
                number_str = '0' + number_str
            self.images.append(pygame.image.load('./image/fish_00' + number_str + '.png'))

        self.index = 0
        self.image = self.images[self.index]
        self.rect = self.image.get_rect() # 描写範囲(必須)

        self.width_rate = width_rate
        self.height_rate = height_rate
        self.image_center_position = position

        self.image_angle = 0

    # 1フレーム事に実行される関数
    def update(self):
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]
        self.index += 1

        self.change_image_scale()  # 画像サイズを変更
        self.rotate_center_image() # 画像を回転

    # 画像のサイズを変更する関数
    def change_image_scale(self):
        x_size = self.image.get_width()  * self.width_rate
        y_size = self.image.get_height() * self.height_rate
        self.image = pygame.transform.scale(self.image, (int(x_size), int(y_size)))

    # 画像の中心で回転させる関数
    def rotate_center_image(self):
        # 画像の傾きを設定
        self.image_angle -= 10
        if self.image_angle <= -360:
            self.image_angle = 0

        # 画像を回転
        rot_image = pygame.transform.rotate(self.image, self.image_angle)
        rot_rect = rot_image.get_rect()
        rot_rect.center = self.image_center_position # 中心位置を設定(移動)

        # 結果を格納
        self.image = rot_image
        self.rect = rot_rect

def main():
    pygame.init()
    screen = pygame.display.set_mode(WINDOW_SIZE) # ウインドウサイズの設定

    # スプライトのオブジェクトを作ってグループ化
    fish1 = FishSprite(0.5, 0.1, (100, 100))
    fish2 = FishSprite(0.1, 0.6, (300, 150))
    fish3 = FishSprite(0.3, 0.3, (500, 250))

    my_group = pygame.sprite.Group(fish1)
    my_group.add(fish2)
    my_group.add(fish3)

    screen.fill(BACKGROUND_COLOR) # 背景色を設定
    clock = pygame.time.Clock()   # クロックを開始

    while True:
        for event in pygame.event.get():
            # ESCキーが押されたら終了
            if (event.type == pygame.KEYDOWN) and (event.key == pygame.K_ESCAPE):
                pygame.quit()
                quit()

        # 背景色で塗りつぶし
        screen.fill(BACKGROUND_COLOR)

        # 画像を更新して描写
        my_group.update()
        my_group.draw(screen)

        # 表示全体を更新
        pygame.display.update()
        clock.tick(FPS) # フレームレート分待機

if __name__ == '__main__':
    main()

 実行すると以下のように縦横比や大きさ、表示位置が違うものが3つ表示されて回転します。
f:id:rikoubou:20200710164615g:plain

 画像の中心で回転しているのがわかりにくいですが、実際にちゃんと画像の中心を軸として回転しています。


 以上がpygameでスプライトアニメーションと画像の変形、回転する方法です。

 スプライトアニメーションをさせているキャラクターをキー入力で動かす、ということもこの方法を応用すればできるようになると思います。

 個人的にゲームを作るという目的はないのですが、ちょっとした面白いことには色々応用できると思うのでこれからもいじっていきたいです。


・参考資料

【ffmpeg】ffmpegでの便利な変換コマンド

 ffmpegについては環境構築方法やちょっとした変換コマンドの記事を過去に書きました。

 変換だけではなくその他にもいろいろと便利な機能があることがわかったので、個人的に情報をまとめようと思った次第です。

 コマンドの一行目が書き方で二行目が例という感じで書いていきます。

 では始めます。


1:ファイルサイズを小さくする

$ ffmpeg -i [対象ファイル名(パス)] -pix_fmt yuv420p [保存ファイル名(パス)]
$ ffmpeg -i input.mov -pix_fmt yuv420p output.mp4

 実行すると場合によっては1/10ぐらいのサイズになります。


2:動画画面の反転・回転

・左右反転

$ ffmpeg -i [対象ファイル名(パス)] -vf hflip [保存ファイル名(パス)]
$ ffmpeg -i input.mp4 -vf hflip output.mp4


・上下反転

$ ffmpeg -i [対象ファイル名(パス)] -vf vflip [保存ファイル名(パス)]
$ ffmpeg -i input.mp4 -vf vflip output.mp4


・上下反転して反時計回りに90度回転

$ ffmpeg -i [対象ファイル名(パス)] -vf transpose=0 [保存ファイル名(パス)]
$ ffmpeg -i input.mp4 -vf transpose=0 output.mp4


・時計回りに90度回転

$ ffmpeg -i [対象ファイル名(パス)] -vf transpose=1 [保存ファイル名(パス)]
$ ffmpeg -i input.mp4 -vf transpose=1 output.mp4


・反時計回りに90度回転

$ ffmpeg -i [対象ファイル名(パス)] -vf transpose=2 [保存ファイル名(パス)]
$ ffmpeg -i input.mp4 -vf transpose=2 output.mp4


・上下反転して時計回りに90度回転

$ ffmpeg -i [対象ファイル名(パス)] -vf transpose=3 [保存ファイル名(パス)]
$ ffmpeg -i input.mp4 -vf transpose=3 output.mp4


3:動画の音声を消す

$ ffmpeg -i [対象ファイル名(パス)] -an [保存ファイル名(パス)]
$ ffmpeg -i input.mp4 -an output.mp4

 このコマンドはPC性能による差が出るのか、環境によっては出力したファイルが途中で再生できなくなっている(壊れている)場合があったので注意が必要かもしれません。


 以上が自分がよく使うコマンド一覧になります。各コマンドは組み合わせて使うこともできます。

 音声を消すコマンドについては一言書いてある通り、PC性能によるものなのか出力したファイルが壊れている場合がありました。
 ちなみに失敗した環境は以下の通り。

  • OS:Windows10 Home
  • CPU:AMD Ryzen 5 2500U
  • メモリ:8GB

 10世代i5のMacBook Pro 2020の環境だと問題なく出力できていたので、スペックによっては不具合が出る場合があるようです。

 この他にも参考資料にあるページ様に便利なコマンドがあるので気になる方は参照してみてください。


・参考資料

【MacOS】ffmpegのインストール方法

 最近になってMacを買い換えたのでインストールした環境がリセットされてしまいました(MacのTime Machineからの復元も初めてやりましたが、細かい設定などは引き継がれなかったっぽいので結局いろいろ設定しなおす必要がある…)。

 なので今回はMacでのffmpegのインストール記事を書いてなかったのを思い出したのもあり、備忘録として残しておきます。

 ちなみにWindowsでのインストール方法やffmpegに関する記事は以下になります。

 では始めます。


1:Homebrewのインストール
 最初にHomebrewを入れます。すでに入っている人はやる必要はありません。

 上記のリンクを開いて赤枠で囲ってあるコマンドをコピーします。
f:id:rikoubou:20200706120858p:plain

 Macのターミナルを開き、コマンドをペーストして実行します。
 パスワードを入力して「Press RETURN to continue or any other key to abort」という文が出てきたらRetuenキーを押下してしばらくまつとインストールが完了します。

 Homebrewがちゃんとインストールできているかは以下のコマンドを実行してエラーが出なければOKです。

$ brew help

 
2:ffmpegのインストール
 Homebrewが入ったらffmpegをインストールします。

 インストールコマンドは以下の通りです。

$ brew install ffmpeg

 コマンドを実行したあとは勝手に必要なものを全てインストールしてくれるのでしばらく待ちます。

 正常にインストールできたかは以下のコマンドを実行してエラーがなければOKです。

$ ffmpeg --help

 あとはWindowsの時と同じように動画の変換などを行うことができます。


 以上がMacOSでのffmpegのインストール方法になります。

 ちょっと動画編集などをやってみようかなと思ってるので、ffmpegも割と使うことになるかもしれないですね。


・参考資料

【Raspberry Pi/python】Raspberry PiのCPU温度などを取得する

 Raspberry Pi 4は発熱がものすごく、普通に使っていてもCPU回りを触ると温かくなります。

 ファンやヒートシンクはほぼ必須なのですが、具体的にどれぐらいの温度になるのかを知りたくて調べたところ簡単にCPUの温度などの情報を取得できることがわかりました。

 案外使う場合があるかと思ったので備忘録として記事にした次第です。

 では始めます。


1:Raspberry PiのCPU情報を取得するコマンド
 LXTerminalを開いて以下のコマンドを入力すれば、各情報を取得できます。

・CPU温度

$ vcgencmd measure_temp

・CPU周波数(クロック数)

$ vcgencmd measure_clock arm

・CPU電圧

$ vcgencmd measure_volts

・CPUのメモリ使用量

$ vcgencmd get_mem arm

GPUのメモリ使用量

$ vcgencmd get_mem gpu

 1回だけそれぞれの情報を取得するだけならコマンドを叩くだけでよいですが、定期的に取得したい場合はpythonなどで記述するのが楽です。


2:pythonからCPU情報を取得するコマンドを実行する
 pythonでshellを実行する場合にはsubprocessを使います。それを使ってコマンドの結果を変数に格納すればpython内で扱うことができるようになります。

 実際にsubprocessを使って1秒ごとにCPUの情報を取得するプログラムは以下の通りです。Ctrl+Cで終了させます。

・cpu_info.py

# -*- coding: utf-8 -*-
import subprocess
import time
from datetime import datetime

def main():
    while True:
        date = datetime.now().strftime("%Y/%m/%d %H:%M:%S")          # 現在時刻
        temp       = run_shell_command("vcgencmd measure_temp")      # CPU温度
        clock      = run_shell_command("vcgencmd measure_clock arm") # CPU周波数
        volts      = run_shell_command("vcgencmd measure_volts")     # CPU電圧
        memory_cpu = run_shell_command("vcgencmd get_mem arm")       # CPUのメモリ使用量
        memory_gpu = run_shell_command("vcgencmd get_mem gpu")       # GPUのメモリ使用量

        # 結果表示
        print("{}, temp:{}, clock:{}, volts:{}, cpu_m:{}, gpu_m:{}".format(date, temp, clock, volts, memory_cpu, memory_gpu))
        time.sleep(1) # 1秒待つ

# シェルコマンドを実行する関数
def run_shell_command(command_str):
    proc = subprocess.run(command_str, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
    result = proc.stdout.split("=")
    return result[1].replace('\n', '')

if __name__ == '__main__':
    main()

 Raspberry Piで上記を実行すると1秒ごとにそれぞれのCPU情報がコンソールの表示されます。
 シェルコマンドの実行結果をsplitしたりreplaceしているのは、イコールが入っていたり改行が入っていたりするのでそれを除去するために入れてあります。


 以上がRaspberry PiのCPU温度などを取得する方法になります。

 今回作ったpythonでのサンプルは結果をprintで表示させているだけですが、CSVなどに出力させるようにすればCPU温度の変化をグラフ化する際のデータ取得などにも使えるかと思います。


・参考資料