基于最小体积单纯形的快速高光谱图像解混算法

高光谱遥感技术是识别目标区域内端元成分及其比例的关键技术,在地物分类、环境监测等领域有广泛应用。高光谱图像解混(Hyperspectral Unmixing, HU)就是分析高光谱数据,识别图像中的端元(endmembers)及其对应的丰度(abundances)的信号处理过程。其中Craig的最小体积外接单纯形准则是一种经典有效的盲解混方法,即将包围数据点云的最小体积单纯形的顶点视为端元估计。但相关算法由于涉及复杂的体积计算而计算效率低下。但是HyperCSI(Hyperplane-based Craig-Simplex Identification)算法不需要计算复杂的体积函数,而是利用一个几何定理:一个N维单纯形可以由N个超平面(N-2维)确定。HyperCSI算法通过构造N个与Craig最小外接单纯形相关的超平面,来重构该最小外接单纯形。这样做不仅避免了体积计算,而且在计算复杂度上也大大优于Craig准则算法。

算法原理

1. 假设和符号定义

设观测数据为 \(\{x[1],\dots,x[L]\} \subset \mathbb{R}^M\), 其中每个 \(x[n] \in \mathbb{R}^M\) 是图像中的一个像素向量,含有M个光谱波段的值。数据 \(x[n]\) 被假设由 \(N\) 个端元 \(\{a_1,\dots,a_N\}\subset \mathbb{R}^M\) 线性组合而成,其丰度向量 \(s[n] = [s_1[n],\dots,s_N[n]]^T \in \mathbb{R}^N\) 满足非负性约束和相加为1。即:

\[x[n] = \sum_{i=1}^N s_i[n] a_i + w[n], \quad \forall n \in \{1,\dots,L\}\]

其中 \(w[n]\) 是加性噪声。令 \(\alpha_i = C^\dagger (a_i-d) \in \mathbb{R}^{N-1}\) 是低维表示(dimension reduction, DR)后的端元向量,其中 \(C\in\mathbb{R}^{M \times (N-1)}\) 是数据矩阵的前N-1个主成分对应的特征向量组成的矩阵, \(d=\frac{1}{L}\sum_{n=1}^L x[n]\) 是数据均值。则可以得到DR后的数据:

\[\tilde{x}[n] = C^\dagger (x[n] - d) = \sum_{i=1}^N s_i[n]\alpha_i \in \mathbb{R}^{N-1}\]

2. 超平面表示Craig最小外接单纯形

alt text 设 Craig 的最小外接单纯形为 \(\mathcal{T} = \mathrm{conv}\{\alpha_1,\dots,\alpha_N\} \subset \mathbb{R}^{N-1}\)。根据以下命题,这个单纯形可以由 \(N\) 个与之相关的超平面 \(H_1,\dots,H_N\) 确定:

命题1 如果 \(\{\alpha_1,\dots,\alpha_N\}\subset\mathbb{R}^{N-1}\) 是仿射独立的(即 \(\mathcal{T}\) 是一个单纯形),那么 \(\mathcal{T}\) 可以由 \(N\) 个紧密包围 \(\mathcal{T}\) 的超平面 \(\{H_1,\dots,H_N\}\) 重构, 其中 \(H_i = \text{aff}(\{\alpha_1,\dots,\alpha_N\}\backslash\{\alpha_i\})\)

证明思路:只需证明 \(\{\alpha_1,\dots,\alpha_N\}\) 可以由 \(\{H_1,\dots,H_N\}\) 确定即可。证明略。

所以 HyperCSI 算法的关键是估计这 \(N\) 个超平面,从而得到 Craig 最小外接单纯形,进而得到端元估计。 alt text ### 3. 超平面法向量估计

现考虑如何估计第 i 个超平面 \(H_i(b_i,h_i) = \{x\in\mathbb{R}^{N-1} \ \vert \ b_i^T x = h_i\}\) 的法向量 \(b_i\) 和常数 \(h_i\)

