2022/07/01(金) [n年前の日記]
#1 [python][cg_tools] ディザリング処理をするプログラムをPythonに移植中その5
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直しているところ。
_Arbitrary-palette positional dithering algorithm
アルゴリズム3を移植中だけど、C++のソースの中に map というものが出現してきた。ググってみたら連想配列相当らしい。平衡二分木がどうとか書いてある…。それってPythonではどう書けばいいのか…。とりあえず、Pythonの辞書(dict)で代替して様子を見てみようか…。
_Arbitrary-palette positional dithering algorithm
アルゴリズム3を移植中だけど、C++のソースの中に map というものが出現してきた。ググってみたら連想配列相当らしい。平衡二分木がどうとか書いてある…。それってPythonではどう書けばいいのか…。とりあえず、Pythonの辞書(dict)で代替して様子を見てみようか…。
[ ツッコむ ]
2022/07/02(土) [n年前の日記]
#1 [python][cg_tools] ディザリング処理をするプログラムをPythonに移植中その6
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直しているところ。
_Arbitrary-palette positional dithering algorithm
上記で紹介されている、Adobe Photoshop っぽいディザ処理を Python で書き直しているのだけど、かなりシンプルな処理なのに、ちゃんとそれっぽい画像に変換されるあたりがなんとも不思議。前回の計算処理で出てしまった誤差を、次の計算に持ち越すあたりがポイントなのだろうか…?
_Arbitrary-palette positional dithering algorithm
上記で紹介されている、Adobe Photoshop っぽいディザ処理を Python で書き直しているのだけど、かなりシンプルな処理なのに、ちゃんとそれっぽい画像に変換されるあたりがなんとも不思議。前回の計算処理で出てしまった誤差を、次の計算に持ち越すあたりがポイントなのだろうか…?
[ ツッコむ ]
2022/07/03(日) [n年前の日記]
#1 [nitijyou] 自宅サーバ止めてました
雷が鳴ったので、16:15-19:15の間、自宅サーバ止めてました。申し訳ないです。
[ ツッコむ ]
#2 [python] パレットデータを取り出すPythonスクリプトを書いてる
ここ最近、任意のパレットデータでディザ処理をかける実験をしているのだけど、そのパレットデータを別途指定できるようにしたいなと。今まではソース内に配列として書いてしまっていたので、パレットデータを変更して実験することが容易ではなかった。
Python の Pillow(PIL) を使って、インデックスカラーのPNGを読み込んで、パレット値を読み取る処理を書いてみたけど、使ってない色まで RGB=(0,0,0) で得られてしまう。インデックスカラー画像は256色あるものと決め打ちされているっぽい。16色や32色しか使ってないpngをパレット指定用画像として使いたいのだけどな…。
もしかして、GIMPのパレットデータファイル (.gpl) を読み込んで処理するのもアリかなと思えてきた。RGB値を正規表現で取り出せそうか少し試してみよう…。
Python の Pillow(PIL) を使って、インデックスカラーのPNGを読み込んで、パレット値を読み取る処理を書いてみたけど、使ってない色まで RGB=(0,0,0) で得られてしまう。インデックスカラー画像は256色あるものと決め打ちされているっぽい。16色や32色しか使ってないpngをパレット指定用画像として使いたいのだけどな…。
もしかして、GIMPのパレットデータファイル (.gpl) を読み込んで処理するのもアリかなと思えてきた。RGB値を正規表現で取り出せそうか少し試してみよう…。
[ ツッコむ ]
2022/07/04(月) [n年前の日記]
#1 [nitijyou] 腹痛で大変だった
おそらくだけど、また尿路結石の痛みが出て苦しんでた。
ロキソニンを飲んでもこんなに痛いのか…と絶望的な気分になるぐらいの痛みだった。ただ、あらかじめ薬を飲んでいたせいか、前回のように何度も吐くほどの痛みにはならかった。とは言っても、布団の上でゴロゴロとのたうち回るぐらい痛かったけど…。
19:00頃、あまりに痛いので、ロキソニンを追加で飲んだ。本来最低でも4時間ほど間隔を空けて飲むこと、となっていたのだけど、どうにも耐えられなくて…。4時間も3時間もたいして変わらんだろと勝手に決めつけて飲んだけれど、何かしらの効果があったのかどうかは不明。追加で飲んでも、その後もずっと痛かった。
トイレで小さいほうをしたら血が出ていたので、やはりコレは尿路結石なんだろうなと。
前回この症状が出たのは… _2022/04/16 だったらしい。2ヶ月半で再発ということになるのだろうか。メモを確認したら、前回は19:10頃から痛み出して、21:40頃に病院を出たと書いてあった。自分の場合、2時間以上は痛みが続くようだなと。
- 16:00頃に右脇腹に違和感を覚えて、これはもしや、また例の痛みではないのかと、痛み止めのロキソニンを飲んだ。
- 2時間後、18:00頃から、右脇腹や背中の痛みがどんどん増してきた。
- 2時間半後、20:30頃に、ようやく収まった。
ロキソニンを飲んでもこんなに痛いのか…と絶望的な気分になるぐらいの痛みだった。ただ、あらかじめ薬を飲んでいたせいか、前回のように何度も吐くほどの痛みにはならかった。とは言っても、布団の上でゴロゴロとのたうち回るぐらい痛かったけど…。
19:00頃、あまりに痛いので、ロキソニンを追加で飲んだ。本来最低でも4時間ほど間隔を空けて飲むこと、となっていたのだけど、どうにも耐えられなくて…。4時間も3時間もたいして変わらんだろと勝手に決めつけて飲んだけれど、何かしらの効果があったのかどうかは不明。追加で飲んでも、その後もずっと痛かった。
トイレで小さいほうをしたら血が出ていたので、やはりコレは尿路結石なんだろうなと。
前回この症状が出たのは… _2022/04/16 だったらしい。2ヶ月半で再発ということになるのだろうか。メモを確認したら、前回は19:10頃から痛み出して、21:40頃に病院を出たと書いてあった。自分の場合、2時間以上は痛みが続くようだなと。
[ ツッコむ ]
2022/07/05(火) [n年前の日記]
#1 [nitijyou] 自宅サーバ止めてました
雷が鳴ったので、18:00-19:40の間、自宅サーバ止めてました。申し訳ないです。
かなり近くに雷が落ちたようで、普段聞いたことが無いような音が…。不安になってエアコンのコンセントまで抜いたりもして。この時期にエアコンが雷で壊されたら命に係わる…。
かなり近くに雷が落ちたようで、普段聞いたことが無いような音が…。不安になってエアコンのコンセントまで抜いたりもして。この時期にエアコンが雷で壊されたら命に係わる…。
[ ツッコむ ]
#2 [nitijyou] 一日中寝てた
昨日のダメージが尾を引いてしまったのか、眠くて眠くて、一日中寝てた。起きたら起きたで手足に力が入らず。考えてみたら昨晩素麺を御椀一杯程度食べて、それ以降何も食べてないなと…。夕飯をどうにか食べたら少し動くようになってきた。
[ ツッコむ ]
2022/07/06(水) [n年前の日記]
#1 [gimp] GIMP を 2.10.32 に更新した
数日前に、Windows10 x64 21H2上にインストールしてあった GIMP 2.10.30 x64 Portable samj版を、GIMP 2.10.32 x64 Portable samj版に更新していたことをメモしてなかった気がするので一応メモ。
最初は上書きでインストールしてみたのだけど、GIMP を起動したら .dll が見つからない等のエラーが出てしまった。2.10.30 と 2.10.32 のフォルダ構成も結構違っていたようなので、別フォルダを作成してインストールすることにした。今後更新があった場合も、別フォルダを作成してインストールすることにしよう…。
ただ、別フォルダにインストールしてしまうと再設定が面倒で…。今回は、旧版インストールフォルダ\Preferences\ 内の、以下のファイルをコピーして再設定を避けてみた。
APNGエクスポート用プラグインも一応導入しておいた。
_APNG (animated PNG) plug-in for Gimp 2.10 Windows64x - GIMP Chat
ただ、GIMP 2.10 はWebP画像フォーマットに標準で対応しているので、フルカラーのアニメ画像が欲しい場合は WebP でエクスポートしたほうがいいような気もする。APNG は拡張子が .png だから、一般的な画像ビューアは、普通のpngなのかAPNG なのか判別できなくて正常表示されないので…。WebPなら拡張子からして違うので、そういった問題は起きないのではないかと…。
最初は上書きでインストールしてみたのだけど、GIMP を起動したら .dll が見つからない等のエラーが出てしまった。2.10.30 と 2.10.32 のフォルダ構成も結構違っていたようなので、別フォルダを作成してインストールすることにした。今後更新があった場合も、別フォルダを作成してインストールすることにしよう…。
ただ、別フォルダにインストールしてしまうと再設定が面倒で…。今回は、旧版インストールフォルダ\Preferences\ 内の、以下のファイルをコピーして再設定を避けてみた。
- controllerrc : マウスボタンの割り当てが設定されてる。
- gimprc : ブラシ、スクリプト、プラグインフォルダ等が設定されてる。GIMPインストールフォルダの記述部分を修正する必要有。
- menurc : ショートカットキー割り当てが設定されてる。
- sessionrc : 各ウインドウの位置その他が設定されてる。
- templaterc : テンプレート一覧が設定されてる。
APNGエクスポート用プラグインも一応導入しておいた。
_APNG (animated PNG) plug-in for Gimp 2.10 Windows64x - GIMP Chat
ただ、GIMP 2.10 はWebP画像フォーマットに標準で対応しているので、フルカラーのアニメ画像が欲しい場合は WebP でエクスポートしたほうがいいような気もする。APNG は拡張子が .png だから、一般的な画像ビューアは、普通のpngなのかAPNG なのか判別できなくて正常表示されないので…。WebPなら拡張子からして違うので、そういった問題は起きないのではないかと…。
[ ツッコむ ]
2022/07/07(木) [n年前の日記]
#1 [python] Pillowのgetpixel()は本当に遅いのか気になったので確認してみた
Python で画像を扱える Pillow (PIL)モジュールについて、1ドット単位で値を読んだり書いたりできる .getpixel()/.putpixel() というメソッドがあるのだけど。巷の各種記事では処理速度が遅いと書いてあって、本当にそうなのかなと気になってきた。
そんなわけで、ベンチマークを取ってみた。環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1。CPU は AMD Ryzen 5 5600X (6コア12スレッド、ベースクロック3.7GHz)。
4288x2848ドットの画像に対してひたすらドットを読むだけの処理をしてみた。ちなみに利用した画像は以下。
_十代の少女 可愛い 肖像画 - Pixabayの無料写真
ソースは以下。
_05getpixel_bench.py
動作には、Pillow と benchmarker が必要。
結果は以下のような感じになった。
.getdata() を使えばたしかに速くなるけれど、一次元配列に対してアクセスするような書き方になるので、可読性はほんのちょっと、若干かすかに、ビミョーに悪くなるような気もする。
対して、.load() を使ったアクセスなら、.getpixel() と同様に x, y を指定してアクセスできるし、しかも .getdata() を使った場合とそれほど処理速度も変わらないわけで…。
個人的には、.getdata() より、可読性と処理速度の両方をそこそこ得られる .load() を使ったほうがいいのではないかと思えてきた。
余談。手元で実験に使ってるスクリプトが、とにかく遅くて…。.load() を使って画像の各ドットにアクセスしていたのだけど、.getdata() を使ったらもっと速く処理できないかと少し期待しながらベンチマークを取ったわけで。ある意味、残念な結果になってしまった。今回、そこらへんを変えてみても結果は変わらないようだなと…。
そんなわけで、ベンチマークを取ってみた。環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1。CPU は AMD Ryzen 5 5600X (6コア12スレッド、ベースクロック3.7GHz)。
4288x2848ドットの画像に対してひたすらドットを読むだけの処理をしてみた。ちなみに利用した画像は以下。
_十代の少女 可愛い 肖像画 - Pixabayの無料写真
ソースは以下。
_05getpixel_bench.py
from PIL import Image from benchmarker import Benchmarker infile = "teen-girl-4467541_4288x2848.jpg" def main(): im = Image.open(infile) width, height = im.size print("%d x %d" % (width, height)) with Benchmarker(100) as bench: @bench(".getdata()") def _(bm): im = Image.open(infile) dt = im.getdata() for y in range(height): idx = width * y for x in range(width): _ = dt[idx + x] @bench(".load()") def _(bm): im = Image.open(infile) src = im.load() for y in range(height): for x in range(width): _ = src[x, y] @bench(".getpixel()") def _(bm): im = Image.open(infile) for y in range(height): for x in range(width): _ = im.getpixel((x, y)) if __name__ == '__main__': main()
動作には、Pillow と benchmarker が必要。
pip install Pillow -U pip install Benchmarker -U
結果は以下のような感じになった。
> py 05getpixel_bench.py 4288 x 2848 ## benchmarker: release 4.0.1 (for python) ## python version: 3.9.13 ## python compiler: MSC v.1929 64 bit (AMD64) ## python platform: Windows-10-10.0.19044-SP0 ## python executable: C:\Python\Python39-64\python.exe ## cpu model: AMD64 Family 25 Model 33 Stepping 2, AuthenticAMD ## parameters: loop=100, cycle=1, extra=0 ## real (total = user + sys) .getdata() 0.7155 0.7188 0.6875 0.0312 .load() 0.7961 0.7969 0.7969 0.0000 .getpixel() 6.2659 6.2656 6.2656 0.0000 ## Ranking real .getdata() 0.7155 (100.0) ******************** .load() 0.7961 ( 89.9) ****************** .getpixel() 6.2659 ( 11.4) ** ## Matrix real [01] [02] [03] [01] .getdata() 0.7155 100.0 111.3 875.8 [02] .load() 0.7961 89.9 100.0 787.1 [03] .getpixel() 6.2659 11.4 12.7 100.0
- .getpixel() は、たしかに遅かった。他のアクセス方法より数倍遅い。
- .getdata() は、たしかに一番速かった。
- ただ、Image.load() をしてからアクセスする方法も、.getdata() 並みの速さでアクセスできるように見える。
.getdata() を使えばたしかに速くなるけれど、一次元配列に対してアクセスするような書き方になるので、可読性はほんのちょっと、若干かすかに、ビミョーに悪くなるような気もする。
対して、.load() を使ったアクセスなら、.getpixel() と同様に x, y を指定してアクセスできるし、しかも .getdata() を使った場合とそれほど処理速度も変わらないわけで…。
個人的には、.getdata() より、可読性と処理速度の両方をそこそこ得られる .load() を使ったほうがいいのではないかと思えてきた。
余談。手元で実験に使ってるスクリプトが、とにかく遅くて…。.load() を使って画像の各ドットにアクセスしていたのだけど、.getdata() を使ったらもっと速く処理できないかと少し期待しながらベンチマークを取ったわけで。ある意味、残念な結果になってしまった。今回、そこらへんを変えてみても結果は変わらないようだなと…。
[ ツッコむ ]
#2 [python][cg_tools] ディザリング処理をするプログラムをPythonに移植中その7
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直しているところ。
_Arbitrary-palette positional dithering algorithm
ある程度動くようになったので、一応アップロード。元記事内の、アルゴリズム1、2、3、及び Photoshopっぽいアルゴリズムを、全部1つのファイルにまとめてみた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
動作には、Pillow と tqdm が必要。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1 + tqdm 4.64.0。
_Arbitrary-palette positional dithering algorithm
ある程度動くようになったので、一応アップロード。元記事内の、アルゴリズム1、2、3、及び Photoshopっぽいアルゴリズムを、全部1つのファイルにまとめてみた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
動作には、Pillow と tqdm が必要。
pip install Pillow -U pip install tqdm -U
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 64bit + Pillow 9.1.1 + tqdm 4.64.0。
◎ 使い方。 :
使い方は以下のような感じ。--mode N でアルゴリズムを選べる。
一応、ヘルプ表示も載せておく。
mode の違いは以下のような感じ。元記事を読まないと分からないとは思うけど…。
py yliluoma_ordered_dither.py -i scene.png -o scenedither_m0_8x8.png --mode 0 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m1_8x8.png --mode 1 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m2_8x8.png --mode 2 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m3_8x8.png --mode 3 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m4_8x8.png --mode 4 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m5_8x8.png --mode 5 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m6_8x8.png --mode 6 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m7_8x8.png --mode 7 py yliluoma_ordered_dither.py -i scene.png -o scenedither_m8_8x8.png --mode 8
一応、ヘルプ表示も載せておく。
> py yliluoma_ordered_dither.py --help usage: yliluoma_ordered_dither.py [-h] -i INPUT -o OUTPUT [-p PALETTE] [-d DITHER] [-m MODE] [-c] Yliluoma ordered dithering 1, 2, 3, 4 optional arguments: -h, --help show this help message and exit -i INPUT, --input INPUT Input png filename -o OUTPUT, --output OUTPUT Output png filename -p PALETTE, --palette PALETTE Palette file (.png or .gpl) -d DITHER, --dither DITHER Dither type 2,4,8 (2x2,4x4,8x8). default: 8 -m MODE, --mode MODE job kind 0 - 8. default: 3 -c, --ciede2000 Enable CIEDE2000 (mode 6 only
mode の違いは以下のような感じ。元記事を読まないと分からないとは思うけど…。
- mode 0: アルゴリズム1。2色の組み合わせを意識して差し替えるべき色を求める。かなり遅い。
- mode 1: アルゴリズム1。mode 0 の改良版。突飛な色の組み合わせは除外する。かなり遅い。
- mode 2: アルゴリズム1。mode 1 の改良版。ガンマ値を正しく反映させる。かなり遅い。
- mode 3: アルゴリズム1。mode 2 の処理高速化版。ループを回さずに数式で近似値を求める。少し早い。
- mode 4: アルゴリズム1。3色の組み合わせを意識して処理する。かなり遅い。
- mode 5: アルゴリズム2。N色の組み合わせを意識しないで色を求める。かなり遅い。
- mode 6: アルゴリズム2。mode 5 の改良版。ガンマ値を正しく反映させる。かなり遅い。
- mode 7: アルゴリズム3。mode 6 の改良版。かなり遅い。
- mode 8: Adobe Photoshop っぽいアルゴリズム。結構早い。
◎ 問題点。 :
このスクリプト、とにかく処理が遅い…。CPU: AMD Ryzen 5 5600X を使って、289x176ドットの画像に対して、16色でディザリングをかけるのに、最悪8分ぐらいかかる…。もちろん、使うアルゴリズムにもよるのだけど…。
比較的変換処理が速いのは、--mode 3 と --mode 8。
それ以外のアルゴリズムは、まあ、遅い。とんでもなく遅い。
比較的変換処理が速いのは、--mode 3 と --mode 8。
- mode 3 は、ループを回して総当たりで相応しい色を探さずに、数式で大まかに合いそうな色を探すアルゴリズム。ただ、速くはなるけれど、生成画像の品質は落ちる。
- mode 8 は、Adobe Photoshop で使われていたらしいアルゴリズム。品質と処理速度のバランスが取れている。ただ、生成画像は全体的にボケ気味な印象を受けた。
それ以外のアルゴリズムは、まあ、遅い。とんでもなく遅い。
◎ 改善策。 :
改善策は、いくつか思いつく。
元記事のソースは 8x8 のディザで処理しているけれど、見た感じ、4x4 のディザでも十分かなと思えた。8x8のディザだと、一番深いところで64回ループが回るけど、4x4なら16回のループで済むので、単純計算で約4倍の速さになりそう。
並列処理を導入するのも手かもしれない。Python で並列処理をさせる方法が分からなかったので今回は試してないけど、今時のCPUなら4コアだの6コアだの持ってるだろうから、1/4、1/6 の処理時間で済むのではなかろうか。実際、元々のC++版は、OpenMP(?) を有効にしてビルドして、並列処理する実行バイナリにしたら爆速になった。
画像の全てのドットに対して、毎回ループを回して、適切なパレットカラーを求めているあたりがアレだろうなという気もする。どれかしらの要素を事前に計算してキャッシュしておいて、そのキャッシュを使い回すようにすれば、もうちょっと改善されるかもしれない。例えばベタ部分が多い画像の場合、画像内に出てくる色の数は限定されるはずで、以前計算したことがある色が出現したら、その時の計算結果を再度使う、という作りにするだけでも効果はありそう。
元記事にも書いてあるけど、kd-tree 等を導入すれば改善される可能性もあるのだろうなと…。画像内のとある色について、差し替えに相応しい色はどれか、と探すあたりで時間がかかっているので、探索時間が短くなれば効果はあるはず。
元記事のソースは 8x8 のディザで処理しているけれど、見た感じ、4x4 のディザでも十分かなと思えた。8x8のディザだと、一番深いところで64回ループが回るけど、4x4なら16回のループで済むので、単純計算で約4倍の速さになりそう。
並列処理を導入するのも手かもしれない。Python で並列処理をさせる方法が分からなかったので今回は試してないけど、今時のCPUなら4コアだの6コアだの持ってるだろうから、1/4、1/6 の処理時間で済むのではなかろうか。実際、元々のC++版は、OpenMP(?) を有効にしてビルドして、並列処理する実行バイナリにしたら爆速になった。
画像の全てのドットに対して、毎回ループを回して、適切なパレットカラーを求めているあたりがアレだろうなという気もする。どれかしらの要素を事前に計算してキャッシュしておいて、そのキャッシュを使い回すようにすれば、もうちょっと改善されるかもしれない。例えばベタ部分が多い画像の場合、画像内に出てくる色の数は限定されるはずで、以前計算したことがある色が出現したら、その時の計算結果を再度使う、という作りにするだけでも効果はありそう。
元記事にも書いてあるけど、kd-tree 等を導入すれば改善される可能性もあるのだろうなと…。画像内のとある色について、差し替えに相応しい色はどれか、と探すあたりで時間がかかっているので、探索時間が短くなれば効果はあるはず。
◎ 余談。 :
このスクリプトで実験した後、減色ツールの OPTPiX や Yukari を使って減色をしてみたら、どれも一瞬で結果が返ってきて…。もしかすると1秒もかかってないのでは…。
それらはおそらくC/C++で書かれているのかなと想像するのだけど、それにしても処理時間が違い過ぎる。おそらく、アルゴリズムからして、もっと上手いやり方があるのだろう…。
それらはおそらくC/C++で書かれているのかなと想像するのだけど、それにしても処理時間が違い過ぎる。おそらく、アルゴリズムからして、もっと上手いやり方があるのだろう…。
[ ツッコむ ]
2022/07/08(金) [n年前の日記]
#1 [python] Pythonの並行処理・並列処理について勉強中
Python の並行処理(マルチスレッド)、並列処理(マルチプロセス)について勉強中。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13。
巷の解説記事内で紹介されてる各サンプルを手元で動かしてみて、マルチスレッドについてはちゃんと動作することを確認できたのだけど。マルチプロセスのサンプルを動かそうとしたら、いきなりエラーが出て悩んでしまった。もしかして、Windows ではマルチプロセスは使えないのだろうか? 試しに Ubuntu Linux 20.04 LTS上で同じスクリプトを動かしてみたら、そちらではすんなり動いてしまった。
どうやら、マルチスレッドはともかく、Windows上ではPythonのマルチプロセスは動かないようだなと…。「Linux や Mac ならマルチプロセスが使えますよ」「Windows? 知らんがな」という状況なのだろう…。
と、一瞬思い込んでしまったのだけど、その後も他の解説記事を眺めて試していたら、Windows上でもマルチプロセスのサンプルが動いてくれた。「Linux でしか使えないよ」というわけではないらしい。
Windows上、かつ、マルチプロセスを使うスクリプトは、以下の記述が無いといかんようで。実処理をトップレベル(?)に書いてしまうとエラーが出てしまう。ただし、Linux上ではトップレベルに書いてしまっても動く、というオチだった模様。
ということで、巷の解説記事内でマルチプロセスのサンプルを見かけて、もし、処理がトップレベルに書かれてたら、上記の記述を追加して動作確認してみると良い、という話になるのだろうなと。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13。
巷の解説記事内で紹介されてる各サンプルを手元で動かしてみて、マルチスレッドについてはちゃんと動作することを確認できたのだけど。マルチプロセスのサンプルを動かそうとしたら、いきなりエラーが出て悩んでしまった。もしかして、Windows ではマルチプロセスは使えないのだろうか? 試しに Ubuntu Linux 20.04 LTS上で同じスクリプトを動かしてみたら、そちらではすんなり動いてしまった。
どうやら、マルチスレッドはともかく、Windows上ではPythonのマルチプロセスは動かないようだなと…。「Linux や Mac ならマルチプロセスが使えますよ」「Windows? 知らんがな」という状況なのだろう…。
と、一瞬思い込んでしまったのだけど、その後も他の解説記事を眺めて試していたら、Windows上でもマルチプロセスのサンプルが動いてくれた。「Linux でしか使えないよ」というわけではないらしい。
Windows上、かつ、マルチプロセスを使うスクリプトは、以下の記述が無いといかんようで。実処理をトップレベル(?)に書いてしまうとエラーが出てしまう。ただし、Linux上ではトップレベルに書いてしまっても動く、というオチだった模様。
def main(): ... if __name__ == "__main__": main()
ということで、巷の解説記事内でマルチプロセスのサンプルを見かけて、もし、処理がトップレベルに書かれてたら、上記の記述を追加して動作確認してみると良い、という話になるのだろうなと。
◎ 参考ページ。 :
_[Python] スレッドで実装する - Qiita
_PythonのThread(並列処理)は速度改善効果がないので「concurrent.futures」を使う - "BOKU"のITな日常
_Pythonでconcurrent.futuresを使った並列タスク実行 - Qiita
_concurrent.futures: 並行処理 in Python - Heavy Watal
_[Python] multiprocessingを試す (1)
_[Python] multiprocessingを試す (2)
_Pythonの並列処理・並行処理をしっかり調べてみた - Qiita
_【Python】並列処理でプログラムを高速化 | 無次元日記
_Pythonで並列処理のすすめ
_Pythonのthreadingとmultiprocessingを完全理解 - Qiita
_【Python】マルチプロセスについて - Qiita
_PythonのThread(並列処理)は速度改善効果がないので「concurrent.futures」を使う - "BOKU"のITな日常
_Pythonでconcurrent.futuresを使った並列タスク実行 - Qiita
_concurrent.futures: 並行処理 in Python - Heavy Watal
_[Python] multiprocessingを試す (1)
_[Python] multiprocessingを試す (2)
_Pythonの並列処理・並行処理をしっかり調べてみた - Qiita
_【Python】並列処理でプログラムを高速化 | 無次元日記
_Pythonで並列処理のすすめ
_Pythonのthreadingとmultiprocessingを完全理解 - Qiita
_【Python】マルチプロセスについて - Qiita
[ ツッコむ ]
2022/07/09(土) [n年前の日記]
#1 [python] Pythonの並行処理・並列処理についてまだ勉強中
昨日に引き続き、Python の並行処理・並列処理について勉強中。巷の解説記事のサンプルをコピペして動作確認。
[ ツッコむ ]
2022/07/10(日) [n年前の日記]
#1 [nitijyou] 投票してきた
朝08:00頃、近所の公会堂まで電動自転車で行ってきて、参議院選挙の投票をしてきた。帰りにザ・ビッグに寄って夜食等を購入。
朝の時点でも暑いなと思ってたら、やはり昼間には30度を超えてた…。朝のうちに行っておいて良かった…。
朝の時点でも暑いなと思ってたら、やはり昼間には30度を超えてた…。朝のうちに行っておいて良かった…。
[ ツッコむ ]
2022/07/11(月) [n年前の日記]
#1 [xyzzy] xyzzyのスニペットについて調べてた
自分は普段 xyzzy という、操作感覚が emacsに近いWindows専用エディタを使っているのだけど。スニペット(Snippet)相当の機能は無いのかなと気になってきたので少し調べてみたり。
スニペット機能と言うのは…要は「定型文入力機能」という説明でいいのだろうか。プログラムソースを打ち込んでいく際、お決まりの一文を入力する場面がちょくちょくあるけれど、それらの定型文を登録しておいて挿入できれば作業が楽になる。
xyzzy の場合、abbrev と dabbrev という、2つの入力補完機能を持っていて。
スニペットは、前者の abbrev に相当するのだろうなと。
ただ、自分の手元の xyzzy では、abbrev の実行(?)が割り当てられてるはずの C-x ' が機能しなくて。設定ファイル ~/.xyzzy を確認したら、C-x ' には just-one-space が割り当てられていて、代わりに M-SPC に snippet-expand が割り当てられてた。昔、自分で設定したんだろうけど…何だっけコレ…。
どうやら自分、snippet.l という拡張を導入して、expand-abbrev の代わりに snippet-expand を使うようにしていたようだなと…。
スニペット機能と言うのは…要は「定型文入力機能」という説明でいいのだろうか。プログラムソースを打ち込んでいく際、お決まりの一文を入力する場面がちょくちょくあるけれど、それらの定型文を登録しておいて挿入できれば作業が楽になる。
xyzzy の場合、abbrev と dabbrev という、2つの入力補完機能を持っていて。
- abbrev : 静的補完。事前に登録した定型文を選んで入力補完してくれる。
- dabbrev : 動的補完。現在開いているバッファ(ファイル)の中から単語を抽出して、入力補完してくれる。
スニペットは、前者の abbrev に相当するのだろうなと。
ただ、自分の手元の xyzzy では、abbrev の実行(?)が割り当てられてるはずの C-x ' が機能しなくて。設定ファイル ~/.xyzzy を確認したら、C-x ' には just-one-space が割り当てられていて、代わりに M-SPC に snippet-expand が割り当てられてた。昔、自分で設定したんだろうけど…何だっけコレ…。
どうやら自分、snippet.l という拡張を導入して、expand-abbrev の代わりに snippet-expand を使うようにしていたようだなと…。
◎ snippet.lについて。 :
ググってみたら、snippet.l はもう入手不可能っぽい。Web Archive で解説ページは見つけられたけど、.zipファイルはDLできなかった。
_silog - script/snippet (Web Archive)
幸い、xyzzyインストールフォルダ\.netinst\src\ 以下で、snippet-2007.07.15.zip というファイルが見つかった。一応、バックアップも兼ねて置いておきます。
_snippet-2007.07.15.zip
snippet.l と abbrev の違いは、定型文を挿入した直後の動作だろうか…。abbrev は定型文を挿入して終わるけど、snippet.l は、挿入後に入力が必要な個所にカーソルを合わせてくれて、C-n や C-p で入力箇所を移動できるっぽい。
まあ、一般的には、abbrev が使えるだけでも十分かなという気もする。 *1
_silog - script/snippet (Web Archive)
幸い、xyzzyインストールフォルダ\.netinst\src\ 以下で、snippet-2007.07.15.zip というファイルが見つかった。一応、バックアップも兼ねて置いておきます。
_snippet-2007.07.15.zip
snippet.l と abbrev の違いは、定型文を挿入した直後の動作だろうか…。abbrev は定型文を挿入して終わるけど、snippet.l は、挿入後に入力が必要な個所にカーソルを合わせてくれて、C-n や C-p で入力箇所を移動できるっぽい。
まあ、一般的には、abbrev が使えるだけでも十分かなという気もする。 *1
◎ abbrevについて。 :
以下のページが分かりやすいだろうか…。
_単語補完機能 - xyzzy - emacs like editor in windows
_xyzzyで単語の自動補完(Static編) - tohokuaikiのチラシの裏
_abbrevの使い方 - himadatanode’s blog
_xyzzy - 覚書wiki - atwiki(アットウィキ)
_abbrev modeのやりかた (Web Archive)
_QuickTour/abbrev - XyzzyWiki (Web Archive)
_動的補完と静的補完の設定と使い方 | for programer | しょぼしょぼすくりぷと xyzzy (Web Archive)
消滅してしまったページが多いのがなんとも。
emacsの解説も参考になるかもしれず。
_abbrev
以下で、デフォルトのキー割り当てが紹介されてる。
_xyzzy機能分類別キーバインド一覧
abbrev の定義ファイルは ~/.abbrev_defs だけど、M-x list-abbrevs か M-x edit-abbrevs を実行すれば編集できる。
C-x C-a か C-x + を使って仮登録してから、M-x list-abbrevs でちゃんと修正、てな感じの登録の仕方になるのかな。たぶん。
_単語補完機能 - xyzzy - emacs like editor in windows
_xyzzyで単語の自動補完(Static編) - tohokuaikiのチラシの裏
_abbrevの使い方 - himadatanode’s blog
_xyzzy - 覚書wiki - atwiki(アットウィキ)
_abbrev modeのやりかた (Web Archive)
_QuickTour/abbrev - XyzzyWiki (Web Archive)
_動的補完と静的補完の設定と使い方 | for programer | しょぼしょぼすくりぷと xyzzy (Web Archive)
消滅してしまったページが多いのがなんとも。
emacsの解説も参考になるかもしれず。
_abbrev
以下で、デフォルトのキー割り当てが紹介されてる。
_xyzzy機能分類別キーバインド一覧
- C-x C-a : add-mode-abbrev 現在のモードのアブレブテーブルに登録(展開する文字列→略称)
- C-x C-h : inverse-add-mode-abbrev 現在のモードのアブレブテーブルに登録(展開する文字列→略称)
- C-x ' : expand-abbrev アブレブ略語を展開
- C-x + : add-global-abbrev グローバルアブレブテーブルに登録(展開する文字列→略称)
- C-x - : inverse-add-global-abbrev グローバルアブレブテーブルに登録(略称→展開する文字列)
abbrev の定義ファイルは ~/.abbrev_defs だけど、M-x list-abbrevs か M-x edit-abbrevs を実行すれば編集できる。
C-x C-a か C-x + を使って仮登録してから、M-x list-abbrevs でちゃんと修正、てな感じの登録の仕方になるのかな。たぶん。
*1: いやまあ、今から新規に xyzzy を使う人は居ないだろうから、一般的もへったくれも無いだろうけど。開発停止状態と言っていいほど枯れ切ってしまって、慣れ過ぎちゃって離れられない人しか使ってないエディタのはずだし…。
[ ツッコむ ]
2022/07/12(火) [n年前の日記]
#1 [python] ディザをかけるPythonスクリプトを弄ってる
Pythonで並列処理(マルチプロセス)を使うやり方が大体分かってきたので、先日 Python で書いた、ディザをかけるスクリプトに並列処理を加えてみようと作業を始めたのだけど。特定のモードの処理に必要な関数だけを残して実行してみたら、以前のスクリプトで得られた生成画像と違う結果になってしまって悩んでいるところ。自分はどこでミスをしてしまったのか…。
[ ツッコむ ]
2022/07/13(水) [n年前の日記]
#1 [python] ディザリング処理をするPythonスクリプトに並列処理を追加してみた
任意のパレットを指定してディザリングをかけるサンプルプログラム群を ―― C++ で書かれてるソレを Python で書き直してみたわけだけど。
_Arbitrary-palette positional dithering algorithm
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
あまりに処理時間がかかり過ぎるので、並列処理(マルチプロセス)も使えるように修正してみた。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 + Pillow 9.1.1 + tqdm 4.64.0。
ソースは以下。
_yodither1.py (Yliluoma's dithering algorithm 1, slow, not tri-tone)
_yodither1tritone.py (Yliluoma's dithering algorithm 1, tri-tone)
_yodither3.py (Yliluoma's dithering algorithm 3)
_yodither4.py (adobe like algorithm)
動作には、Pillow、tqdm が必要。
スクリプトの使い方は以下。
一応ヘルプも載せておきます。
コマンドラインオプションに --mp をつければ並列処理(マルチプロセス)が有効になる。
_Arbitrary-palette positional dithering algorithm
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
あまりに処理時間がかかり過ぎるので、並列処理(マルチプロセス)も使えるように修正してみた。
動作確認環境は、Windows10 x64 21H2 + Python 3.9.13 + Pillow 9.1.1 + tqdm 4.64.0。
ソースは以下。
_yodither1.py (Yliluoma's dithering algorithm 1, slow, not tri-tone)
_yodither1tritone.py (Yliluoma's dithering algorithm 1, tri-tone)
_yodither3.py (Yliluoma's dithering algorithm 3)
_yodither4.py (adobe like algorithm)
動作には、Pillow、tqdm が必要。
pip install Pillow -U pip install tqdm -U
スクリプトの使い方は以下。
python yodither1.py -i input.png -o out.png --mp python yodither1tritone.py -i input.png -o out.png --mp python yodither3.py -i input.png -o out.png --mp python yodither4.py -i input.png -o out.png --mp
一応ヘルプも載せておきます。
> py yodither1.py --help usage: yodither1.py [-h] -i INPUT -o OUTPUT [-p PALETTE] [-d DITHER] [--mp] Yliluoma ordered dithering 1 optional arguments: -h, --help show this help message and exit -i INPUT, --input INPUT Input png filename -o OUTPUT, --output OUTPUT Output png filename -p PALETTE, --palette PALETTE Palette file (.png or .gpl) -d DITHER, --dither DITHER Dither type 2,4,8 (2x2,4x4,8x8). default: 8 --mp Enable multi process
コマンドラインオプションに --mp をつければ並列処理(マルチプロセス)が有効になる。
◎ 処理時間を実測。 :
CPU : AMD Ryzen 5 5600X (6コア12スレッド、3.7 - 4.6GHz) 上で、289 x 176 ドットの画像を変換して動作確認してみた。
ということで、並列処理にすることで速くなる場合と、遅くなる場合があると分かった。でもまあ、8分近くかかってた処理が2分で終わるようになった点はありがたい。
1ドット単位の計算をする際に並列処理を使ってしまったので、すぐに結果が得られるアルゴリズムの場合は、並列処理をするための下準備のほうがネックになってしまったのだろうけど。これがもし、1ラインずつ処理する形で並列処理を使っていたら、どのスクリプトでも効果が得られたのではないか、という気もする。
ただ、どのみち Python では、この手の処理は遅すぎてアレだなと…。
Script name | --mp (multi process) | Time |
---|---|---|
yodither1.py | off | 07:41 |
yodither1.py | on | 02:11 |
yodither1tritone.py | off | 02:36 |
yodither1tritone.py | on | 01:11 |
yodither3.py | off | 00:39 |
yodither3.py | on | 00:53 |
yodither4.py | off | 00:30 |
yodither4.py | on | 00:49 |
- yodither1.py, yodither1tritone.py は並列処理にすることで速くなった。
- yodither3.py, yodither4.py は並列処理にしたらむしろ遅くなった。
ということで、並列処理にすることで速くなる場合と、遅くなる場合があると分かった。でもまあ、8分近くかかってた処理が2分で終わるようになった点はありがたい。
1ドット単位の計算をする際に並列処理を使ってしまったので、すぐに結果が得られるアルゴリズムの場合は、並列処理をするための下準備のほうがネックになってしまったのだろうけど。これがもし、1ラインずつ処理する形で並列処理を使っていたら、どのスクリプトでも効果が得られたのではないか、という気もする。
ただ、どのみち Python では、この手の処理は遅すぎてアレだなと…。
◎ 余談。 :
以前作成したスクリプトと生成画像が違ってしまって悩んでいたのだけど、以前作成したスクリプト内で、r2, g2, b2 と書くべきところを r2, b2, g2 と書いてしまっていたのが原因だった。以前のスクリプトの生成画像のほうが間違っていた…。
一応、修正して、Gist にアップロードし直しておいた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
一応、修正して、Gist にアップロードし直しておいた。
_Yliluoma's ordered dithering algorithm 1, 2, 3. Python version.
[ ツッコむ ]
以上、13 日分です。