DICOM XAという深遠にして難解なる世界への手がかり
DICOM-XAという動画フォーマットは、医療画像診断分野において1997年頃より全世界の医療現場・研究において用いられてきたものです。このDICOMフォーマットの制定により、全世界で統一されたフォーマットで画像情報を正確に伝達・保存が可能となったのです。しかしながら、その動画フォーマットであるDICOM-XAというものは、難解なデータ構造を持っています。
齋藤 滋は、2010年頃に、C/C++プログラミングの勉強のために自身でその動画再生プログラムを作成することを決意しました。しかし、それは困難と苦痛に満ちた試みでした。DICOM-XAは静止画のフォーマットである JPEGに基づいています。そして JPEGというフォーマットの根源にあるのは、ハフマン符号化というデータ欠損の無い圧縮です。なぜ、DICOM-XAが難解であるか? と問われれば、その多くは、肝腎のHuffmannフォーマットに関する明確な記述が JPEG仕様書にしか存在しないからであり、その JPEG独特の符号化をプログラミング言語で記載したものの解説は世の中にほとんど存在しないからでした。このような荒波の中、DICOM-XAの解読プログラム(=動画再生プログラム)を自分自身でフル・スクラッチで書くことに私は挑戦しまた。ここに、この齋藤 滋自身が歩んできた困難に満ちた長い戦いの記録を残します。
今新幹線で大垣あたり移動中 – C++で二進出力を可能とするクラス
2012年9月14日
本日はこれから兵庫医科大学病院に行き、AIM-TRIというカナダのケベックで開催されている学会に、同院よりライブを飛ばします。舛谷先生、松陰先生、そして吉町先生と一緒なので気が楽です。新幹線の中では相変わらず C++を用いて DICOM XA関係のプログラムを書いて、そしてコンパイルして、そしてrunして試しています。
その過程でかつて書いた部品プログラムを幾つか改良しつつあります。デバッグ用に重宝しているのが、二進出力用のクラスなのです。以前も紹介しましたが、それを書いた時には、何と愚かにも整数型int というのは16 bitsと思い込んでいたのです。ですから、int型の値を二進出力しても16桁しか出力しませんでした。何でこんな思い込みをしていたのか? と言いますと、僕がプログラミングの世界に入ったのは、何と1978年頃なのです。当時 Intel 8080/8085とか、Zilog Z-80といった 8-bits CPUの世界であり、そのCPUをボードに2KBぐらいの少ないメモリー、クロック回路、それに4桁のLCDそして簡単なインターフェースを一つの配線ボードに載せた「ワンボード・コンピューター」というのがそうですね、当時の価格で15万円ぐらいで売り出され、メカの好きな人たちには絶大な人気だったのです。「トレーニング・キット」とも言いました。
最もポピュラーだったのは、NECが発売していてIntel 8085を載せていた TK-80というトレーニング・キットでしたが、僕が購入したのは、Sharpが発売していたMBS80Kとかいうトレーニング・キットで、Z-80が載っていました。何しろ僕のプログラミングはそこに始まりました。ですから、当然キーボードなど無く、16 Keyのパッドのみですから、プログラムの入力は、全て機械語で16進入力するのです。それから暫くすると、世の中に「マイコン」つまりMy Computerを短くしたものですが、それが出てきて、僕はすぐに Sharpの MZ80というベストセラーのマイコンに移行しました。
これは、ディスプレー(といっても、たかだか80 x 40文字しか出ない)と、フル・キーボード、そして外部記憶としてカセット・テープがついていたのです。その上では、BASIC言語、Assembler言語、Pascalなどが走り、そのような「高級言語」でプログラムを書いて楽しむことができました。ものすごい進歩!!!
当時は CPUが 8bitsでしたし、次に出てきた8086といった世間を席巻したCPUは 16 bitsでしたので、整数型 intというのは2 bytes用いた 16 bitsというのが世間の常識でした。その頃の記憶が体に染みついているのですね。
何はともあれ、現在は 32 bits or 64 bits CPUが主流ですので、何時の頃からか世間の常識は 整数型 intは 32 bitsというのが当たり前となっているのです。何しろ16 bitsでは 0から 65535までの数しか表せませんが、32 bitsでは 0から何と 4294967295という巨大な数まで表すことができます。すっ、すっ、すっごーーーいっ!!
ということで、これまで16 bitsで書いていた二進出力を修正したのです。まずは ヘッダ部分です:
#ifndef __OSTREAM_H_ #define __OSTREAM_H_ // 二進出力を可能とした ostream (Programmedd by Shigeru SAITO, MD on June 5th, 2009) // modified by S. SAITO, MD on December 14th, 2010 // 使い方: このheader fileをインクルードし、名前空間ostを用いてcoutに出力する // ost::ostream cout; とcoutを生成し、 // cout << value; // のように使う、そして標準出力については std::cout << std::endl; のようにする // 入力の型(BYTE, WORD, int)に応じて自動的に8桁、16桁で出力するがsetw()で出力桁数を変更できる // modified on Sepptember 14th, 2012 (hex出力の大文字化および32 bits, 16 bitsのint型に対応) // #include <iostream> #include <iomanip> #include <string> typedef unsigned char BYTE; typedef unsigned short WORD; namespace ost { enum e_manip {bin, hex, dec, endl}; class setw { int width_; setw() {} // 引数無しコンストラクタ禁止 public: setw(int n); int get_width(void) const; }; class ostream { private: int width, bitWidth; e_manip mManip; bool mIsSetW; void setWidth(int w); void out(int n); public: ostream(); ostream & operator << (const setw & sw); ostream & operator << (const e_manip em); ostream & operator << (const BYTE n); ostream & operator << (const WORD n); ostream & operator << (const int n); ostream & operator << (const char* s); ostream & operator << (const std::string str); }; }; // namespace ost #endif __OSTREAM_H_
そして次はコードです:
#include "ostream.h" #include "stdafx.h" namespace ost { setw::setw(int n): width_(n) { if (width_ < 1) width_ = 1; if ((sizeof n == 4)&&(width_ > 32)) width_ = 32; if ((sizeof n == 2)&&(width_ > 16)) width_ = 16; } int setw::get_width(void) const { return width_; } void ostream::out(int n) { int printWidth = 0; mIsSetW ? (printWidth = width): (printWidth = bitWidth); switch (mManip) { case bin: for (int i = printWidth; i > 0; --i) { std::cout << (((n >> (i - 1)) & 0x00000001) ? '1': '0'); if ((i != 8) && ((i - 1)%4 == 0)) std::cout << " "; } break; case hex: std::cout << "0x" << std::hex << std::uppercase << std::setw(printWidth); std::cout << std::setfill('0') << n; std::cout << " "; break; case dec: std::cout << std::dec << std::setw(printWidth) << std::setfill('0') << n; break; default: break; } } ostream::ostream(): width(1), bitWidth(8), mManip(bin), mIsSetW(false) {} ostream& ostream::operator << (const setw & sw) { width = sw.get_width(); mIsSetW = true; return *this; } ostream& ostream::operator << (const e_manip em) { if (em == endl) { std::cout << std::endl; } else { mManip = em; } mIsSetW = false; return *this; } ostream & ostream::operator << (const BYTE n) { switch (mManip) { case bin: bitWidth = 8; break; case hex: bitWidth = 2; break; case dec: bitWidth = 3; break; } out(static_cast<int>(n)); mIsSetW = false; return *this; } ostream & ostream::operator << (const WORD n) { switch (mManip) { case bin: bitWidth = 16; break; case hex: bitWidth = 4; break; case dec: bitWidth = 5; break; } out(static_cast<int>(n)); mIsSetW = false; return *this; } ostream & ostream::operator << (const int n) { switch (mManip) { case bin: if (sizeof n == 4) { bitWidth = 32; } if (sizeof n == 2) { bitWidth = 16; } break; case hex: bitWidth = 4; break; case dec: bitWidth = 5; break; } out(n); mIsSetW = false; return *this; } ostream & ostream::operator << (const char* s) { std::cout << s; mIsSetW = false; return *this; } ostream & ostream::operator << (const std::string str) { std::cout << str; mIsSetW = false; return *this; } } // namespace ost
使い方はどうするか?と言いますと 実際のコード例を示します:
#include "ostream.h" int main() { ost::ostream cout; // 二進出力クラスの実体化 int i = 1; -1という整数はどのように出力されるか? cout << "16進出力: " << ost::hex << i << ost::endl; cout << "2進出力: " << ost::bin << i << ost::endl; return 0; }
心臓病学会座長終了
2012年9月15日
無事 座長の仕事も終え、今サンダーバードで富山に向かっています。小牧からの便は満席だったので、富山から羽田に戻ります。
電車の中で大きな過ちに気付きました
typedef struct JPEGTAGTBL { BYTE *DHT; BYTE *SOI; };
としていたのですが、以下のように変数を宣言すると訳の分からないエラーが出るのです
typedef struct JPEGTAGTBL { BYTE *DHT; BYTE *SOI; } *jpegTagTbl;
どういうこと? と考えあぐね、やっとtypedefがいらないことに気付きました バカみたい
何じゃ これは!! — DICOM XA表示プログラム
2012年9月26日
さてさて遅々としてはいるものの確実に前に進んでいる DICOM XA表示用プログラムですが、この長い中南米PCI旅行の最中も暇を見つけてやっています。
やっと、MFC frameworkを用いて C++で一コマの絵を出すことに成功しましたが、いやいや決して成功していないのです。符号化のデコードがうまくいっていないのです。実際のDICOM XA fileを読み込み、10コマ目を表示したらばこんなになってしまいました。これからたくさんのステップがありますね。その道が楽しみです。
時差ボケ
2012年9月28日
時差ボケにより覚醒 2:30AMです。こんな時には本を読むに限ります。
と、いう訳で「JPEG 概念からC++による実装まで」をパラパラと読んでいます。この本は何回読んだことでしょう。そして常に持ち歩いているのです。内容は僕にとってはとても難しいのですが、C++の勉強にもなります。ほとんどの部分は読み飛ばししてきました。DICOM-XAには必要無い、と思っているからです。特に離散コサイン変換の部分は必要ありません。DICOM-XAでは「ロスレス」圧縮だからです。
こうして読み飛ばすことにより、重要なことも読み飛ばしていることに気付いたのです。それが
- スキャンセグメントの最初にはスキャンヘッダが存在する 従って SOS (Start of Scan)タグに引き続いての8 bytesは画像データではない
- DRI (Define Restart Interval) タグを確認することにより、ビット誤りを訂正するリスタート・インターバルの存在確認
- RSTm (Re-Start) タグをスキャン内で確認することにより、リスタートする部分があるか否かの確認
- スキャン内で、0xFFが存在する可能性があり、その場合、次に続くバイトが0xであれば、0xFF 0x00というバイト列の内の、0xFF部分を正当な値と見なし、0x00というバイトを読み飛ばさねばならない
これらの重大な事実に気付きました。そういう訳で、実際のDICOM-XA fileを binary editorで開き、2, 3について検証しました。 DRI = 0xFFDDですので、これがスキャン・インターバルの中に存在するかどうか調べたところ、ありません。念のため、RSTm (mはモジュロ8つまり、8で割った余りですから、0~7の整数です)の存在を調べました。RST0 = 0xFFD0、RST1 = 0xFFD1 ・・・・ ですので、それを検索しても存在しません。従って重大な事実として、DICOM-XAにはビット誤りに対するリスタートは存在しない、ということになります。
次に4について検証しました。ショックなことに、0xFF00というバイト列はスキャン・データ すなわち画像データ中に多数存在しました。今まで書いたプログラムでは、0xFF00というバイト列が来たとしても、そのままデータとして処理していましたので、これを修正せねばなりません。
さらに重要なのは、今まではスキャンヘッダの存在を全く無視していた、ということです。データでない部分から復号をしていたのです。もう無茶苦茶ですよね。どうりで SOS (0xFFDA)の後に、どのDICOM XA fileでも同じようなバイト列
0x00 0x08 0x01 0x01 0x00 0x01 0x00 0x00が存在していた訳です。疑問には思っていましたが、そのささやかな疑問を心の中で無視していたのです。
まあ何れにしてもこれで前に進めそうですね。
これらか重要なのです
ようやく時差ボケから復帰
2012年10月3日
先週木曜日夜に南米ペルーそして中米メキシコの長い旅より帰国し、金曜日には朝からTAVI、そしてそのまま仙台に入り、土曜日には東北厚生年金病院より、仙台PTCAネットワークライブデモンストレーションでの、PCIライブデモンストレーション治療、その後そのまま品川に舞い戻り、若い医師のために、Jons Hopkins大学 Resar先生、Changuang Memorial Hospital, Kaoshiungより Wu先生をお招きしての CrossRoads Institute Young Interventional Fellowship CourseにDirectorとして参加し日曜日まで、そして台風が来ました。
月曜日は夕方まで外来診療そして昨日火曜日は外来診療を夕方までした後、とっても難しいPCI一例と、それ以外に治験のPCIなど行いました。体が辛い状態が続きました
しかし、これでようやく時差ボケが解消されました。今朝は5:30AM起床し、今羽田空港ラウンジで、札幌行きの飛行機を待っています。夕方またリターンしてきます。
どうしてこんなに時間が無いのでしょうね。
懸案の DICOMプログラムは絵にしたところで、大きな暗礁に乗り上げてしまいました。どうしてもまともな絵が出てこないのです。どうしよう どうしよう
あああ すっかり壁に
2012年10月21日
DICOM XAプログラム すっかり壁にぶちあたっています
どうプログラム見直しても bit出力、ハフマン表解読、その他正しいと思われるのにまともな絵にならないのです。この状態で既に数週間経過
助け舟が必要ですが、なかなか踏み切れません
それにしても、一つがっかり Visual Studio 2010 Professionalにはどうやら C++に対するプロファイラがついていないらしいのです。UltimateやPremiumにはあるらしいのですが、これらは完全に業務用ソフト開発用なので、価格が70万円ぐらいするのです、とても手を出せるものではありません
まあ、まだプログラムも完成していないのにプロファイラもくそもありませんが・・・
自分の人生を賭けた戦い
013年7月17日
再び自分の人生を賭けた戦いに挑み始めました
去年も挑戦し、挫折したものです それは人生の最近何年も賭けているものです DICOM-XA Viewerプログラミングです
去年は随分といい線まで行ったのです、懸案の Huffman Decodingが作動し始めたのです、しかし、実際に画像を作成しても絵にならなかったのです それで挫折しかし、今再びその戦いの場に復帰しました これが人生で最後のチャンスかも知れません
そこで、以前のプログラムを出してきました いったいいつからこれをやっているのか? 驚きました何と少なくとも 2006年ベオグラードの時差ボケの中で書いたものがありました
それを掲載します
#ifndef __DIB32_H_ #define __DIB32_H_ // Dib32.h // This is a DIB class. // Written by S. Saito on April 14, 2006 in Belgrade. // This header file actually contains the source code itself also. // This DIB class must be created in the Constructor of the Document Class. // Also, it must be deleted in the Destructor of the Document Class. // A small bug was fixed on September 7th, 2012 (private members were not initialized). // class CDib32 //32 bits DIBクラス { private: LPBYTE lpDIB; // DIB全体へのPointer LPDWORD lpPixel; // 画像PixelへのPointer LPBITMAPINFO lpbiInfo; int sizex, sizey; // 画像Pixelのサイズ public: inline CDib32(void) // Default Constructor :lpDIB(NULL), lpPixel(NULL), lpbiInfo(NULL), sizex(0), sizey(0){ Resize(0, 0); } inline CDib32(int x, int y) { Resize (x, y); } inline BOOL SetDib32(int x, int y, COLORREF c) { // Set Pixel color if ((x<0)||(x>=sizex)) return FALSE; // BIT-OR was changed to LOGICAL-OR according to Dr. TAKAMURA if ((y<0)||(y>=sizey)) return FALSE; // BIT-OR was changed to LOGICAL-OR according to Dr. TAKAMURA // to speed up the evaluation. Also, '>'s were corrected to '>='. lpPixel[x + y*sizex] = c; return TRUE; } inline BOOL SetDib32Clip(int x, int y, COLORREF c) { // Set Pixel with already clipping // 既にクリッピングが保証されている lpPixel[x + y*sizex] = c; return TRUE; } inline COLORREF GetDib32(int x, int y) { // Get Pixel color COLORREF c; if (x<0) x = 0; if (y<0) y = 0; if (x>sizex) x = sizex-1; if (y>sizey) y = sizey-1; // the bug was fixed by introducing sizex-1 and sizey-1 // according to Dr. TAKAMURA on July 18, 2013 c = lpPixel[x + y*sizex]; return c; } inline COLORREF GetDib32Clip(int x, int y) { // Get Pixel color with already clipping // 既にクリッピングが保証されている return lpPixel[x + y*sizex]; } inline void Dib32Draw(CDC *pDC) { // Draw to DC Dib32Draw(pDC, 0, 0); } inline void Dib32Draw(CDC *pDC, int x, int y) { // Draw to DC with offset of (x, y) Dib32Draw(pDC, x, y, 1.0); } inline void Dib32Draw(CDC *pDC, int x, int y, float ratio) { // Draw to DC with offset of (x, y) // with the enlargement by r times. HDC hdc = pDC->GetSafeHdc(); StretchDIBits(hdc, x, y, static_cast<int>(sizex*ratio), static_cast<int>(sizey*ratio), 0, 0, sizex, sizey, lpPixel, lpbiInfo, DIB_RGB_COLORS, SRCCOPY); } inline void Dib32DrawR(CDC *pDC, int x, int y, float ratio) { // Draw to DC with reversed image HDC hdc = pDC->GetSafeHdc(); StretchDIBits(hdc, x, y, static_cast<int>(sizex*ratio), static_cast<int>(sizey*ratio), 0, 0, sizex, sizey, lpPixel, lpbiInfo, DIB_RGB_COLORS, SRCINVERT); } inline void Resize(int x, int y) { // Resize DIB and actually substantiate DIB sizex = x; sizey = y; if (lpDIB != NULL) { HeapFree(GetProcessHeap(), 0, lpDIB); } lpDIB = static_cast<LPBYTE>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFO) + x*y*4)); lpbiInfo = reinterpret_cast<LPBITMAPINFO>(lpDIB); lpPixel = reinterpret_cast<LPDWORD>(lpDIB + sizeof(BITMAPINFO)); lpbiInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); lpbiInfo->bmiHeader.biWidth = x; lpbiInfo->bmiHeader.biHeight = -y; lpbiInfo->bmiHeader.biPlanes = 1; lpbiInfo->bmiHeader.biBitCount = 32; lpbiInfo->bmiHeader.biCompression = BI_RGB; } inline LPDWORD GetPixelTop(void) { // get pointer to lpPixel return lpPixel; } public: ~CDib32(void) { HeapFree(GetProcessHeap(), 0, lpDIB); } }; #endif
やったあ ついにやったあ
2013年7月18日
月曜日から水曜日にかけてフランスに出かけ、経大動脈的大動脈弁植え込み術の実践トレーニングを受けてきました その怖さと素晴らしさの両極端を実際に体で体験してきました。濃密な素晴らしい体験でした
その合間を縫って、約一年ぶりに DICOM-XA viewerの作成に取り掛かりました とりかかる、と言ってもまずは一年前に仕上げたコードを再確認する作業です 何しろすっかり自分が何を考え、何をしてきたか それらを忘れていたからです 今回は、超強力な援軍がいて下さるのです 画像処理プログラミングのプロです その先生は全てご存じです しかし、先生からコードを頂く訳にはいきません それでは自分で理解できないからです
その一方で深刻な問題につきあたりました 僕自身 Windows上では画面に画像を出力することはできるようになっています これには、実は MFC (Microsoft Foundation Class)という C++のフレームワークを用いてプログラム書いています このフレームワークでは画面出力に Device Context (DC)という概念を用い、そこに書き込むことにより、画面に出力され、またマウス操作なども受け付けるのです これは非常に便利なのです、しかし、では Mac OSXあるいは Linuxに移行する時には問題です そんなフレームワークは無いからです
それで、どうやって OSX上で画像を作るか? それに悩みました 色々と調べ、どうやら X-window上の OpenGLというフレームワーク、さらにそれを使いやすくした GLUTというフレームワークを用いれば僕のようなアマでも何とかなる可能性があることが分かりました
そして、このページを参考にしました このページの通りにやったところ、Mac上にこのような画面が出力されたのです 感激です 超感激です
これからサンパウロ
2013年7月24日
今 羽田空港国際線ラウンジで 7/24 01:30AM発の EMIRATES航空 Dubai行きを待っています 既に日にちが変わりました
Dubaiで同じ Emirates航空に乗り継いで Sao Pauloに向かうのです このルートが日本とサンパウロを結ぶ最短のルートとなりますが 初めて使います
現地には2泊滞在し、 SOLACIという学会に参加し、色々な役割を終え、日曜日 7/28の夕方には成田空港に帰国することになっています。地球の裏側への往復としては最短の旅程でしょうね
この間、 DICOM-XA Viewerプログラムに大きな進展がありました。いくら考えても自分一人では解決できないので、ついに以前コンタクトさせて頂いたその道のプロの方に相談したのです そして、見事に僕の書いたプログラムの中に幾つかのバグを指摘して頂き、その方はきちんとした画像の生成に成功されたのです
頂いたヒントをこの旅行の往復の飛行機の中で解析し、自分のプログラムをきちんとしたものにするつもりです ようやく大きな目標に近づいてきたのです とてもうれしく思います
ついに絵が出た
2013年7月28日
ついについに DICOM-XAの一フレームを画像として出すことができました これまでの少なくとも 2006年から取り掛かってきた自分自身のプロジェクトがようやく実体化しつつあります
「DICOM-XAの Viewerを作ろう」と思い立ったのは、色々な理由がありました
- 我々からすれば謎の多い DICOM-XAを我々でも理解できるようにしたい そのためには自分自身でプログラムを書いて、てぎれば皆が理解し易いスクリプトで書き換え、それを公開したい
- 自分自身のC++の勉強のための題材としたい
- 自分自身何年かがかりの目標を持ちたい
- 自らの頭脳の限界に挑戦したい
それでも何回も何回も挫折したのです 色々な方々にご教授をお願いしました DICOM-XA Viewerを開発しておられるメーカーの方々にも質問を投げかけました しかし、何時も答えは曖昧なものでした そりゃあ彼らも必死で開発し、その心臓部のアルゴリズムは秘密にしたいと思います 仕方ありません
そんな中で ひょんなことで芝浦工業大学の先生方と知り合いとなり、T先生に核心的なヘルプを頂きました 流石に画像処理のプロ、僕が何年もかかっても解決できなかったことが、数日で解決しました でもただ言われるままにしているのではありません 自分で理解し、確認しながらの作業でした そして、サンパウロからドバイへの14時間の飛行機の中でついに絵が出ました 感激の瞬間でした これまでの少なくとも7年間に及ぶ苦労がやっと報われつつあるのです
でも、今後はパラパラ漫画にするために、タイマー割り込みをかけたり、動画とするためには色々な作業があります それがまた楽しみです さらには OSXにも移植したいと思います そして、それらの作業の中で理解を確実なものとして それを そうですねえ Visual Basicか、PHPあたりのスクリプト言語で書き直し、もちろんスピードの点で使い物にはならないでしょうが 公開したいと思います それではできた絵をここで初めて公開します
成田到着
2013年7月28日
長ーい長ーい飛行の末に成田に到着しました 長かったです しかもこの間 あまり睡眠とっていません 例の DICOM-XA画像化に興奮し、プログラムばかりしていました やはり日本は暑いですねえ 極寒のサンパウロとはものすごく違います
これから夢は DICOM-XAの動画表示 あるいはインターフェースの実装 あるいはOSXへの移植 色々と課題があります とても楽しみですね
深刻な問題
2013年7月29日
本日深刻な問題を知りました 僕は Macbook-Proを使い、OSX10.8の上に、Parallels Desktopを用いて Windows7を走らせ、普段はその Windows7上で仕事やプログラムを書いています
CD/DVD読み込みの設定が、OSX優先となっていたため、DICOM-CD/DVDを挿入すると、自動的に OSX上の Osirixが立ち上がりファイルを読み込み、Windows7側では読み込めなかったのです
そこで、そうやって OSX上に読み込まれた DICOM-XA fileを Desktopにコピーしました Desktopに関しては両方のOSから普通に読み書きできるからです また読み込んだファイルは XAですから binary dataということになりますので、当然ながら Windows7上の binary editorでも読み込める筈です
ところがところが VisualStudio 2010内臓のbinary editorで開きに行くと開けないのです!!! Binary editorで開けないファイルがこの世に存在するなんて信じられません ひっょとして、と思い、Google博士に聞いてみました そして、Parallelsを用いても Windows側で CD/DVDを読み込む方法を見つけました、そして Windows側でCD/DVDを開いてファイルを Desktopにコピーしたのです そうするとなんとなんと 今度は普通に Binary Editorで読み込めるのです
これってどういうこと? 同じDesktopに書き込んでいるのですから、少なくとも物理的ファイル・フォーマットの違いの問題ではありません なんかファイル・ヘッダーが違う関係で読み込めないのかなあ?
それぞれのOSの Binary Editorで開いてみて比較すればわかるのでしょうが・・・ こんなに深刻な問題につきあたるなんて想像していませんでした
実際問題として一度 CD/DVDから Osirixに読み込んでしまえば、それをDICOM-XAで書きだしたとしても、本当に Windows上の DICOM Viewerで読めるのかどうか という深刻な問題を投げかけています 誰か試してみないですか?