根据以下命题,只要能找到 \(H_i\) 上的 \(N-1\) 个仿射独立点,即可确定 \(b_i\)

命题2 给定任意 \(N-1\)\(H_i\) 上的仿射独立点集 \(\{p_1^{(i)},\dots,p_{N-1}^{(i)}\}\subset H_i\),则有(除去一个正比例因子):

\[b_i = v_i (p_1^{(i)}, \dots, p_{N-1}^{(i)})\]

其中

\[v_i(p_1, \dots, p_{N-1}) = (I_{N-1} - P(P^TP)^{-1}P^T)(p_j - p_i), \quad \forall j\neq i\]

\(P = [\alpha_1 \cdots \alpha_i \cdots \alpha_j \cdots \alpha_N] - \alpha_j \cdot 1_{N-2}^T\)

接下来我们将从原始数据 \(X = \{\tilde{x}[1], \dots, \tilde{x}[L]\}\) 中寻找 \(H_i\) 上的 \(N-1\) 个"最近"点集 \(P_i\)。具体做法是:

  1. 首先利用 SPA 算法从 \(X\) 中提取出 \(N\) 个最"纯净"的像素 \(\{\tilde{\alpha}_1, \dots, \tilde{\alpha}_N\}\) (可视为离 \(\alpha_1, \dots, \alpha_N\) 最近的像素)

  2. 计算超平面 \(\tilde{H}_i = \text{aff}(\{\tilde{\alpha}_1, \dots, \tilde{\alpha}_N\}\backslash\{\tilde{\alpha}_i\})\) 的法向量 \(\tilde{b}_i\)

  3. 将数据集 \(X\) 划分为 \(N-1\) 个不相交区域 \(R_1^{(i)},\dots,R_{N-1}^{(i)}\),每个区域以一个 \(\tilde{\alpha}_j\) 为中心

  4. 在每个区域内寻找离 \(\tilde{H}_i\) 最近的一个点,即求解:

\[p_k^{(i)} \in \arg\max\{\tilde{b}_i^T p \mid p \in X \cap R_k^{(i)}\}, \quad \forall k\in\{1,\dots,N-1\}\]

令所得点集为 \(P_i = \{p_1^{(i)}, \dots, p_{N-1}^{(i)}\}\)

  1. 根据命题2,计算HyperCSI算法中第i个超平面的法向量估计:

\[\hat{b}_i = v_i(p_1^{(i)}, \dots, p_{N-1}^{(i)})\]

4. 超平面内积常数估计

上述方法可以得到Craig最小外接单纯形的 \(N\) 个超平面的法向量估计 \(\{\hat{b}_1,\dots,\hat{b}_N\}\)。为了完整确定这些超平面,我们还需要估计对应的内积常数 \(\hat{h}_i\)。考虑以下引理:

引理1

  1. 对于所有的 \(p\in X\),有 \(b_i^Tp \leq h_i\)(即所有数据点都在同一侧)。

  2. \(p\in X\)\(H_i\) 的距离为 \(\text{dist}(p,H_i) = |h_i - b_i^Tp| / \|b_i\|\)

  3. 当且仅当 \(b_i\) 由内向外指向Craig最小外接单纯形时,点到平面距离最大值对应的点 \(\hat{p} = \arg\max\{b_i^Tp\mid p\in X\}\) 为离 \(H_i\) 最近的点。

所以很自然可以取

\[\hat{h}_i = \max\{\hat{b}_i^T p \mid p \in X\}\]

为对应的内积常数估计。

在存在噪声的情况下,由于噪声可能使数据中的端元种类膨胀,导致Craig最小外接单纯形体积增大,估计超平面被推离数据均值(DR空间中的原点)。为了缓解这种效果,我们对估计超平面进行适当内移,令

