pythonコードをCythonで秘匿化してさらにpyinstallでexe化する
ちょっとしたツールをpythonでサクッと作成して提供したい。 でもコードは見られたくない。もちろん無料の方法が良い。なんてことがあるかと思います。 そんなときに知っておくと良い方法を共有します。
前準備
未インストールの場合はMicrosoft C++のビルドツールをインストールしてください。
Microsoft C++ Build Tools - Visual Studio
仮想環境を作成する
virtualenv .venv .venv\Scripts\activate.bat
必要なライブラリをインストールします。 他、サンプルではopencvをインストールしました。
pip install cython pip install pyinstaller
秘匿化したいコードを書く
今回秘匿化するpythonコードです。 ファイル名は「read_and_show_image.pyx」としています。
# read_and_show_image.pyx
import os
import cv2
def read_and_show_image(image_path):
if not os.path.exists(image_path):
return
img = cv2.imread(image_path)
cv2.imshow("image", img)
cv2.waitKey(0)
# 動作確認用。呼び出さないのでなくても良い。
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("image_path")
args = parser.parse_args()
read_and_show_image(args.image_path)
秘匿化する
今作成したコードを秘匿化するためのコードsetup.pyを以下のように作成します。
# setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(
name = "read_and_show_image",
ext_modules = cythonize('read_and_show_image.pyx')
)
秘匿化を実行します。
python setup.py build_ext --inplace
成功すると、以下のようにファイルが生成されます。

秘匿化したコードを呼び出す
秘匿化したライブラリを呼び出すコードを作成します。 このコードは秘匿化されないので余計なことを書かないよう注意です。
# sample.py
from read_and_show_image import read_and_show_image
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("image_path")
args = parser.parse_args()
read_and_show_image(args.image_path)
秘匿化コードと呼び出し側をPyinstallerでまとめてexe化する
呼び出し側も書けたので、これらを1つのexeにまとめます。
pyinstaller sample.py --onefile
実行すると、sample.specというファイルが生成されます。以下のように修正します。

修正したら、exe化します。
pyinstaller samplec.spec
成功すると、distディレクトリにsample.exeという実行ファイルが作成されます。
opencvを含んでいるので、今回は55MBと大きめな実行ファイルが完成しました。
動作確認
生成したexeの動作確認をしてみます。適当にアイコンを読み込ませてみました。
cd dist sample.exe image.png

