本日の Python勉強

どのようにオブジェクトを下位関数に渡すか悩みました まず JPEG Tagの定義ファイル defTag.pyです

# defTag.py

jpegTag = {
    'TAG': '0xFF',
    'DHT': '0xFFC4',
    'SOI': '0xFFD8',
    'EOI': '0xFFD9',
    'SOF': '0xFFC3',
    'SOS': '0xFFDA'

}

if __name__ == '__main__':
    print(jpegTag)
    print(jpegTag['TAG'], jpegTag['DHT'])

つぎに、これを読み込んで JPEG Tagの DHT, SOI, EOIアドレスを探すルーチンです searchJPEGTAGS.pyです

import sys
from bitstring import ConstBitStream
from defTag import jpegTag

def searchDHTs(file_obj):
    DHTs = list(file_obj.findall(jpegTag['DHT'], bytealigned=True))
    return DHTs

def searchSOIs(file_obj):
    SOIs = list(file_obj.findall(jpegTag['SOI'], bytealigned=True))
    return SOIs

def searchEOIs(file_obj):
    EOIs = list(file_obj.findall(jpegTag['EOI'], bytealigned=True))
    return EOIs

if __name__ == '__main__':
    xa = ConstBitStream(filename=sys.argv[1])
    print(searchDHTs(xa))
    print(searchSOIs(xa))
    print(searchEOIs(xa))

そして、ここに file objectを渡す上位ルーチンです ファイル名は test_searchJPEGTAGS.py です

from searchJPEGTAGS import searchDHTs, searchSOIs, searchEOIs
import sys
from bitstring import ConstBitStream

xa = ConstBitStream(filename='XA1.dcm')
print(searchDHTs(xa))
print(searchSOIs(xa))
print(searchEOIs(xa))

これを走らせると結果は 以下のようになります

[10352, 5398688, 6469600, 11807904, 17146912, 22482576, 27843824, 33224096, 38652544, 44104704, 49597104, 55103072, 60640800, 66181296, 71753056, 77315744, 82880880, 88431792, 93978432, 99509264, 105038752, 110572944, 116110208, 121646512, 127184304, 132726336, 138267056, 143811248]
[10336, 5398672, 6469584, 11807888, 17146896, 22482560, 27843808, 33224080, 38652528, 44104688, 49597088, 55103056, 60640784, 66181280, 71753040, 77315728, 82880864, 88431776, 93978416, 99509248, 105038736, 110572928, 116110192, 121646496, 127184288, 132726320, 138267040, 143811232]
[5398584, 6469504, 11807800, 17146808, 22482472, 27843728, 33224000, 38652440, 44104600, 49597008, 55102976, 60640696, 66181200, 71752952, 77315648, 82880776, 88431688, 93978328, 99509160, 105038656, 110572840, 116110104, 121646408, 127184208, 132726232, 138266952, 143811152, 149355088]

要するに XA1.dcmという DICOM XAファイルの中の JPEG Tagアドレスが検出されたのです もちろん XA fileのフレーム数分あります

Python関数引数に関する考察

どうしても訳が分からないことがありました 要するに Pythonでの関数の名前空間が分かっていなかったのです 特にリストを引数で渡す場合です ここには、「リストの場合関数内部でグローバル変数を変化させれば、関数から出てもその変化は引き継がれる」というように記載されています

ところがこのテストプログラムではそのようにならないのです

from bitstring import ConstBitStream
from defTag import jpegTag

DHTs = []
print("DHTs: {}".format(id(DHTs))) #A

def searchTags(DHTs):
    xa = ConstBitStream(filename='xa1.dcm') #B
    print("DHTs: {}".format(id(DHTs)))
    DHTs = list(xa.findall(jpegTag['DHT'], bytealigned=True))
    print("DHTs: {}".format(id(DHTs))) #C


if __name__ == '__main__':
    searchTags(DHTs)
    print("DHTs = {0}".format(DHTs))