\[\hat{H}_i = \{\hat{b}_i^Tx = \hat{h}_i/c\}, \quad c \geq 1\]

其中 \(c\) 是一个内移因子,取值为

\[c = \max\{1, \max\{-v_{ij}/d_j \mid i\in\{1,\dots,N\}, j\in\{1,\dots,M\}\}\} / \eta\]

这里 \(\eta \in (0,1]\) 是一个预设参数(典型取0.9), \(v_{ij}\)\(C(\hat{B}_{-i}^{-1}\hat{h}_{-i})\) 的第j个元素, \(d_j\) 是数据均值 \(d\) 的第j个元素, \(\hat{B}_{-i}\)\(\hat{h}_{-i}\) 分别由向量 \(\{\hat{b}_j,\hat{h}_j\}_{j\neq i}\) 确定。这样做可以确保估计端元特征为非负。

最终,经过内移后的端元估计为:

\[\hat{\alpha}_i = \hat{B}_{-i}^{-1}\frac{\hat{h}_{-i}}{c}, \quad \hat{a}_i = C\hat{\alpha}_i + d, \quad \forall i\in\{1,\dots,N\}\]

5. 丰度估计

尽管丰度通常通过求解完全受约束最小二乘(FCLS)问题估计,但由于Craig准则提供的一些几何量,实际可以利用如下解析形式表达式快速估计丰度:

\[\hat{s}_i[n] = \left(\frac{\hat{h}_i - \hat{b}_i^T\tilde{x}[n]}{\hat{h}_i - \hat{b}_i^T\hat{\alpha}_i}\right)_+, \quad \forall i\in\{1,\dots,N\}, \, \forall n\in\{1,\dots,L\}\]

其中 \((y)_+ = \max\{y,0\}\) 用于约束丰度非负。当像素 \(\tilde{x}[n]\) 位于估计端元外接单纯形内时,该估计就等价于求解FCLS问题所得结果。但当像素偏离估计单纯形较远时,可能会产生一定偏差。不过对于高信噪比的高光谱数据,大部分像素都会落在估计单纯形附近,利用上述快速丰度估计是合理的。

算法特点总结

  • HyperCSI算法通过构造Craig最小外接单纯形的关联超平面,避免了复杂的体积计算,从而实现了高效的Craig准则求解。

  • 它只需找到 \(N(N-1)\) 个像素(与数据长度无关)即可重构Craig最小外接单纯形的 \(N\) 个超平面。

  • 理论证明了在无噪声和足够多像素的条件下,HyperCSI算法可以完全识别出真实端元和Craig最小外接单纯形。

  • 丰度估计采用封闭形式快速计算。

  • 整体计算复杂度为 \(\mathcal{O}(N^2L)\),与一些基于纯像素的经典算法复杂度相当。

总之,HyperCSI算法是一种新颖高效的Craig准则求解方法,在避免复杂体积计算的同时,保留了传统算法的优良性能。

代码实现

MATLAB实现

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
% 参考文献:
% C.-H. Lin, C.-Y. Chi, Y.-H. Wang, and T.-H. Chan,
% ``A fast hyperplane-based minimum-volume enclosing simplex algorithm for blind hyperspectral unmixing,"
% arXiv preprint arXiv:1510.08917, 2015.
%======================================================================
% 超平面基于Craig-Simplex-识别算法的快速实现
% [A_est, S_est, time] = HyperCSI(X,N)
%======================================================================
% 输入
% X是M-by-L数据矩阵,其中M是光谱波段数,L是像素数
% N是端元数量
%----------------------------------------------------------------------
% 输出
% A_est是M-by-N混合矩阵,其列是估计的端元签名
% S_est是N-by-L源矩阵,其行是估计的丰度图
% time是计算时间(以秒为单位)
%========================================================================

function [A_est, S_est, time] = HyperCSI(X,N)
t0 = clock; % 获取当前时间

