我正在尝试阅读一个简单的dicom文件名为" CR-MONO1-10-chest"来自http://www.barre.nom.fr/medical/samples/,这是一张440x440大小的图像。
如http://www.dclunie.com/medical-image-faq/html/part1.html所示,图像数据位于文件的末尾:
换句话说,如果图像是256×256,未压缩,则为12-16 位深(因此通常,但不总是,存储为两个字节 每个像素),然后我们都知道该文件将包含 256 * 256 * 2 =文件末尾的131072字节像素数据。如果 文件是145408字节长,因为所有GE Signa 3X / 4X文件都是 例如,在到达之前,您需要跳过14336字节的标题 数据。从左上角的光栅开始逐行设定 顺序,尝试两种替代字节顺序,处理16到8位 窗口问题,很快就会在屏幕上显示您的图像 你的工作站。
http://people.cas.sc.edu/rorden/dicom/index.html上的数字也显示图像数据位于文件的末尾。
我正在使用以下代码来读取和显示此文件中的图像:
(define in (open-input-file "CR-MONO1-10-chest" #:mode 'binary))
(define size (* 2 440 440)) ; width and ht are 440
(define ignore (read-bytes (- 387976 size) in)) ; size of file is 387976
(define imgdata (read-bytes size in))
(close-input-port in)
(define img (make-object bitmap% imgdata 440 440))
img
但是,它只显示黑白像素的随机混合:
使用440 * 440而不是2 * 440 * 440也不起作用。
以下代码也不会读取图片:
(define img (make-object bitmap% in 'unknown))
这根本不显示任何图像。
问题在哪里,我该如何解决?
答案 0 :(得分:3)
您正在正确计算图像数据偏移,此数据似乎是原始和未压缩的。问题似乎只是Racket不支持这种图像数据。这是16位单通道强度数据。每两个字节代表一个灰度级的像素(实际上,对于该图像,只使用10位,其他6位应该被忽略)。
make-object
make-bitmap
函数似乎仅支持颜色(24或32)或单色(1)位深度。这就是你的例子中跳出来的东西:当你创建位图时,你没有说明像素是16位。还缺少有关字节顺序的任何内容。并且在Racket文档中没有任何地方显示它允许您指定其中任何一个。
在获取深度函数documentation中似乎缺乏对16位灰度数据的支持:
(发送位图get-depth)→exact-nonnegative-integer? 获取位图的颜色深度,为单色位图为1 和32为彩色位图。另见is-color?。
这是一个解决方案,循环并将每个16位像素转换为ARGB像素。
#lang racket/gui
(define in (open-input-file "CR-MONO1-10-chest" #:mode 'binary))
(define size (* 2 440 440)) ; width and ht are 440
(define ignore (read-bytes (- 387976 size) in)) ; size of file is 387976
(define imgdata (read-bytes size in))
(close-input-port in)
(define rgbdata (make-bytes (* 4 440 440)))
(define img (make-object bitmap% 440 440))
(define max 1024.0) ; 10 bits valid
(for ([y 440])
(for ([x 440])
(define index (+ (* y 440) x))
(define b1 (bytes-ref imgdata (+ (* index 2) 0))) ; first byte
(define b2 (arithmetic-shift (bytes-ref imgdata (+ (* index 2) 1)) 8)) ; second byte
(define val (bitwise-xor b1 b2)) ; combine bytes
(define screenval (exact-floor (* 255 (/ val max)))) ; convert to 8-bit screen value
; create ARGB pixel
(define b (bytes (bytes-ref (make-bytes 1 255) 0) (bytes-ref (make-bytes 1 screenval) 0) (bytes-ref (make-bytes 1 screenval) 0) (bytes-ref (make-bytes 1 screenval) 0)))
(send img set-argb-pixels x y 1 1 b)
))
img
产:
但请注意:请注意,图像数据可以存储在DICOM文件中的方式有很多种(您链接的页面上有一些很好的例子)。并且您需要注意DICOM标头的许多部分以正确解码图像数据。
答案 1 :(得分:3)
问题是Racket绘图库无法识别图像编码。我建议将其转换为32位ARGB:
(require racket/draw)
(define (dicom->bitmap path x y)
(let* ([bmp (make-object bitmap% x y)]
[dc (send bmp make-dc)]
[dicom (file->bytes path #:mode 'binary)]
[header-size (- (file-size path) (* 2 x y))]
[dicom-img/raw (subbytes dicom header-size)]
[dicom-img/argb (dicom-img->argb dicom-img/raw)])
(send dc set-argb-pixels 0 0 x y dicom-img/argb)
(send dc get-bitmap)))
(define (dicom-img->argb bytes)
(let* ([len (bytes-length bytes)]
[pixel-count (/ len 2)]
[argb (make-bytes (* 4 pixel-count))])
(define (set-pixel! value ix)
(let ([offset (* 4 ix)])
(bytes-set! argb offset 0)
(bytes-set! argb (+ 1 offset) value)
(bytes-set! argb (+ 2 offset) value)
(bytes-set! argb (+ 3 offset) value)))
(for ([ix (in-range pixel-count)])
(let* ([offset (* 2 ix)]
[pixel-value (+ (bytes-ref bytes offset)
(arithmetic-shift (bytes-ref bytes (+ 1 offset)) 8))]
[scaled-value (arithmetic-shift pixel-value -2)])
(set-pixel! scaled-value ix)))
argb))
然后你可以这样称呼它:
(dicom->bitmap "CR-MONO1-10-chest" 440 440)
此特定程序仅适用于以小端顺序存储在2个字节中的10位/像素,但只需稍加努力就可以将其参数化以用于其他编码。
如果你有一个包含该格式的多个图像的文件,最后,该程序应该能够将它们作为位图列表提取出来。
(require racket/draw)
(define (dicom->bitmap* path x y z)
(let* ([dicom (file->bytes path #:mode 'binary)]
[img-size (* 2 x y z)]
[header-size (- (file-size path) img-size)]
[dicom-img/raw* (for/list ([z^ (in-range z)])
(let* ([offset (+ header-size (* z^ img-size))]
[img-bytes (subbytes dicom offset (+ offset img-size))])
img-bytes))])
(map (λ (raw) (raw->bitmap raw x y)) dicom-img/raw*)))
(define (raw->bitmap bytes x y)
(let* ([bmp (make-object bitmap% x y)]
[drawing-context (send bmp make-dc)]
[dicom-img/argb (raw->argb bytes)])
(send drawing-context set-argb-pixels 0 0 x y dicom-img/argb)
(send drawing-context get-bitmap)))
(define (raw->argb bytes)
(let* ([len (bytes-length bytes)]
[pixel-count (/ len 2)]
[argb (make-bytes (* 4 pixel-count))])
(define (set-pixel! value ix)
(let ([offset (* 4 ix)])
(bytes-set! argb offset 0)
(bytes-set! argb (+ 1 offset) value)
(bytes-set! argb (+ 2 offset) value)
(bytes-set! argb (+ 3 offset) value)))
(for ([ix (in-range pixel-count)])
(let* ([offset (* 2 ix)]
[pixel-value (+ (bytes-ref bytes offset)
(arithmetic-shift (bytes-ref bytes (+ 1 offset)) 8))]
[scaled-value (arithmetic-shift pixel-value -2)])
(set-pixel! scaled-value ix)))
argb))
其中z是图像的数量。我只能用z = 1来测试它:(dicom->bitmap* "CR-MONO1-10-chest" 440 440 1)