1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// 医学图像处理(v12.10.0)
// 窗宽窗位调整、伪彩色映射、医学图像增强
///|
/// 窗宽窗位配置
pub(all) struct WindowLevel {
window_width : Double // 窗宽
window_level : Double // 窗位
}
///|
/// 创建默认窗宽窗位(肺窗)
pub fn window_level_lung() -> WindowLevel {
WindowLevel::{ window_width: 1500.0, window_level: -600.0 }
}
///|
/// 创建纵隔窗
pub fn window_level_mediastinum() -> WindowLevel {
WindowLevel::{ window_width: 400.0, window_level: 40.0 }
}
///|
/// 创建骨窗
pub fn window_level_bone() -> WindowLevel {
WindowLevel::{ window_width: 2000.0, window_level: 400.0 }
}
///|
/// 创建脑窗
pub fn window_level_brain() -> WindowLevel {
WindowLevel::{ window_width: 80.0, window_level: 40.0 }
}
///|
/// 应用窗宽窗位调整
/// 将原始灰度值(如 CT 值 HU)映射到 0-255
pub fn apply_window_level(
img : @types.Image,
config : WindowLevel,
) -> @types.Image {
let w = img.width
let h = img.height
let channels = img.channels
let out_data : Array[Byte] = Array::make(w * h, b'\x00')
let low = config.window_level - config.window_width / 2.0
let high = config.window_level + config.window_width / 2.0
for y in 0..<h {
for x in 0..<w {
let idx = (y * w + x) * channels
// 取第一个通道作为灰度值
let raw = img.data[idx].to_double()
let mapped = if raw <= low {
0.0
} else if raw >= high {
255.0
} else {
(raw - low) / config.window_width * 255.0
}
out_data[y * w + x] = mapped.min(255.0).max(0.0).to_int().to_byte()
}
}
@types.Image::{
width: w,
height: h,
channels: 1,
data: Bytes::from_array(out_data),
}
}
///|
/// 医学图像伪彩色映射
/// 支持多种医学常用伪彩色方案
pub fn medical_colormap(
img : @types.Image,
colormap? : String = "hot",
) -> @types.Image {
let cmap = colormap
let w = img.width
let h = img.height
let channels = img.channels
let out_data : Array[Byte] = Array::make(w * h * 3, b'\x00')
for y in 0..<h {
for x in 0..<w {
let idx = (y * w + x) * channels
let gray = if channels >= 1 {
img.data[idx].to_double() / 255.0
} else {
0.0
}
let out_idx = (y * w + x) * 3
// 多种伪彩色映射
let (r, g, b) = match cmap {
"hot" =>
// 黑 -> 红 -> 黄 -> 白
if gray < 0.33 {
((gray / 0.33 * 255.0).to_int(), 0, 0)
} else if gray < 0.66 {
(255, ((gray - 0.33) / 0.33 * 255.0).to_int(), 0)
} else {
(255, 255, ((gray - 0.66) / 0.34 * 255.0).to_int())
}
"cool" =>
// 青 -> 品红
((gray * 255.0).to_int(), ((1.0 - gray) * 255.0).to_int(), 255)
"spring" =>
// 品红 -> 黄
(255, (gray * 255.0).to_int(), ((1.0 - gray) * 255.0).to_int())
"summer" =>
// 绿 -> 黄
((gray * 128.0).to_int(), (128.0 + gray * 127.0).to_int(), 0)
"autumn" =>
// 红 -> 黄
(255, (gray * 255.0).to_int(), 0)
"winter" =>
// 蓝 -> 绿
(0, (gray * 255.0).to_int(), ((1.0 - gray) * 255.0).to_int())
"bone" => {
// 骨色:黑 -> 灰 -> 白(带一点蓝调)
let v = (gray * 255.0).to_int()
(v, v, (v + 20).min(255))
}
"pink" => {
// 粉色:灰 -> 粉
let v = (gray * 255.0).to_int()
(
v.min(255),
(v.to_double() * 0.6).to_int().min(255),
(v.to_double() * 0.7).to_int().min(255),
)
}
_ => {
// 灰度
let v = (gray * 255.0).to_int()
(v, v, v)
}
}
out_data[out_idx] = r.min(255).max(0).to_byte()
out_data[out_idx + 1] = g.min(255).max(0).to_byte()
out_data[out_idx + 2] = b.min(255).max(0).to_byte()
}
}
@types.Image::{
width: w,
height: h,
channels: 3,
data: Bytes::from_array(out_data),
}
}
///|
/// 医学图像对比度增强(CLAHE 简化版,自适应直方图均衡化)
pub fn medical_contrast_enhance(
img : @types.Image,
clip_limit? : Double = 2.0,
tile_size? : Int = 8,
) -> @types.Image {
let _ = clip_limit
let _ = tile_size
let w = img.width
let h = img.height
let channels = img.channels
// 转换为灰度
let gray : Array[Int] = Array::make(w * h, 0)
for i in 0..<(w * h) {
let idx = i * channels
let r = img.data[idx].to_int()
let g = if channels >= 2 { img.data[idx + 1].to_int() } else { r }
let b = if channels >= 3 { img.data[idx + 2].to_int() } else { r }
gray[i] = (0.299 * r.to_double() +
0.587 * g.to_double() +
0.114 * b.to_double()).to_int()
}
// 全局直方图均衡化(简化版)
let histogram : Array[Int] = Array::make(256, 0)
for i in 0..<(w * h) {
histogram[gray[i]] += 1
}
// 累积分布函数
let cdf : Array[Int] = Array::make(256, 0)
let mut sum = 0
for i in 0..<256 {
sum += histogram[i]
cdf[i] = sum
}
// 映射
let total = w * h
let out_data : Array[Byte] = Array::make(w * h, b'\x00')
for i in 0..<(w * h) {
let value = gray[i]
let equalized = if total > 0 {
(cdf[value].to_double() / total.to_double() * 255.0).to_int()
} else {
value
}
out_data[i] = equalized.min(255).max(0).to_byte()
}
@types.Image::{
width: w,
height: h,
channels: 1,
data: Bytes::from_array(out_data),
}
}
///|
/// 医学图像降噪(各向异性扩散,简化版)
pub fn medical_denoise(
img : @types.Image,
iterations? : Int = 5,
kappa? : Double = 30.0,
) -> @types.Image {
let iter = iterations
let k = kappa
let w = img.width
let h = img.height
let channels = img.channels
let mut current : Array[Double] = Array::make(w * h * channels, 0.0)
for i in 0..<(w * h * channels) {
current[i] = img.data[i].to_double()
}
for _ in 0..<iter {
let next : Array[Double] = Array::make(w * h * channels, 0.0)
for y in 1..<(h - 1) {
for x in 1..<(w - 1) {
for c in 0..<channels {
let idx = (y * w + x) * channels + c
let center = current[idx]
// 四邻域梯度
let north = current[((y - 1) * w + x) * channels + c] - center
let south = current[((y + 1) * w + x) * channels + c] - center
let east = current[(y * w + (x + 1)) * channels + c] - center
let west = current[(y * w + (x - 1)) * channels + c] - center
// 扩散系数(指数函数,边缘保留)
let cn = @math.exp(-(north.abs() / k) * (north.abs() / k))
let cs = @math.exp(-(south.abs() / k) * (south.abs() / k))
let ce = @math.exp(-(east.abs() / k) * (east.abs() / k))
let cw = @math.exp(-(west.abs() / k) * (west.abs() / k))
// 更新
let lambda = 0.25
next[idx] = center +
lambda * (cn * north + cs * south + ce * east + cw * west)
}
}
}
// 边界复制
for y in 0..<h {
for x in 0..<w {
if y == 0 || y == h - 1 || x == 0 || x == w - 1 {
for c in 0..<channels {
next[(y * w + x) * channels + c] = current[(y * w + x) * channels +
c]
}
}
}
}
current = next
}
let out_data : Array[Byte] = Array::make(w * h * channels, b'\x00')
for i in 0..<(w * h * channels) {
out_data[i] = current[i].min(255.0).max(0.0).to_int().to_byte()
}
@types.Image::{
width: w,
height: h,
channels,
data: Bytes::from_array(out_data),
}
}
///|
/// 测量图像中两点之间的距离(像素距离)
pub fn measure_distance(
x1 : Int,
y1 : Int,
x2 : Int,
y2 : Int,
pixel_spacing? : Double = 1.0,
) -> Double {
let spacing = pixel_spacing
let dx = (x2 - x1).to_double()
let dy = (y2 - y1).to_double()
(dx * dx + dy * dy).sqrt() * spacing
}
///|
/// 测量图像中区域的面积(像素面积)
pub fn measure_area(mask : @types.Image, pixel_area? : Double = 1.0) -> Double {
let area_per_pixel = pixel_area
let w = mask.width
let h = mask.height
let channels = mask.channels
let mut count = 0
for y in 0..<h {
for x in 0..<w {
let idx = (y * w + x) * channels
if mask.data[idx].to_int() > 128 {
count += 1
}
}
}
count.to_double() * area_per_pixel
}