%------------------------ 步骤1 ------------------------
[M L ] = size(X); % 获取X的尺寸
d = mean(X,2); % 计算均值向量
U = X-d*ones(1,L); % 均值中心化
[eV D] = eig(U*U'); % 计算特征值和特征向量
C = eV(:,M-N+2:end); % 提取前N-1个主成分
Xd = C'*(X-d*ones(1,L)); % 维度缩减数据(Xd是(N-1)-by-L)

%------------------------ 步骤2 ------------------------
alpha_tilde = SPA(Xd,L,N); % 确定最纯像素

%------------------------ 步骤3 ------------------------
for i = 1:N
bi_tilde(:,i) = compute_bi(alpha_tilde,i,N); % 获得bi_tilde
end

r = (1/2)*norm(alpha_tilde(:,1)-alpha_tilde(:,2)); % 初始化超球半径
for i = 1:N-1
for j = i+1:N
dist_ai_aj(i,j) = norm(alpha_tilde(:,i)-alpha_tilde(:,j));
if (1/2)*dist_ai_aj(i,j) < r
r = (1/2)*dist_ai_aj(i,j); % 计算超球半径
end
end
end
Xd_divided_idx = zeros(L,1); % 初始化标记数组
radius_square = r^2; % 半径的平方
for k = 1:N
[IDX_alpha_i_tilde]= find( sum( (Xd- alpha_tilde(:,k)*ones(1,L) ).^2,1 ) < radius_square );
Xd_divided_idx(IDX_alpha_i_tilde) = k ; % 计算超球
end

%------------------------ 步骤4 ------------------------
for i = 1:N
Hi_idx = setdiff([1:N],[i]); % 除去第i个端元
for k = 1:1*(N-1)
Ri_k = Xd(:,( Xd_divided_idx == Hi_idx(k) )); % 选择属于第k个超球的数据
[val idx] = max(bi_tilde(:,i)'*Ri_k); % 找到与bi_tilde(:,i)投影最大的点
pi_k(:,k) = Ri_k(:,idx); % 记录这些点作为超平面上的N-1个仿射独立点
end
b_hat(:,i) = compute_bi([pi_k alpha_tilde(:,i)],N,N); % 计算b_hat(:,i)
h_hat(i,1) = max(b_hat(:,i)'*Xd); % 计算h_hat(i,1)
end

%------------------------ 步骤5&步骤6 ------------------------
comm_flag = 1; % comm_flag = 1表示有噪声,需要将超平面向数据云中心移动
% comm_flag = 0表示无噪声,不需要执行步骤5(因此c = 1)

eta = 0.9; % 0.9是经验上的良好选择,用于USGS库中的端元
for i = 1:N
bbbb = b_hat;
ccconst = h_hat;
bbbb(:,i) = []; % 除去第i列
ccconst(i) = []; % 除去第i个元素
alpha_hat(:,i) = pinv(bbbb')*ccconst; % 计算alpha_hat(:,i)
end

if comm_flag == 1
VV = C*alpha_hat; % 将alpha_hat投影到原始维度
UU = d*ones(1,N); % 构造均值向量
closed_form_optval = max( 1 , max(max( (-VV) ./ UU)) ); % 计算c'
c = closed_form_optval/eta; % 计算c
h_hat = h_hat/c; % 更新h_hat
alpha_hat = alpha_hat/c; % 更新alpha_hat
end
A_est = C * alpha_hat + d * ones(1,N); % 端元估计

%------------------------ 步骤7 ------------------------
% 步骤7可以被删除,如果用户不需要丰度估计
S_est = ( h_hat*ones(1,L)- b_hat'*Xd ) ./ ( ( h_hat - sum( b_hat.*alpha_hat )' ) *ones(1,L) );
S_est(S_est<0) = 0; % 非负约束
% end

time = etime(clock,t0); % 计算运行时间


%% 子程序1
function [bi] = compute_bi(a0,i,N)
Hindx = setdiff([1:N],[i]); % 除去第i个端元
A_Hindx = a0(:,Hindx); % 选择其他端元
A_tilde_i = A_Hindx(:,1:N-2)-A_Hindx(:,N-1)*ones(1,N-2); % 计算A_tilde_i
bi = A_Hindx(:,N-1)-a0(:,i); % 计算bi
bi = (eye(N-1) - A_tilde_i*(pinv(A_tilde_i'*A_tilde_i))*A_tilde_i')*bi; % 投影bi到null(A_tilde_i)
bi = bi/norm(bi); % 归一化
return;
% end


%% 子程序2
function [alpha_tilde] = SPA(Xd,L,N)

% 参考文献:
% [1] W.-K. Ma, J. M. Bioucas-Dias, T.-H. Chan, N. Gillis, P. Gader, A. J. Plaza, A. Ambikapathi, and C.-Y. Chi,
% ``A signal processing perspective on hyperspectral unmixing,��
% IEEE Signal Process. Mag., vol. 31, no. 1, pp. 67�V81, 2014.
%
% [2] S. Arora, R. Ge, Y. Halpern, D. Mimno, A. Moitra, D. Sontag, Y. Wu, and M. Zhu,
% ``A practical algorithm for topic modeling with provable guarantees,��
% arXiv preprint arXiv:1212.4777, 2012.
%======================================================================
% 连续投影算法(SPA)的实现
% [alpha_tilde] = SPA(Xd,L,N)
%======================================================================
% 输入
% Xd是降维后的数据矩阵
% L是像素数
% N是端元数量
%----------------------------------------------------------------------
% 输出
% alpha_tilde是(N-1)-by-N矩阵,其列是降维后的最纯像素
%======================================================================
%======================================================================

%----------- 定义默认参数------------------
con_tol = 1e-8; % SPA收敛容差
num_SPA_itr = N; % SPA后处理迭代次数
N_max = N; % 最大迭代次数

%------------------------ SPA初始化 ------------------------
A_set=[]; Xd_t = [Xd; ones(1,L)]; index = []; % 初始化
[val ind] = max(sum( Xd_t.^2 )); % 找到最大投影和的点
A_set = [A_set Xd_t(:,ind)]; % 将该点加入A_set
index = [index ind]; % 记录索引
for i=2:N
XX = (eye(N_max) - A_set * pinv(A_set)) * Xd_t; % 投影到A_set的补空间
[val ind] = max(sum( XX.^2 )); % 找到最大投影和的点
A_set = [A_set Xd_t(:,ind)]; % 将该点加入A_set
index = [index ind]; % 记录索引
end
alpha_tilde = Xd(:,index); % 初始最纯像素估计

%------------------------ SPA后处理 ------------------------
current_vol = det( alpha_tilde(:,1:N-1) - alpha_tilde(:,N)*ones(1,N-1) ); % 计算初始体积
for jjj = 1:num_SPA_itr
for i = 1:N
b(:,i) = compute_bi(alpha_tilde,i,N); % 计算bi
b(:,i) = -b(:,i); % 取负值
[const idx] = max(b(:,i)'*Xd); % 找到与bi投影最大的点
alpha_tilde(:,i) = Xd(:,idx); % 更新alpha_tilde(:,i)
end
new_vol = det( alpha_tilde(:,1:N-1) - alpha_tilde(:,N)*ones(1,N-1) ); % 计算新体积
if (new_vol - current_vol)/current_vol < con_tol
break; % 收敛
end
end
return;
% end

Python实现

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
import numpy as np
from time import time

# Reference:
# C.-H. Lin, C.-Y. Chi, Y.-H. Wang, and T.-H. Chan,
# ``A fast hyperplane-based minimum-volume enclosing simplex algorithm for blind hyperspectral unmixing,"
# arXiv preprint arXiv:1510.08917, 2015.
#======================================================================
# A fast implementation of Hyperplane-based Craig-Simplex-Identification algorithm
# [A_est, S_est, time] = HyperCSI(X,N)
#======================================================================
# Input
# X is M-by-L data matrix, where M is the number of spectral bands and L is the number of pixels.
# N is the number of endmembers.
#----------------------------------------------------------------------
# Output
# A_est is M-by-N mixing matrix whose columns are estimated endmember signatures.
# S_est is N-by-L source matrix whose rows are estimated abundance maps.
# time is the computation time (in secs).
#========================================================================

def HyperCSI(X, N):
t0 = time()

#------------------------ Step 1 ------------------------
M, L = X.shape
d = np.mean(X, axis=1, keepdims=True)
U = X - d
D, eV = np.linalg.eigh(U @ U.T)
C = eV[:, M-N:M]
Xd = C.T @ (X - d) # dimension reduced data (Xd is (N-1)-by-L)

#------------------------ Step 2 ------------------------
alpha_tilde = SPA(Xd, L, N) # the identified purest pixels

#------------------------ Step 3 ------------------------
bi_tilde = np.zeros((N-1, N))
for i in range(N):
bi_tilde[:, i] = compute_bi(alpha_tilde, i, N) # obtain bi_tilde

r = 0.5 * np.linalg.norm(alpha_tilde[:, 0] - alpha_tilde[:, 1])
for i in range(N-1):
for j in range(i+1, N):
dist_ai_aj = np.linalg.norm(alpha_tilde[:, i] - alpha_tilde[:, j])
if 0.5 * dist_ai_aj < r:
r = 0.5 * dist_ai_aj # compute radius of hyperballs

Xd_divided_idx = np.zeros(L, dtype=int)
radius_square = r**2
for k in range(N):
IDX_alpha_i_tilde = np.sum((Xd - alpha_tilde[:, k].reshape(-1, 1))**2, axis=0) < radius_square
Xd_divided_idx[IDX_alpha_i_tilde] = k # compute the hyperballs

#------------------------ Step 4 ------------------------
b_hat = np.zeros((N-1, N))
h_hat = np.zeros(N)
for i in range(N):
Hi_idx = [idx for idx in range(N) if idx != i]
pi_k = np.zeros((N-1, N-1))
for k in range(N-1):
Ri_k = Xd[:, Xd_divided_idx == Hi_idx[k]]
idx = np.argmax(bi_tilde[:, i].T @ Ri_k)
pi_k[:, k] = Ri_k[:, idx] # find N-1 affinely independent points for each hyperplane
b_hat[:, i] = compute_bi(np.hstack((pi_k, alpha_tilde[:, i].reshape(-1, 1))), N, N)
h_hat[i] = np.max(b_hat[:, i].T @ Xd)

#------------------------ Step 5 & Step 6 ------------------------
comm_flag = 1
# comm_flag = 1 in noisy case: bring hyperplanes closer to the center of data cloud
# comm_flag = 0 when no noise: Step 5 will not be performed (and hence c = 1)

eta = 0.9 # 0.9 is empirically good choice for endmembers in USGS library
alpha_hat = np.zeros((N-1, N))
for i in range(N):
bbbb = np.delete(b_hat, i, axis=1)
ccconst = np.delete(h_hat, i)
alpha_hat[:, i] = np.linalg.pinv(bbbb.T) @ ccconst

if comm_flag == 1:
VV = C @ alpha_hat
UU = d * np.ones((1, N))
closed_form_optval = max(1, np.max((-VV) / UU)) # c' in Step 5
c = closed_form_optval / eta
h_hat = h_hat / c
alpha_hat = alpha_hat / c

A_est = C @ alpha_hat + d # endmemeber estimates

#------------------------ Step 7 ------------------------
# Step 7 can be removed if the user do not need abundance estimation
S_est = (h_hat.reshape(1, -1) - b_hat.T @ Xd) / ((h_hat - np.sum(b_hat * alpha_hat, axis=1)).reshape(1, -1))
S_est = np.maximum(S_est, 0)
# end

time_elapsed = time() - t0

return A_est, S_est, time_elapsed


#% subprogram 1
def compute_bi(a0, i, N):
Hindx = [idx for idx in range(N) if idx != i]
A_Hindx = a0[:, Hindx]
A_tilde_i = A_Hindx[:, :-1] - A_Hindx[:, -1].reshape(-1, 1)
bi = A_Hindx[:, -1] - a0[:, i]
A_tilde_i_pinv = np.linalg.pinv(A_tilde_i.T @ A_tilde_i)
bi = (np.eye(N-1) - A_tilde_i @ A_tilde_i_pinv @ A_tilde_i.T) @ bi
bi = bi / np.linalg.norm(bi)
return bi


#% subprogram 2
def SPA(Xd, L, N):
# Reference:
# [1] W.-K. Ma, J. M. Bioucas-Dias, T.-H. Chan, N. Gillis, P. Gader, A. J. Plaza, A. Ambikapathi, and C.-Y. Chi,
# ``A signal processing perspective on hyperspectral unmixing,��
# IEEE Signal Process. Mag., vol. 31, no. 1, pp. 67�V81, 2014.
#
# [2] S. Arora, R. Ge, Y. Halpern, D. Mimno, A. Moitra, D. Sontag, Y. Wu, and M. Zhu,
# ``A practical algorithm for topic modeling with provable guarantees,��
# arXiv preprint arXiv:1212.4777, 2012.
#======================================================================
# An implementation of successive projection algorithm (SPA)
# [alpha_tilde] = SPA(Xd,L,N)
#======================================================================
# Input
# Xd is dimension-reduced (DR) data matrix.
# L is the number of pixels.
# N is the number of endmembers.
#----------------------------------------------------------------------
# Output
# alpha_tilde is an (N-1)-by-N matrix whose columns are DR purest pixels.
#======================================================================
#======================================================================

#----------- Define default parameters------------------
con_tol = 1e-8 # the convergence tolence in SPA
num_SPA_itr = N # number of iterations in post-processing of SPA
N_max = N # max number of iterations

#------------------------ initialization of SPA ------------------------
A_set = np.zeros((N, 0))
Xd_t = np.vstack((Xd, np.ones(L)))
index = []
val = np.sum(Xd_t**2, axis=0)
ind = np.argmax(val)
A_set = np.hstack((A_set, Xd_t[:, ind].reshape(-1, 1)))
index.append(ind)
for i in range(1, N):
XX = Xd_t - A_set @ np.linalg.pinv(A_set.T @ A_set) @ A_set.T @ Xd_t
val = np.sum(XX**2, axis=0)
ind = np.argmax(val)
A_set = np.hstack((A_set, Xd_t[:, ind].reshape(-1, 1)))
index.append(ind)
alpha_tilde = Xd[:, index]

#------------------------ post-processing of SPA ------------------------
current_vol = np.linalg.det(alpha_tilde[:, :-1] - alpha_tilde[:, -1].reshape(-1, 1))
for jjj in range(num_SPA_itr):
b = np.zeros((N-1, N))
for i in range(N):
b[:, i] = compute_bi(alpha_tilde, i, N)
b[:, i] = -b[:, i]
idx = np.argmax(b[:, i].T @ Xd)
alpha_tilde[:, i] = Xd[:, idx]
new_vol = np.linalg.det(alpha_tilde[:, :-1] - alpha_tilde[:, -1].reshape(-1, 1))
if (new_vol - current_vol) / current_vol < con_tol:
break
current_vol = new_vol
return alpha_tilde

基于最小体积单纯形的快速高光谱图像解混算法
http://jingmengzhiyue.top/2024/03/24/HyperCSI/
作者
Jingmengzhiyue
发布于
2024年3月24日
许可协议