この場合、出力はA, B, Cの値(アドレス)が出力され、最後に゜カラリスト[]が出力されます そして興味深いことには A == Bであるにもかかわらず B != Cなのです つまり関数内で新たに変数が作成された訳です これは意図する動作ではありません そこで調べるとここに詳細に記載がありました これによれば、関数内で変数に変更を行えば、関数内の変数とグローバル空間の変数は同じアドレスを参照するようです そこで以下のテストを書きました

from bitstring import ConstBitStream
from defTag import jpegTag

DHTs = []
print("#A: {}".format(id(DHTs))) #A

def searchTags(DHTs):
    xa = ConstBitStream(filename='xa1.dcm')
    print("#B: {}".format(id(DHTs))) #B
    DHTs.extend(list(xa.findall(jpegTag['DHT'], bytealigned=True)))
    print("#C: {}".format(id(DHTs))) #C


if __name__ == '__main__':
    searchTags(DHTs)
    print("DHTs = {0}".format(DHTs))

これで走らせてみると当方での出力は以下の通りでした

#A: 4441990408
#B: 4441990408
#C: 4441990408
DHTs = [10352, 5398688, 6469600, 11807904, 17146912, 22482576, 27843824, 33224096, 38652544, 44104704, 49597104, 55103072, 60640800, 66181296, 71753056, 77315744, 82880880, 88431792, 93978432, 99509264, 105038752, 110572944, 116110208, 121646512, 127184304, 132726336, 138267056, 143811248]

これで意図した通りとなりました 要するに関数内で値を受け渡したいリストに変更を加えることにより関数内変数とグローバル変数が同じアドレスを参照したことにより参照渡しが実現された訳です

やったあ

Pythonで DICOM XAに挑む編です

XA fileは動画シネ(シネには限らず USなんかもですが・・・)をコマ(= Frame)毎にパラパラ漫画のように連続して記録してあります

そして、それぞれの Frameは Huffman Code圧縮されていて、その圧縮のキーはそれぞれの Frame毎に設定されています これは圧縮効率を最大にするためなのです

そこで、これを解読するためには、Frame毎に設定されている Huffman定義テーブル = Define Huffman Table (DHT)を検出し、フレーム毎に分離する必要があります

このため、まず行っていることはフレーム毎に分離するため、DHTを検出することです これをやってみました

from defTag import jpegTag
from bitstring import ConstBitStream
from defTag import jpegTag
DHT_address = []

xa = ConstBitStream(filename='xa1.dcm')
print(list(xa.findall(jpegTag['DHT'], bytealigned=True)))

これで以下のようなリストが出力されました

10352, 5398688, 6469600, 11807904, 17146912, 22482576, 27843824, 33224096, 38652544, 44104704, 49597104, 55103072, 60640800, 66181296, 71753056, 77315744, 82880880, 88431792, 93978432, 99509264, 105038752, 110572944, 116110208, 121646512, 127184304, 132726336, 138267056, 143811248]

これは xa1.dcmという DICOM XA fileの中の DHTの位置を表していることになります これを用いて Frame毎にファイルを切り分けて暗号解読すれば良いということになりますね

ちなみに、defTag.pyは以下のように定義しました

jpegTag = {
    'TAG': '0xFF',
    'DHT': '0xFFC4',
    'SOI': '0xFFD8',
    'EOI': '0xFFD9',
    'SOF': '0xFFC3',
    'SOS': '0xFFDA'

}

if __name__ == '__main__':
    print(jpegTag)
    print(jpegTag['TAG'], jpegTag['DHT'])

何事もうまくいかないな

昨日はプックスペース栄和堂に行ってゆったりとした時間を過ごすつもりでした それで丁度 12:00頃 Cross Bikeで病院を出発し向かいました

そして店の前の自転車スペースで自転車に鍵をしてさあドアを開けようとすると何と Closedとなっていたのです

