Repository navigation
Expand file tree
/
Copy pathutils.py
More file actions
117 lines (99 loc) · 3.45 KB
/
Copy pathutils.py
File metadata and controls
117 lines (99 loc) · 3.45 KB
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 2 18:29:31 2021
@author: yanni
"""
import torch
import torch.fft as torch_fft
import torch.nn as nn
import numpy as np
# import sigpy as sp
def normalize_np(gen_img, estimated_mvue):
'''
Estimate mvue from coils and normalize with 99% percentile.
'''
scaling = np.quantile(np.abs(estimated_mvue), 0.99)
return gen_img * scaling
def unnormalize_np(gen_img, estimated_mvue):
'''
Estimate mvue from coils and normalize with 99% percentile.
'''
scaling = np.quantile(np.abs(estimated_mvue), 0.99)
return gen_img / scaling
def normalize(gen_img, estimated_mvue):
'''
Estimate mvue from coils and normalize with 99% percentile.
'''
scaling = torch.quantile(estimated_mvue.abs(), 0.99)
return gen_img * scaling
def unnormalize(gen_img, estimated_mvue):
'''
Estimate mvue from coils and normalize with 99% percentile.
'''
scaling = torch.quantile(estimated_mvue.abs(), 0.99)
return gen_img / scaling
# Centered, orthogonal ifft in torch >= 1.7
def ifft(x):
x = torch_fft.ifftshift(x, dim=(-2, -1))
x = torch_fft.ifft2(x, dim=(-2, -1), norm='ortho')
x = torch_fft.fftshift(x, dim=(-2, -1))
return x
# Centered, orthogonal fft in torch >= 1.7
def fft(x):
x = torch_fft.fftshift(x, dim=(-2, -1))
x = torch_fft.fft2(x, dim=(-2, -1), norm='ortho')
x = torch_fft.ifftshift(x, dim=(-2, -1))
return x
def nrmse(x,y):
num = torch.norm(x-y)
den = torch.norm(x)
return num/den
def get_mvue(kspace, s_maps):
''' Get mvue estimate from coil measurements '''
return np.sum(sp.ifft(kspace, axes=(-1, -2)) * \
np.conj(s_maps), axis=1)
# Multicoil forward operator for MRI
class MulticoilForwardMRI(nn.Module):
def __init__(self, orientation):
self.orientation = orientation
super(MulticoilForwardMRI, self).__init__()
return
# Centered, orthogonal ifft in torch >= 1.7
def _ifft(self, x):
x = torch_fft.ifftshift(x, dim=(-2, -1))
x = torch_fft.ifft2(x, dim=(-2, -1), norm='ortho')
x = torch_fft.fftshift(x, dim=(-2, -1))
return x
# Centered, orthogonal fft in torch >= 1.7
def _fft(self, x):
x = torch_fft.fftshift(x, dim=(-2, -1))
x = torch_fft.fft2(x, dim=(-2, -1), norm='ortho')
x = torch_fft.ifftshift(x, dim=(-2, -1))
return x
'''
Inputs:
- image = [B, H, W] torch.complex64/128 in image domain
- maps = [B, C, H, W] torch.complex64/128 in image domain
- mask = [B, W] torch.complex64/128 w/ binary values
Outputs:
- ksp_coils = [B, C, H, W] torch.complex64/128 in kspace domain
'''
def forward(self, image, maps, mask):
# Broadcast pointwise multiply
coils = image[:, None] * maps
# Convert to k-space data
ksp_coils = self._fft(coils)
if self.orientation == 'vertical':
# Mask k-space phase encode lines
ksp_coils = ksp_coils * mask[:, None, None, :]
elif self.orientation == 'horizontal':
# Mask k-space frequency encode lines
ksp_coils = ksp_coils * mask[:, None, :, None]
else:
if len(mask.shape) == 3:
ksp_coils = ksp_coils * mask[:, None, :, :]
else:
raise NotImplementedError('mask orientation not supported')
# Return downsampled k-space
return ksp_coils