技術雑食系車好きの備忘録

今やってるもの:python・サーバ構築・blender

<Python>dictionary型の基本メモ・恒河沙より大きい数字を使えるのか?

JavaのMap型に近いものをイメージしてもらえればヨシ

メモ>記法

a = {
"a":100,
"b":50,
"c":300000000000000000000000000000000000000000000000000000000(3恒河沙
}

メモ>並び順操作

①書かれたままに出力した場合
a = { "a" : 100, "b" : 50, "c" : 300000000000000000000000000000000000000000000000000000000 }
for i in a:
print(i)

a
b
c
と出力(Key項目値の昇順を出力)

②sorted()関数を使ってみる
a = { "a" : 100, "b" : 50, "c" : 300000000000000000000000000000000000000000000000000000000 }
print(sorted(a))

a
b
c
と出力(Key項目値の昇順を出力)

③sorted()関数を使って並び替えてみる
a = { "a" : 100, "b" : 50, "c" : 300000000000000000000000000000000000000000000000000000000 }
print(sorted(a, key = a.get))

['b', 'a', 'c']
と出力(値の昇順でkey値を出力)

④sorted()関数を使って、値で並び替えてみる(降順)
a = { "a" : 100, "b" : 50, "c" : 300000000000000000000000000000000000000000000000000000000 }
print(sorted(a, key = a.get, reverse = True))

['c', 'a', 'b']
と出力(値の降順でkey値を出力)

実験>どこまでの桁数を使える?


a = { "a" : 100, "b" : 50, "c" : ***************************************** }
for i in a:
print(a.get(i))
この「**************」の部分に莫大な数字を入力して、どこまで耐えられるか(print()で出力できるか)を実験。
CPの性能に左右されるとも思いますが、まあ一般的なご家庭にある貧弱PCだと認識してもらえれば大丈夫です。
早速ですが、実験結果はこちら。
恒河沙は成功したので一~極の結果は省略しますが、大きい数トリビアとして記載だけ

単位   桁数     数値 結果 
一~兆  1~10の12乗 省略 省略
京    10の16乗 省略 省略
垓    10の20乗 省略 省略
じょ
(のぎへんに予)
10の24乗 省略 省略
穣    10の28乗 省略 省略
溝    10の32乗 省略 省略
澗    10の36乗 省略 省略
正    10の40乗 省略 省略
載    10の44乗 省略 省略
極    10の48乗 省略 省略
恒河沙  10の52乗 1000000000000000000000000000000000000000
0000000000000
成功
阿僧祇  10の56乗 1000000000000000000000000000000000000000
00000000000000000
成功
那由他  10の60乗 1000000000000000000000000000000000000000
000000000000000000000
成功
不可思議 10の64乗 1000000000000000000000000000000000000000
0000000000000000000000000
成功
無量大数 10の68乗 1000000000000000000000000000000000000000
00000000000000000000000000000
成功

大きい数にも平然と対処する、シビれる言語ですね

<Python>with構文の作動原理を理解する

はじめに

Javaで開発をしていた際、jarファイルなどのライブラリを眺めていると「元はどんなソースで書かれたものなんだろう」と気になり、逆コンパイルして追跡したくなる趣向があります。
Pythonでファイル操作に使用されるwith構文を学んだ際、その深淵が気になったので探ってみます。

結論だけ知りたい方は、最後のまとめ部分まで飛ばしてください。

※注意
個人的な解釈がふんだんに使われている内容なので、実際の言語仕様とは異なる可能性があります。
あくまで個人的な納得優先です、、、

with構文とは

Pythonにおけるwith構文とは、簡単に言えばファイルの読み書きにおいて前後処理を担ってくれる組み込み関数みたいなものです。
一般的に、ファイル読み書きにおいては「ファイルを開く」「ファイルを閉じる」処理はそれぞれ前後処理として明示的にプログラミングする事が安全と言われています。

※例

with open("sample.txt", "w") as fw:
    fw.write("test")

例えば上記のプログラムをwith構文を使用せずに書くと

fw = open("sample.txt", "w")
fw.write("test")
fw.close()

となります。

with構文無しだと前後処理を別々にプログラムする必要がありますが、with構文を使えばwithの1行が前後処理を担ってくれるのです。
ちゃんとした言い方をするなら、「特定の処理の前処理と後処理を設定することで、その処理をより簡潔かつ安全に利用できるようにするもの」ということ。

with構文の作動原理

では、with構文はどこにプログラムの本体が存在するのか探っていきます。
探っていく上での観点は2つ。
1.プログラム上の「with」が、with構文であることを判断するプログラムはどのように書かれているのか
2.前後処理はどのようなプログラムで書かれているのか

with構文とは何者か

まず、プログラム上にwithが出現した際に、「with構文が出たぞォォォ」をどう判断しているのか探ります。
そもそもwith構文は、公式曰く「コンテキストマネージャによって定義されたメソッド」です。
簡単に言えば、「コンテキストマネージャ」の一部品で、「withが出たぞォ(ry」はコンテキストマネージャで判断していると言えます。
>公式ドキュメント
docs.python.org

コンテキストマネージャとは何者か

じゃあ「コンテキストマネージャ」とは何かと言うと、インタプリタに組み込まれている関数の一種です。
docs.python.org

平たく言えば、「Pythonの実行環境に元々設定されている部品」という感じでしょうか。
そのため、「withが出(ry」の判断は、Pythonが使用するPCのメモリ上に展開されている = 人の目には見えない場所に定義されているものだと解釈します。(どこを探してもそれらしいファイルが無いので)

よって、with構文であることを判断する処理は、文法が間違っていなければPython側がよしなに実行してくれるものと理解することにしました。


with構文における処理の中身

with構文を判断する処理は目に見えませんが、前後処理が書かれているプログラムはPythonの言語リファレンスとライブラリの内容を照らして、推測ながらそれらしい部分を発見できました。
>リファレンス
docs.python.org

>ライブラリ:contextlib.py(一部抜粋)

class nullcontext(AbstractContextManager):
    """Context manager that does no additional processing.

    Used as a stand-in for a normal context manager, when a particular
    block of code is only sometimes used with a normal context manager:

    cm = optional_cm if condition else nullcontext()
    with cm:
        # Perform operation, using optional_cm if condition is True
    """

    def __init__(self, enter_result=None):
        self.enter_result = enter_result

    def __enter__(self):
        return self.enter_result

    def __exit__(self, *excinfo):
        pass

文章にすると長くなるので、フロー図にするとこんな感じです。

気付いた点としては以下の2つ。
特にファイルクローズをfinallyで実行していない事が意外でした。
・try/finallyを使用しているのではなく、ファイルオープン ~ ファイルクローズまで一直線の処理で走らせていること
・本処理でのエラーは、ファイルクローズ処理側にFalseで渡してその後の動きを委ねている(基本はエラー吐いて終わり)

色々実験してみようとも思いましたが、思いのほか深淵が深淵すぎてここで打ち切ろうと思います。。。
気が向いたらまた何かやってみようかと。


まとめ

with構文は調べると色々理解が深まるが、闇が激深なので
ファイルオープンとクローズを担ってくれる構文と覚えておけばヨシ

参考:
https://djangobrothers.com/blogs/with_statement_basic/
https://zenn.dev/k41531/articles/9c566a778b79ca

<Blender>前髪が五条さんの鳥キャラクターを作る

はじめに

今日はBlenderの日。
Tom Studioさん(下記リンク参照)の動画を参考に、かわいらしい鳥のキャラクターを作ってみます。
Youtubeチャンネル⇒https://l.instagram.com/?u=https%3A%2F%2Fyoutube.com%2Fchannel%2FUCYw2EiB2tSnI7lXq6juL78w&e=ATMph3UOBz5DrQVUdH_LYtBEdUae7oBrdhDm8bTlLFkVt5zWnuzaE0zosMDhitkcOzl04dKl-uw-fubM&s=1

★参考
youtu.be

解説付きで非常に分かりやすかったですが、芸術センスはどうにもならず完成品がこちら。

前髪が完全に五条勝さんです、本当にありがとうございました。


ポイントと思ったテクニックは、
・カクカクなメッシュを丸っこくする(動画Part1 12:51~)
・メッシュの絶妙な曲げ感(動画Part2 1:40~)
・メッシュを滑らかにするサブリビジョンサーフェス(動画Part2 4:54)
・質感、照明位置の補正(動画Part3全部)

後記

気付いたらメッシュの一部が真っ黒になっていました
どうも原因が分からず気合と根性で乗り切りましたが、原因と対処法が分かったら追記しようと思います

<Python Openpyxl>add_imageについてランエボとともに考える

はじめに

Pythonを使ってExcelやwordに画像を張り付けるお勉強で使われたメソッド、「add_image」の仕様がイマイチ理解できなかったので調べてみた。

リファレンス

https://openpyxl.readthedocs.io/en/stable/api/openpyxl.worksheet.worksheet.html#openpyxl.worksheet.worksheet.Worksheet.add_image

・仕様説明
add_image(img, anchor=None)[source]
Add an image to the sheet. Optionally provide a cell for the top-left anchor
⇒和訳:画像をシートに貼り付けます。オプションで左上セル(ExcelならA1)に貼り付けます。

なるほど、後半がイマイチ分からん。

・ソース

def add_data_validation(self, data_validation):
    """ Add a data-validation object to the sheet.  The data-validation
        object defines the type of data-validation to be applied and the
        cell or range of cells it should apply to.
    """
    self.data_validations.append(data_validation)

コメント部分曰く、data_validationには画像データを貼り付けたいセルもしくはセルの範囲を指定せよという事。
なんてことはない、ただのペーストする場所を指定しているだけでした。
add_image(img, 'A1') ⇒ A1セルに画像添付
add_image(img, 'C55') ⇒ C55セルに画像添付

★参考
qiita.com

add_image()で使用する画像のサイズ

次にポイントになるのが、引数img側の事前設定

img.width = 72 * 7
img.height = 25 * 10

こんな感じでわざわざ掛け算するサンプルコードが多いるのは何故だろうと考えてみたが、至極当然な話。
上記の設定の場合「幅72ptの列7個分、高さ25ptの行10個分」の大きさで画像をペーストしますよ、という事。
確かに貼り付ける際、幅何個分行何個分という基準で考えると分かりやすいです。
※cmではなくpt

サイズにマイナスを指定したら?

こんな疑問が頭に思い浮かんだので実験。
ちょうどランエボの画像が大量にあったので使ってみます、予想は縦横が反転して貼り付けられる。

>オリジナルサイズ
幅:約791pt
高さ:約592pt

import openpyxl

workbook = openpyxl.load_workbook("test.xlsx")
sheet = workbook['Sheet1']

# 比較用に正の値サイズで貼り付け
img1 = openpyxl.drawing.image.Image("01.evo5.JPG")
img1.width = 791 / 2
img1.height = 592 / 2
sheet.add_image(img1, 'A1')

# 負の値サイズで貼り付け
img2 = openpyxl.drawing.image.Image("01.evo5.JPG")
img2.width = -791 / 2
img2.height = -592 / 2
sheet.add_image(img2, 'I1')

workbook.save('insert.xlsx')

さて結果は、、、

あれ、、、エラー起きたわけでもないのに貼り付けられて無い?
と思いきや、サイズ0状態で張り付けられていました。

まとめ

add_image()を使いたい場合は、ペーストする画像の縦横サイズとセル番地を事前に定義しておくこと。
そして、画像サイズ設定の最小は0pt、負の値をセットしても0ptで貼りつくよということ。
なんという初歩的な理解

<python OpenCV>機械学習でランエボシリーズを見分けられるのか?

はじめに

Pythonの画像認識用ライブラリ「OpenCV」を使用した機械学習のお勉強中、ふと「初歩的な知識でニッチな違いも判別できるのか?」かと思い、試してみました。

題材は「詳しい人なら分かるが、詳しくない人には同じに見える」系のものが良いと考え、三菱自動車の「ランサーエボリューションV」と「ランサーエボリューションⅦ」にします。(以降「ランエボ5/7」)

機械学習した後、ランエボ5の写真とランエボ7の写真を仕分ける事ができれば成功です。

プログラム

  1. ランエボ5と7の写真を読み込ませてsavファイルを出力
  2. savファイルを読み込んだ上で用意されたランエボの写真を読み込み、判別させる

というプログラムを組みます

1.ランエボ5と7の写真を読み込ませてsavファイルを出力

Excelの設定ファイルから学習用の情報を読み込み、画像を読み込んで学習、ファイル出力するプログラムです

>01.ImageLearning.py

import os
import cv2
import glob
import pandas as pd
from sklearn import svm
import pickle

current_dir = os.getcwd()
labels = []
images = []
# 設定ファイルの読み込み
df = pd.read_excel("リスト.xlsx")

for index, row in df.iterrows():
    # 画像を読み込むフォルダを指定
    image_folder = str(row["No"])+"."+str(row["シリーズ名"])
    image_path = os.path.join(current_dir, image_folder)
    os.chdir(image_path)

    # フォルダ内の画像ファイルを取り出し
    for file in glob.glob("*.JPG"):
        # 画像を学習しやすいように加工
        img = cv2.imread(file)
        img = cv2.resize(img, (64, 64))
        img = img.flatten()

        # ラベルと画像をリストに追加する
        labels.append(row["シリーズ名"])
        images.append(img)
    print("Log  事前準備完了 : "+image_folder)
os.chdir(current_dir)
# 学習モデルを作成、学習
model = svm.SVC(decision_function_shape='ovr')
model.fit(images, labels)

# 相関を表示
print(model.score(images, labels))
# 学習データをファイルに保存
pickle.dump(model, open("model.sav", "wb"))
2.写真を読み込み、判別

1で出力したsavファイルを使用して、画像を判別させるプログラムです
判別結果はコンソールに出力します

>02.ImageJudgement.py

import cv2
import glob
from sklearn import svm
import pickle
#学習モデルの読み込み
model = pickle.load(open("model.sav", 'rb'))
#フォルダ内の画像ファイルを取り出す
for file in glob.glob("*.JPG"):
    img = cv2.imread(file)
    #画像を学習しやすいように加工する
    img = cv2.resize(img, (64, 64))
    img = img.flatten()
    print(file,"判定結果"+str(model.predict([img])))

事前準備

①.設定ファイルのExcel
中身はこんな感じ、Noとシリーズ名を組み合わせて読み込み先フォルダを指定、シリーズ名は後の画像判定の回答にも使用します
置き場は1のプログラムと同じフォルダです

②.学習用画像の用意
1のプログラム置き場のサブフォルダ内に各ランエボ写真を同じ枚数配置
写真の角度、カラーは適当に

ランエボ5用フォルダ

ランエボ7用フォルダ

③.判別対象の画像用意
2のプログラムと同じフォルダに、ランエボ5と7の画像を4枚づつ用意
色は揃えて角度は適当に

実行結果

実際にやってみます
①.画像読み込み、savファイル出力実行結果

(base) C:\Users\USER\python\sample_ImageLearn\01.Learning>python 01.ImageLearning.py
Log  事前準備完了 : 1.エボ5
Log  事前準備完了 : 2.エボ7
1.0

末尾の「1.0」は、教本曰く「学習結果の妥当性(目安」だそうで、別途勉強してみます

②.画像認識、識別実行結果
①の実行で生成した「model.sav」ファイルを、写真読み込み・判別用プログラム格納先にコピーして実行

(base) C:\Users\USER\python\sample_ImageLearn\02.Judgement>python 02.ImageJudgement.py
01.evo5.JPG 判定結果['エボ5']
02.evo5.JPG 判定結果['エボ7']
03.evo5.JPG 判定結果['エボ7']
04.evo5.JPG 判定結果['エボ7']
05.evo7.JPG 判定結果['エボ5']
06.evo7.JPG 判定結果['エボ7']
07.evo7.JPG 判定結果['エボ7']
08.evo7.JPG 判定結果['エボ7']

結果

結果は以下の通り、正答率は50%でした。

画像 正解 Python側答案 結果
1枚目 エボ5 エボ5 正解
2枚目 エボ5 エボ7 不正解
3枚目 エボ5 エボ7 不正解
4枚目 エボ5 エボ7 不正解
5枚目 エボ7 エボ5 不正解
6枚目 エボ7 エボ7 正解
7枚目 エボ7 エボ7 正解
8枚目 エボ7 エボ7 正解

うーん微妙...まあ初めての機械学習としては及第点でしょうか。
今後学習する画像の枚数を増やしたり、ランエボ7寄りの回答なのでランエボ5の画像バリエーションを増やしたらまた違う結果になるかもです。

精度が上がれば、フェアレディZZ33Z34型、色んな車のエンジンルームを比べるのも面白いかと思います。
ひとまずは満足。