仕方なく諦め、自宅を通り過ぎて坂道の途中にあるのを認識していた別の Cafeに向かったのです 結構きつい坂道で、Cross Bikeのギアを思い切り lowにしたのですがその途端にチェーンが外れ、そのまま前ギアに挟み込み、いくら手で戻そうとしても戻りません 仕方なく、自転車を転がしながら自宅にトボトボと歩いて自転車を押して帰りました

そして自宅でドライバーなどを用いて何とか復旧しようとしたのですががっちりとギアにチェーンが挟まれ 何ともできず、修理に出さねばならない事態に陥りました この Cross Bikeは先日定期点検から戻ってきたばかりで、何となくギアに音がして、しかもチェーンの張りが問題ありそうでした 案の定こんなことになってしまいました

結果的に土曜日午後優雅にカフェで思索に耽る、その予定が全部駄目となりました 本当にこの世の中は思うようには行きません

それで、朝から MacBook Proで PyCharmを立ち上げ色々と設定していたのですが、内蔵する Terminal Windowを開くとどうも文字コードの関係なのでしょうか うまいこと動作しません 色々と探してみるとこのページに遭遇しました その通りに設定してみるとスイスイとターミナルが動作するようになりました ありがたい まあ思いどおりに行かないこともあれば 何とな解決することもありますね めげない めげない

こんなことも知らなかった

Ron先生に刺激され、少しというか一ヶ月間ぐらいサボっていた Pythonのプログラミングに本日取り組みました 朝から外来診療し、その後PCIでしたが、PCIは若者に任せ自分は Pythonでした

ツールは PyCharmと、VisualStudio Codeです なかなか VisualStudio Codeが使い勝手が良いです

  • やりたいこと
    • jpeg tagを使いまわしできるように一つのファイルにまとめ、使用する時に importする
  • ファイル1 = defineTag.py
    • これは importされるファイルであり、ここにjpeg tag定義をまとめる
  • ファイル2 = test_defineTag.py
    • これがメイン・ルーチンでありここから importする
# defineTag.py

jpegTag {
    'TAG': 0xFF,
    'DHT': 0xC4,
    'SOI': 0xD8,
    'EOI': 0xD9,
    'SOF': 0xC3,
    'SOS': 0xDA
}

if __name__ == '__main__':
    print(jpegTag)
    print(jpegTag['TAG'])

そしてこれを呼び出すメインです

#test_defineTag.py


from defTag import jpegTag

print(jpegTag)
print(jpegTag['TAG'])

これをターミナルから呼び出します

$ python test_defTag.py

そうすると、以下のように応答されます

{'TAG': 255, 'DHT': 196, 'SOI': 216, 'EOI': 217, 'SOF': 195, 'SOS': 218}
255

これで使いたい時に、jpegTagを呼び出せば良いということになります ここまで来るのに数時間必要でした

ヘロヘロと光明

昨日はミヤンマー そして札幌でのTAVI 3例に引き続き、早朝から W治療を 4例実施、その間に外来診療をしながらです そして懸案の重症大動脈弁狭窄症の患者さんに対してどのように対処するか 議論の後、治療に踏み切りました

とても重症で併存疾患もありかつ救急で運び込まれてきた患者さんです 心臓血管外科、循環器内科、麻酔科、血管外科、看護師さん、技師さん、コーディネーター皆総出で 19:00から 23:00まで頑張りました

それから遅くに自宅に帰宅、一人で夕食食べながら MacBook Proを立ち上げメールを見ていたところ、Ron先生からのメールを受信、懸案の DICOM moduleなどを用いて 非圧縮DICOM XAを動画展開できそう、とのプログラムでした

素晴らしいです 漠然としていたモヤの中の色々が見えてきそうです これまでの 圧縮DICOM画像の解析と併せてもっと前に進めていければ良いですね それでこそ Pythonを勉強している甲斐があります