無事表示されました!
aws SDK for .NETでの認証方法
C#でEC2インスタンスの監視するアプリを作りたかったのですが、認証に失敗して躓いたので記事に残そうと思います。
認証方法
以下の3つがあります。今回は1のSDKストアを使用します。
方法1.SDKストアを使う
ユーザーのホームディレクトリに認証情報ファイルを暗号化して作成し、それを参照します。
方法2.Credentialファイルを使う
キーIDとシークレットキーIDを書いたテキストファイルを指定すれば良いので簡単ですが、ファイルを見ればIDがわかってしまうのでおすすめしません。
方法3.環境変数を使う
こちらもIDが見えるのでおすすめしません。
以下、手順です。
1. プロファイル作成
以下を一度実行すればプロファイルが作成されます。
using Amazon.Runtime.CredentialManagement;
using System;
namespace CreateProfile
{
class Program
{
static void Main(string[] args)
{
string profileName = "[プロファイル名]";
string keyId = "[KEY_ID]";
string secretKey = "SECRET_KEY";
WriteProfile(profileName, keyId, secretKey);
}
static void WriteProfile(string profileName, string keyId, string secretKey)
{
Console.WriteLine($"Create the [{profileName}] profile");
var options = new CredentialProfileOptions
{
AccessKey = keyId,
SecretKey = secretKey
};
var profile = new CredentialProfile(profileName, options);
var netSdkStore = new NetSDKCredentialsFile();
netSdkStore.RegisterProfile(profile);
}
}
}
成功すると、
[%USERPROFILE%\AppData\Local\AWSToolkit\RegisteredAccounts.json
に認証情報ファイルが暗号化した状態で保存されます。

2. プロファイルを利用してインスタンスのステータスを監視する
以下のように実装しました。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Threading;
using Amazon;
using Amazon.EC2;
using Amazon.EC2.Model;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;
namespace CheckStatus
{
class Program
{
static void Main(string[] args)
{
var instanceId = "i-0xxxxxxxxxxxxxxx";
var instanceIds = new List<string> { instanceId };
DescribeInstancesResponse responseDescribe;
var requestDescribe = new DescribeInstancesRequest
{
InstanceIds = instanceIds,
};
var ec2Client = new AmazonEC2Client(RegionEndpoint.APNortheast1);
int wait = 2000; // miliseconds
while (true)
{
Console.Write("");
var response = ec2Client.DescribeInstancesAsync(requestDescribe).Result.Reservations;
foreach(var reservations in response)
{
foreach (var instance in reservations.Instances)
{
Console.WriteLine("{0}: {1}",instance.InstanceId, instance.State.Name);
// 0 : pending
// 16 : running
// 32 : shutting-down
// 48 : terminated
// 64 : stopping
// 80 : stopped
// You can ignore the high byte value by zeroing out all of the bits above 2^8 or
// 256 in decimal.
}
Thread.Sleep(wait);
}
}
}
}
}
設定は以下のようになっています。"AWSProfileName"="sample_profile"と指定しておけば自動で参照してくれます。
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="AWSProfileName" value="sample_profile"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>
実行結果
停止していたインスタンスをマネジメントコンソールから起動→停止したときの挙動です。
i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: pending i-0xxxxxxxxxxxxxxx: running i-0xxxxxxxxxxxxxxx: running i-0xxxxxxxxxxxxxxx: running i-0xxxxxxxxxxxxxxx: running i-0xxxxxxxxxxxxxxx: running i-0xxxxxxxxxxxxxxx: running i-0xxxxxxxxxxxxxxx: running i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopping i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped i-0xxxxxxxxxxxxxxx: stopped
この記事は以下を参考にしました。
行列式の対数を行列で偏微分する公式の証明
今回は,線形代数でよく使う以下の公式の証明を行います.
![]()
ここで,
は正則な正方行列とします.
導出
![]()
公式を使って式を変形するだけなので,わかりやすいかと思います.
の公式の証明を以下の記事に載せているので,よろしければ参考にしてください.
参考文献
この記事は,以下を参考にしました.
余因子と余因子展開 | 大学1年生もバッチリ分かる線形代数入門
行列式を行列で偏微分する公式の証明
機械学習の勉強をしているのですが,EMアルゴリズムの数式を理解できず,線形代数の勉強を始めました...
今回は,線形代数でよく使う以下の公式の証明を行います.![]()
ここで,
はn次元の正則な正方行列とします.
できるだけ視覚的にわかりやすく示せればと思っています. では,証明を初めていきます.|A|はスカラーなので,Aで偏微分すると,以下のようになります.
![]()
ここで,
は行列Aのi行j列成分を表しています.
では,それぞれの要素について考えることにします.行列Aに対する
成分の余因子を
とします.
|A|は余因子展開により,Aのそれぞれの行,列について,以下のように表すことができます.![]()
![]()
以上より,求めたい各要素の偏微分について以下の式が成り立ちます.
![]()
よって,以下が成り立ちます.
![]()
ここで,余因子行列は以下のように表せます.
![]()
2つの式(1), (2)を見比べると,転置になっていることがわかります. したがって,(1)はAの転置行列の余因子行列ということになります.
![]()
逆行列の定義
を用いて,以下のように変形します.
![]()
以上より,題意を示すことができました.
いかがだったでしょうか.偏微分したときに,なぜ転置が起こるのかの理解の助けになれば幸いです.
参考文献
この記事は,以下を参考にしました.
余因子と余因子展開 | 大学1年生もバッチリ分かる線形代数入門
動画ファイルから指定フレームをキャプチャする方法
C++で画像処理をされる方が多いからか、C#でOpenCVを使う記事がなかなか見つからなくて困っています。
自分が苦労したことを共有し、誰かの助けになれば幸いです。
今回は、OpenCVSharpを使って、動画ファイルから指定したフレームの画像を取得する方法を紹介いたします。
サンプルコード
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using OpenCvSharp; namespace CaptureFrame { class Capture { static void Main(string[] args) { // vtest.avi ファイルの500フレーム画像を取得する var frame = CaptureFrame("vtest.avi", 500); if (0 < frame.Width && 0 < frame.Height) { Cv2.ImShow("frame", frame); Cv2.WaitKey(0); } } static Mat CaptureFrame(string fileName, int frameNo) { var frame = new Mat(); using (var videoCapture = new VideoCapture(fileName)) { // 次にキャプチャされるフレームのインデックスを // 引数で受け取ったフレーム番号にセットする videoCapture.Set(CaptureProperty.PosFrames, frameNo); videoCapture.Read(frame); } return frame; } } }結果
目的の画像が表示されました!
注意
①Dispose漏れ
VideoCaptureを使用したあとは、必ずDisposeしましょう!
Disposeし忘れを防止するために、usingステートメントを使用することを勧めます!②フレーム開始番号
フレームの番号は0から始まります。 サンプルコードではフレーム番号を500と指定しています。 よって、動画の最初のフレームから501番目のフレームを取得していることになります。
動画
動画は以下からダウンロードしました。 github.com
参考記事
動画を扱う — OpenCV-Python Tutorials 1 documentation www.sejuku.net