そして今朝は辛かったけど頑張って出勤です

今朝のツーリング

わーあいっ こんなの見つけたー

TAVIからPCIへの移行休み時間でダラダラしています その間に何とこんなの見つけました 何と奇特な方がおられるのでしょうか 感謝 感謝 感謝です

Versionだって 3.6対応だし Web上に書かれているのでどんどん upgradeされるのです ありがたい話です それは Pythonのテキスト なのです

素晴らしいですねえ

Dive in Python

ついに思い切って参加しました しかも今回は会場が東京駅前の理研です 理研の AIPセンターです ちなみに AIPは何か?と言えば、「革新知能統合研究センター」のことで、AIP = Advanced Intelligence Projectのことだそうです

Stapy x 理研AIP

今回の研究会の中心は OSS (Open Source Software) = 基本的にソースコードを GitHubなどでインターネット上に公開しながら有志がインターネットで参加してし協同で優れたソフトを早く開発していくというもの このOSSの代表作が Linuxであり、また それこそ 統計ソフトRもそうですし、多数存在します

今日の開催場所理研 AIPというのは、東京駅八重洲口歩いて数分の場所に存在する巨大な奇麗で新しいビルの15階にあります 流石東京だと思わせるビルです

Coredo日本橋ビル

内容は OSSとして開発されているPandasという Pythonの数値計算の有名なライブラリに日本人として唯一開発に参加されている方の講演とか、日本で開発され、全世界に広がっている深層学習のためのPython Frameworkである CHAINERの開発に参画されている方の講演、そして Scikit-Learnによる Pythonでの機械学習のお話、そして理研の教授であられる先生による講演などとても難しいお話が並びました

本日のスタッフ

結局全てが終了したのは 9:15pm頃であり、全く休憩無しでした 終了し、すぐに消え去ろうとしたところ、懇親会(ビアバッシュ)入り口で「齋藤先生」と突然声をかけられました えっ えっ 何とこの StaPyの毎回の研究会運営の中心であられる岸さまでした

そして驚くことに、何と岸さんは EP班の村上部長の義理のお兄さんだったのです いやあ驚きました 世の中広いようで狭いのですねえ

もうすぐ開始です

東京駅より日本橋に向けて歩いて 10分 Credoと大きくビルに書かれた 19階建ての新しい大きなビル 上の方には Bank of Americaとか Merill-Lynchとか大きな文字がかかれていて「何だこれはアメリカの銀行集団ビルか?」と思える様相です

何れにしてもそこの 15階、これが一般の人々は 5階までしか上がれない構造なのですが、その入口を探すのも一苦労でした その 15階に理研の「革新知能統合研究センター」というのがあり、そこに天才たちがどうやら集まっており、集会室らしき壁の黒板には多分議論した跡なのでしょうか 理解不可能な複雑な数式が並んでいました

理研での Python勉強会

その中の広い会議室 これがスクール形式で僕は楽ちんな机がある席の前から二列目に座席を確保したのです もうすぐはじまるでしょう 参加者の会話を聴いていると「京都から新幹線で今ついた」とか言っておられる方もいらっしゃります 身なりは登山する人みたいです まあ僕ひどく汚い身なりですから人のことは言えません 楽しみです

さあ出発

今朝は朝からたくさんの外来患者さんを診察し、たくさんの入院オーダーも切りました お一人PCIをやることになっていましたが、今日はこれからの勉強会に出席せねばならない(正確には したい)ため、部下に任せて自転車でまず早めに自宅に戻りました

EuroPCR2017最初のライブ Main Arenaで

そして、自宅からバス停まで歩き、なかなか来ないバスをひたすら待ち、ようやく大船駅から 17:39発の東海道線に乗り、今電車で東京駅増まで向かっています これから 理研の賢い先生方による Python関連の講義を受けるため日本橋にあるという理研AIPというところに出かけるのです

楽しみだなあ