如何科学地利用高光谱图像合成真彩色RGB图像?

2023-11-17

如何科学地利用高光谱图像合成真彩色RGB图像?

1. 前言

参考链接:

色匹配函数是什么? - 知乎 (zhihu.com)

23. 颜色知识1-人类的视觉系统与颜色 - 知乎 (zhihu.com)

色彩空间基础 - 知乎 (zhihu.com)

色彩空间表示与转换 - 知乎 (zhihu.com)

CIE XYZ - freshair_cn - 博客园 (cnblogs.com)

CIE 1931 color space - Wikipedia

CIE 1931色彩空间 - 维基百科,自由的百科全书 (wikipedia.org)

RGB/XYZ Matrices (brucelindbloom.com)

调色名词浅析——Gamma(伽玛)校正 - 知乎 (zhihu.com)

前置条件:

  • 必须有高光谱图像
  • 必须有波段信息,(你需要知道高光谱图像每个通道对应的波长是多少)

对于波段信息,我的波段信息是从软件ENVI中获取的txt文件
本文以128波段的高光谱图像为例,txt文件详细内容在文末给出

先上流程图,随后再逐一解释:

在这里插入图片描述

2. 计算色匹配函数

色匹配函数其实就是如下三条曲线(使用python手动绘制):

CIE-XYZ色匹配函数曲线如下:

在这里插入图片描述

2.1 什么是色匹配函数

追根溯源的话,得从我们人类的视网膜说起。大部分人类的视网膜上有三种感知颜色的感光细胞,叫做视锥细胞,分别对不同波长的光线敏感,称为 L/M/S 型细胞。三种视锥细胞最敏感的波长分别是橙红色(长波,Long),绿色(中波,Medium),蓝色(短波,Short)。这三种视锥细胞的归一化感光曲线如下图所示

在这里插入图片描述

不仅如此,人类眼睛对不同颜色光线混合的反应还是 线性 的。根据 格拉斯曼定律(Grassmann’s Law),两束不同颜色的光 C 1 C_1 C1 C 2 C_2 C2,假设某个视锥细胞对他们的反应分别是 r 1 r_1 r1 r 2 r_2 r2,现在将他们按照一个比例混合,得到第三种颜色 C 3 = α C 1 + β C 2 C_3=\alpha C_1 + \beta C_2 C3=αC1+βC2,那么视锥细胞对这个混合颜色的反应也将是前两个反应的线性叠加 r 3 = α r 1 + β r 2 r_3=\alpha r_1 + \beta r_2 r3=αr1+βr2

格拉斯曼定律是一个实验规律,并没有物理或者生物学上的依据。然而这个规律大大简化了我们对人类彩色视觉系统的建模,并且给我们使用线性代数理论分析人类彩色视觉系统提供了一个前提和基础。

前面已经提到,人类视网膜上有三种感知色彩的视锥细胞,所以理论上我们用三种颜色的光就可以混合出自然界中任何一种颜色来。在 20 世纪 20 年代,David Wright 和 John Guild 各自独立地领导了一些实验,通过三种颜色的光源进行匹配,得到了人眼对于不同颜色光的匹配函数。此后,多名科学家多次进行了类似的实验,加深了我们对人类彩色视觉的认识。

实验过程大致是这样的,把一个屏幕用不透光的挡板分割成两个区域,左边照射某个被测试的颜色的光线,这里记为 C C C(以下用大写字母表明颜色,用小写字母表明分量大小),右边同时用三种颜色的光同时照射,这里记为 R R R G G G B B B。然后,调节右边三种颜色光源的强度,直到左右两边的颜色看上去一样为止。假设这个时候三种颜色的光源强度分别为 r r r g g g b b b,那么根据光色叠加的线性性质,我们可以写出

C = r R + g G + b B C = rR + gG + bB C=rR+gG+bB

也就是说,只要按照 (r,g,b) 的分量来混合 (R,G,B) 三种颜色的光,就可以得到 C 这个颜色的光。于是在这一系列实验里,科学家们把左边的颜色按着光谱顺序,挨个测试了一遍,得到了纯光谱色的混合叠加的数据,这就是 色匹配函数(Color Matching Function) ,并且在这个基准下定义的色彩空间,就是 CIE RGB 色彩空间。下图是 CIE RGB 的色匹配函数曲线,(图片数据来自CVRL main (ucl.ac.uk))。浅色的细线代表实验中不同参与者个人的色匹配函数曲线,中间深色的粗线代表数据的平均值。

在这里插入图片描述

可以看到,曲线上出现了负数,这是怎么回事?回想一下前面描述的实验过程,左边是被测试的光色,右边是可调节的三色光的混合。如果碰到一种情况,右边三色光无论如何调节比例,都不能混合出左边的颜色,比如某种颜色的光强度已经减小为 0 了,然而看趋势还需要继续减小才能与左边的光色相匹配,怎么办?这时候需要往左边的光色中混入三色光中的一种或者几种,继续调节,直到两边的颜色匹配。在左边(被测试)的色光中添加,那就是相当于在右边的混合光中减去,这就导致了色匹配函数曲线上出现了负数。实际上,这相当于就是光线的「减法」了。

比如,对于 555nm 的黄色光,色匹配函数的值是 (1.30, 0.97, -0.01),意味着将 1.30 份的红光与 0.97 份的绿光混合放在右边,左边放上 1 份的 555nm 的黄光,以及 0.01 份的蓝光,这样左右两边的光色看上去就一样了。

因为有部分出现了负数,在使用和计算上都有不方便,因此就对这个匹配函数进行了一下线性变换,变换到一个所有分量都是正的空间中。变换后的色彩空间就是 CIE XYZ 色彩空间。 (图片数据来自CVRL main (ucl.ac.uk)

img

CIE RGB 色彩空间和 CIE XYZ 色彩空间是完全等价的,两者只是差了一个线性变换。由于允许「减法」的存在,因此 CIE RGB 空间是能够表示所有颜色的;同样的,CIE XYZ 空间也能。

在计算机问世之前,计算带有负值乘法的曲线是很麻烦的;XYZ就是为了把RGB空间转换成另一个没有负值的、方便计算的空间。很明显,XYZ的三色刺激值是想象出来的。

XYZ不用于描述颜色,而用于说明光波如何组合会产生什么样的颜色,因此XYZ是独立于设备的。

对于某些计算任务来说,查表可能变得不切实际。CIE XYZ颜色匹配函数可以通过高斯函数的和来近似。

g ( x ) g(x) g(x)表示分段高斯函数,定义如下:
g ( x ; μ , σ 1 , σ 2 ) = { e x p ( − 1 2 ( x − μ ) 2 / σ 1 2 ) , x < μ e x p ( − 1 2 ( x − μ ) 2 / σ 2 2 ) , x < μ g(x;\mu,\sigma_1,\sigma_2) = \begin{cases} exp(-\frac{1}{2}(x-\mu)^2/\sigma_1^2)&, {x<\mu}\\ exp(-\frac{1}{2}(x-\mu)^2/\sigma_2^2)&, {x<\mu} \end{cases} g(x;μ,σ1,σ2)={exp(21(xμ)2/σ12)exp(21(xμ)2/σ22),x<μ,x<μ

也就是说, g ( x ) g(x) g(x)类似于钟形曲线,其峰值在 x = μ x=μ x=μ处, σ 1 σ1 σ1的扩散/标准偏差在平均值的左侧, σ 2 σ2 σ2的扩散在平均值右侧。使用以纳米为单位测量的波长 λ λ λ,我们可以近似1931色匹配函数:
x ‾ ( λ ) = 1.056 g ( λ ; 599.8 , 37.9 , 31.0 ) + 0.362 g ( λ ; 442.0 , 16.0 , 26.7 ) − 0.065 g ( λ ; 501.1 , 20.4 , 26.2 ) , y ‾ ( λ ) = 0.821 g ( λ ; 568.8 , 46.9 , 40.5 ) + 0.286 g ( λ ; 530.9 , 16.3 , 31.1 ) , z ‾ ( λ ) = 1.217 g ( λ ; 437.0 , 11.8 , 36.0 ) + 0.681 g ( λ ; 459.0 , 26.0 , 13.8 ) . \begin{aligned} {\overline {x}}(\lambda )&=1.056g(\lambda ;599.8,37.9,31.0)+0.362g(\lambda ;442.0,16.0,26.7)\\[2mu]&\quad -0.065g(\lambda ;501.1,20.4,26.2),\\[5mu] {\overline {y}}(\lambda )&=0.821g(\lambda ;568.8,46.9,40.5)+0.286g(\lambda ;530.9,16.3,31.1),\\[5mu] {\overline {z}}(\lambda )&=1.217g(\lambda ;437.0,11.8,36.0)+0.681g(\lambda ;459.0,26.0,13.8).\end{aligned} x(λ)y(λ)z(λ)=1.056g(λ;599.8,37.9,31.0)+0.362g(λ;442.0,16.0,26.7)0.065g(λ;501.1,20.4,26.2),=0.821g(λ;568.8,46.9,40.5)+0.286g(λ;530.9,16.3,31.1),=1.217g(λ;437.0,11.8,36.0)+0.681g(λ;459.0,26.0,13.8).

以上数据来自维基百科:CIE 1931 color space - Wikipedia

3. 根据光谱数据计算XYZ空间值

给定这些缩放了颜色匹配函数,带有频谱功率分布 I ( λ ) I(\lambda) I(λ)的一个颜色的RGB 三色刺激值给出为:
R = ∫ 0 ∞ I ( λ )   r ‾ ( λ )   d λ G = ∫ 0 ∞ I ( λ )   g ‾ ( λ )   d λ B = ∫ 0 ∞ I ( λ )   b ‾ ( λ )   d λ R= \int_0^\infty I(\lambda)\,\overline{r}(\lambda)\,d\lambda \\ G= \int_0^\infty I(\lambda)\,\overline{g}(\lambda)\,d\lambda \\ B= \int_0^\infty I(\lambda)\,\overline{b}(\lambda)\,d\lambda R=0I(λ)r(λ)dλG=0I(λ)g(λ)dλB=0I(λ)b(λ)dλ

实际上计算时多采用XYZ色彩空间,故对频谱分布函数积分时一般使用如下公式:
X = ∫ 0 ∞ I ( λ )   x ‾ ( λ )   d λ Y = ∫ 0 ∞ I ( λ )   y ‾ ( λ )   d λ Z = ∫ 0 ∞ I ( λ )   z ‾ ( λ )   d λ X= \int_0^\infty I(\lambda)\,\overline{x}(\lambda)\,d\lambda \\ Y= \int_0^\infty I(\lambda)\,\overline{y}(\lambda)\,d\lambda \\ Z= \int_0^\infty I(\lambda)\,\overline{z}(\lambda)\,d\lambda X=0I(λ)x(λ)dλY=0I(λ)y(λ)dλZ=0I(λ)z(λ)dλ
其中 λ \lambda λ代表波长, I ( λ ) I(\lambda) I(λ)对应了该波段下的能量强度值(其实就是灰度值) 。

x ‾ ( λ ) , y ‾ ( λ ) , z ‾ ( λ ) \overline{x}(\lambda),\overline{y}(\lambda),\overline{z}(\lambda) x(λ),y(λ),z(λ) 分别代表了刚才说的色匹配函数。

4. 将XYZ色彩空间变换到RGB色彩空间

由于 CIE RGB 和 CIE XYZ 两者其实是同一个线性空间的不同表达,因此两者的转换可以通过转换矩阵实现。

由于 CIE XYZ 空间是一个很方便的线性空间,与具体设备无关,因此常用来做各种颜色空间转换的中间媒介。设想某个颜色的光,经过色匹配函数的计算,得到了三个 XYZ 的值,如果直接将这三个值作为 RGB 颜色显示到屏幕上,显然是不对的。我们必须把 XYZ 的值转换到屏幕的 RGB 空间中的值。
[ R l i n G l i n B l i n ] = M [ X Y Z ] \begin{bmatrix}R_{lin}\\G_{lin}\\B_{lin}\end{bmatrix} = M\begin{bmatrix}X\\Y\\Z\end{bmatrix} RlinGlinBlin =M XYZ
由于不同的显示效果的需求,存在不同RGB色彩空间。不同的RGB色彩空间色域存在差异。

不同RGB色彩空间的转换矩阵在如下链接中可以找到:

RGB/XYZ Matrices (brucelindbloom.com)

因为白色参考点相关的内容确实还没有搞懂,但是对于本文要实现的目标不影响,所以挑选不同的转换矩阵尝试就好了,本文使用D50白色参考点,sRGB色域:

在这里插入图片描述

5. 伽马校正

在转换完之后,我们只是得到了一个线性的 RGB 值,要被显示器正确显示的话,还需要进行 gamma 校正。每个 RGB 空间对应的 gamma 校正公式不完全一致,大多数情况下都是 C = C l i n 1 / γ C=C_{lin}^{1/\gamma} C=Clin1/γ,其中 γ = 2.2 γ=2.2 γ=2.2,少数情况,比如 Apple RGB 采用的是 $γ=1.8 $的情况,再比如上面选择的 sRGB 空间,采用了一种分段的非线性函数进行校正:
C = { 12.92 C l i n , C l i n ≤ 0.0031308 1.055 C l i n 1 / 2.4 − 0.055 , C l i n > 0.0031308 C = \begin{cases} 12.92C_{lin} &,C_{lin} \leq 0.0031308 \\ 1.055C_{lin}^{1/2.4} - 0.055 &,C_{lin} \gt 0.0031308 \end{cases} C={12.92Clin1.055Clin1/2.40.055,Clin0.0031308,Clin>0.0031308
在粗略的场景下,也可以直接使用 γ=2.2 的公式代替。

6. 代码实现

# coding=utf-8
import scipy.io as sio
import numpy as np
import cv2
import matplotlib.pyplot as plt
import os
import re


class GeneratorRGB:

    def __init__(self, wave_length):
        # 波长
        self.wavelengths = wave_length
        # self.transform_matrix = [[2.36461385, -0.89654057, -0.46807328],
        #                          [-0.51516621, 1.4264081, 0.0887581],
        #                          [0.0052037, -0.01440816, 1.00920446]]
		# 转换矩阵
        self.transform_matrix = [[3.1338561, -1.6168667, -0.4906146],
                                 [-0.9787684, 1.9161415, 0.0334540],
                                 [0.0719453, -0.2289914, 1.4052427]]
	# g(x;u,sigma1,sigma2)
    def piecewise_gaussian(self, x, u, sigma1, sigma2):
        return np.where(x < u, np.exp(-0.5 * (x - u) ** 2 / sigma1 ** 2), np.exp(-0.5 * (x - u) ** 2 / sigma2 ** 2))

    def x_gaussian(self, wavelength, adj=None):
        if not adj:
            adj = [{"u": 0, "sigma1": 0, "sigma2": 0},
                   {"u": 0, "sigma1": 0, "sigma2": 0},
                   {"u": 0, "sigma1": 0, "sigma2": 0}]
        result = 0.362 * self.piecewise_gaussian(wavelength,
                                                 442.0 + adj[0]["u"],
                                                 16.0 + adj[0]["sigma1"],
                                                 26.7 + adj[0]["sigma2"])
        result += -0.065 * self.piecewise_gaussian(wavelength,
                                                   501.1 + adj[1]["u"],
                                                   20.4 + adj[1]["sigma1"],
                                                   26.2 + adj[1]["sigma2"])
        result += 1.056 * self.piecewise_gaussian(wavelength,
                                                  599.8 + adj[2]["u"],
                                                  37.9 + adj[2]["sigma1"],
                                                  31.0 + adj[2]["sigma2"])
        return result

    def y_gaussian(self, wavelength, adj=None):
        if not adj:
            adj = [{"u": 0, "sigma1": 0, "sigma2": 0},
                   {"u": 0, "sigma1": 0, "sigma2": 0}]
        result = 0.286 * self.piecewise_gaussian(wavelength,
                                                 530.9 + adj[0]["u"],
                                                 16.3 + adj[0]["sigma1"],
                                                 31.1 + adj[0]["sigma2"])
        result += 0.821 * self.piecewise_gaussian(wavelength,
                                                  568.8 + adj[1]["u"],
                                                  46.9 + adj[1]["sigma1"],
                                                  40.5 + adj[1]["sigma2"])
        return result

    def z_gaussian(self, wavelength, adj: list = None):
        if not adj:
            adj = [{"u": 0, "sigma1": 0, "sigma2": 0},
                   {"u": 0, "sigma1": 0, "sigma2": 0}]
        result = 0.980 * self.piecewise_gaussian(wavelength,
                                                 437.0 + adj[0]["u"],
                                                 11.8 + adj[0]["sigma1"],
                                                 36.0 + adj[0]["sigma2"])
        result += 0.681 * self.piecewise_gaussian(wavelength,
                                                  459.0 + adj[1]["u"],
                                                  26.0 + adj[1]["sigma1"],
                                                  13.8 + adj[1]["sigma2"])
        return result

        # color matching function

    # 计算色匹配函数值
    def get_CIE_XYZ_weights(self, adj_x: list = None, adj_y: list = None, adj_z: list = None):
        cie_x = self.x_gaussian(self.wavelengths, adj=adj_x)
        cie_y = self.y_gaussian(self.wavelengths, adj=adj_y)
        cie_z = self.z_gaussian(self.wavelengths, adj=adj_z)
        return cie_x, cie_y, cie_z
	
    # 显示CIE-xyz色匹配函数曲线
    def show_weights_curve(self, adj_x: list = None, adj_y: list = None, adj_z: list = None):
        # adj_x = [{"u": 50, "sigma1": 0, "sigma2": 0},
        #          {"u": 50, "sigma1": 0, "sigma2": 0},
        #          {"u": 50, "sigma1": 0, "sigma2": 0}]
        #
        # adj_y = [{"u": -50, "sigma1": 0, "sigma2": 0},
        #          {"u": -50, "sigma1": 0, "sigma2": 0}]
        #
        # adj_z = [{"u": 0, "sigma1": 10, "sigma2": 10},
        #          {"u": 0, "sigma1": 10, "sigma2": 30}]
        # rgb_generator.show_weights_curve(adj_x=adj_x, adj_y=adj_y, adj_z=adj_z)
        cie_x, cie_y, cie_z = self.get_CIE_XYZ_weights(adj_x=adj_x, adj_y=adj_y, adj_z=adj_z)
        plt.figure("xyz_cmf")
        plt.xlabel("wave length/nm")
        plt.ylabel("value")
        plt.plot(self.wavelengths, cie_x, linewidth=1.5, color="r", label="x")
        plt.plot(self.wavelengths, cie_y, linewidth=1.5, color="g", label="y")
        plt.plot(self.wavelengths, cie_z, linewidth=1.5, color="b", label="z")
        plt.legend()
        plt.grid()
        plt.show()
	
    # 伽马校正
    def gamma_correction(self, rgb, gamma=1.5):
        rgb = np.power(rgb, 1 / gamma)
        return rgb
	# 将高光谱图像合成为RGB图像
    # 高光谱图像 宽width,高height,通道数channels
    # hyper_image.shape == (height,width,channels) 
    # adj_x,adj_y,adj_z,用来微调,u和sigma,改变xyz曲线的形状实现特殊效果
    def get_rgb(self, hyper_image, adj_x: list = None, adj_y: list = None, adj_z: list = None, BGR=True,
                gamma_correction=False):

        cie_x, cie_y, cie_z = self.get_CIE_XYZ_weights(adj_x=adj_x, adj_y=adj_y, adj_z=adj_z)
        X = np.sum(hyper_image * cie_x, axis=2)
        Y = np.sum(hyper_image * cie_y, axis=2)
        Z = np.sum(hyper_image * cie_z, axis=2)
        R = X * self.transform_matrix[0][0] + Y * self.transform_matrix[0][1] + Z * self.transform_matrix[0][2]
        G = X * self.transform_matrix[1][0] + Y * self.transform_matrix[1][1] + Z * self.transform_matrix[1][2]
        B = X * self.transform_matrix[2][0] + Y * self.transform_matrix[2][1] + Z * self.transform_matrix[2][2]
        if BGR:
            rgb_img = np.stack((B, G, R), axis=-1)
        else:
            rgb_img = np.stack((R, G, B), axis=-1)
        rgb_img = (rgb_img - np.min(rgb_img)) / (np.max(rgb_img) - np.min(rgb_img))
        if gamma_correction:
            rgb_img = self.gamma_correction(rgb_img)
        return rgb_img

# 根据txt波长信息生成对应的npy波长文件
def envitxt2npy(txt_path, npy_savepath):
    with open(txt_path) as f:
        lines = f.readlines()[3:]
        wavelengths = [float(re.findall(r"\d+\.?\d*", line)[0]) for line in lines]
    wavelengths = np.array(wavelengths)
    np.save(os.path.join(npy_savepath, "wavelengths_" + str(len(wavelengths)) + ".npy"), wavelengths)


if __name__ == "__main__":
    envitxt2npy("envi_plot.txt", ".")
    wavelengths = np.load("wavelengths_128.npy")
    # wavelengths_96 = wavelengths[31:223:2]
    rgb_generator = GeneratorRGB(wavelengths)

    rgb_generator.show_weights_curve()

7. 附录

波段信息txt文件,一共128个波段:

ENVI ASCII Plot File [*** *** 24 11:45:14 1919]
Column 1: Wavelength
Column 2: n_D Class #1~~2##255,0,0
  371.700012   778.943339
  376.100006   770.241712
  380.500000   748.032550
  385.000000   711.031947
  389.399994   706.342978
  393.899994   694.409283
  398.299988   698.135021
  402.799988   710.817360
  407.299988   727.958409
  411.799988   737.475588
  416.299988   739.506932
  420.700012   754.845690
  425.200012   753.913201
  429.799988   766.892706
  434.299988   799.750452
  438.799988   835.210970
  443.299988   893.353225
  447.899994   924.624473
  452.399994   948.472574
  457.000000   921.470766
  461.500000   918.262809
  466.100006   917.420735
  470.700012   922.870404
  475.299988   952.725136
  479.899994   976.078360
  484.399994  1012.474985
  489.100006  1050.302592
  493.700012  1181.345992
  498.299988  1346.992164
  502.899994  1583.062086
  507.500000  1964.079566
  512.200012  2337.871609
  516.799988  2608.419530
  521.500000  2934.751055
  526.200012  3094.039783
  530.799988  3225.940928
  535.500000  3279.060880
  540.200012  3196.213382
  544.900024  3166.150090
  549.599976  3102.237492
  554.299988  3030.236890
  559.000000  2949.843882
  563.700012  2992.290536
  568.500000  2944.970464
  573.200012  2879.842676
  577.900024  2709.165160
  582.700012  2544.176612
  587.400024  2243.330319
  592.200012  2080.393008
  597.000000  1939.819168
  601.799988  1797.521398
  606.500000  1670.897529
  611.299988  1568.100663
  616.099976  1483.772152
  621.000000  1448.660639
  625.799988  1376.030741
  630.599976  1329.355636
  635.400024  1293.602170
  640.299988  1251.915009
  645.099976  1221.805907
  650.000000  1174.126582
  654.799988  1124.404461
  659.700012  1131.710066
  664.599976  1119.727547
  669.400024  1103.228451
  674.299988  1090.617842
  679.200012  1080.449066
  684.099976  1026.330922
  689.099976   993.049427
  694.000000  1033.698614
  698.900024  1022.889090
  703.799988  1008.230862
  708.799988   998.568415
  713.700012   962.066305
  718.700012   888.371308
  723.599976   878.981314
  728.599976   866.410488
  733.599976   888.247137
  738.599976   897.895118
  743.599976   917.882459
  748.599976   911.596745
  753.599976   914.708258
  758.599976   771.996986
  763.599976   730.689572
  768.599976   847.165160
  773.700012   855.122363
  778.700012   836.664858
  783.799988   827.171790
  788.799988   806.916817
  793.900024   790.221820
  798.900024   789.949367
  804.000000   809.836649
  809.099976   807.355033
  814.200012   784.625075
  819.299988   769.038577
  824.400024   786.312839
  829.500000   788.345389
  834.700012   806.656420
  839.799988   826.106088
  844.900024   827.244123
  850.099976   827.270645
  855.200012   816.968053
  860.400024   824.337553
  865.500000   814.603978
  870.700012   798.827004
  875.900024   796.328511
  881.099976   787.040386
  886.299988   772.019289
  891.500000   761.085594
  896.700012   742.569620
  901.900024   697.479204
  907.099976   697.937312
  912.400024   680.795660
  917.599976   674.689572
  922.900024   671.657625
  928.099976   671.411694
  933.400024   649.347197
  938.700012   619.044605
  943.900024   624.757083
  949.200012   619.104882
  954.500000   621.953586
  959.799988   610.510549
  965.099976   612.142857
  970.400024   613.606992
  975.700012   621.637734
  981.099976   613.901145
  986.400024   615.367691
  991.700012   616.359253
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何科学地利用高光谱图像合成真彩色RGB图像? 的相关文章

随机推荐

  • ElementUI表格错位问题

    最近一个项目需要用到表格 为了图省事直接用的ElementUI组件 使用默认的参数在表格所在的容器大小变化时会发生错位问题 如下图所示 网上的一些方法基本都试过了 没啥作用 可能是方式不对 最后查询ElementUI文档 在el table
  • 开关稳压电源设计

    文末下载完整资料 摘要 本设计应用隔离型回扫式DC DC电源变换技术完成开关稳压电源的设计及制作 系统主要由整流滤波电路 DC DC变换电路 单片机显示与控制电路三部分组成 开关电源的集成控制由脉宽调制控制芯片UC3843及相关电路完成 利
  • linux编程第一部分总结

    C 多线程安全原则 对象析构很复杂 我们采用shared ptr和weak ptr来做 enable shared from this lt gt 是用来做回调的 因为多线程中可能对象的生命周期比传出去的this指针短 同时为了不延长对象的
  • 碎片笔记

    前言 与传统的AI攻防 后门攻击 对抗样本 投毒攻击等 不同 如今的大模型攻防涉及以下多个方面的内容 目录 一 大模型的可信问题 1 1 虚假内容生成 1 2 隐私泄露 二 大模型的安全问题 2 1 模型窃取攻击 2 2 数据窃取攻击 2
  • python-ue4-metahuman-nerf:我创造了一个数字人!!

    原文 https zhuanlan zhihu com p 561152870 目录 收起 1 准备工作 制作 MetaHuman 角色 1 1 创建 MetaHuman 角色 1 2 Quixel Bridge 下载 MetaHuman
  • android 恢复出厂设置流程分析,Android恢复出厂设置流程分析

    最近看恢复出厂的一个问题 以前也查过这方面的流程 所以这里整理一些AP framework层的流程 在setting gt 备份与重置 gt 恢复出厂设置 gt 重置手机 gt 清除全部内容 gt 手机关机 gt 开机 gt 进行恢复出厂的
  • unity 五种旋转方式localEulerAngles、eulerAngles、rotation、localRotation和Rotate的区别

    1 1 transform localEulerAngles 使用localEulerAngles进行旋转的时候 我们要使用transform localEulerAngles new Vector3 x y z 其中 new Vector
  • 矩阵 行列式的计算

    行列式要求 要计算行列式 那么这个矩阵一定是一个方阵 行列式性质 行列式转置后值不变 互换行列式中两行 值变为相反数 行列式中两行成比例 行列式为0 行列式中一行所有元素乘以一个数后加到另一行 行列式值不变 行列式的计算有很多方法 矩阵的行
  • GPT专业应用:自动撰写宣传稿

    图片由Lexica 生成 输入 Staff working on product promotion 宣传稿是指按照有关政策文件或相关精神 以宣传某种主张 某项工作 某件事情等为目的 为获得理解 支持而撰写的应用文 基本格式包含四个要素 分
  • React 初学 - 使用 If/Else 条件进行渲染以及使用 && 获得更简洁的条件- 个人笔记50

    MyComponent 的 state 中包含一个布尔值 用于跟踪是否要在 UI 中显示某个元素 按钮切换此值的状态 目前 它每次都呈现相同的 UI 用if else语句重写render 方法 如果display为true则返回当前标记 否
  • CARLA平台+Q-learning的尝试(gym-carla)

    接触强化学习大概有半年了 也了解了一些算法 一些简单的算法在gym框架也实现了 那么结合仿真平台Carla该怎么用呢 由于比较熟悉gym框架 就偷个懒先从这个开始写代码 项目地址 https github com cjy1992 gym c
  • 3、上台阶问题

    问题描述 有n级楼梯 有2种爬法 1次1级 2级 n级楼梯有多少种爬法 解决思路 n 1 1种爬法 n 2 2种爬法 n 3 第一次爬1级 有2种爬法 第一次爬2级 有1种爬法 共3种爬法 第n次爬楼梯 f n f n 1 f n 1 代码
  • 成功解决ubuntu-22.04的sudo apt-get update一直卡在【0% [Waiting for headers]】

    成功解决ubuntu 22 04的sudo apt get update一直卡在 0 Waiting for headers 问题描述 解决方案 问题描述 在下载安装包的时候一直卡在0 Waiting for headers 报错信息如下
  • 【动态内存管理】

    目录 前言 一 动态内存开辟函数 一 malloc 二 free 三 calloc 四 realloc 二 常见错误 一 对NULL指针解引用 二 对动态开辟空间的越界访问 三 对动态开辟内存多次free 四 未在初始位置进行free 五
  • 软件技术国产化

    软件技术国产化 如果大家做的项目是涉及国企 政府 校园的 应该都有听过 技术国产化 其实不单单是软件开发这一块 其它行业也会有这一说法 自从中美之间发生贸易战 美国对中国一些企业进行制裁 甚至封杀 像我们软件开发这行 会限制一些开发工具 技
  • 【面试题】java常考面试题

    java中sleep方法和wait方法的区别 sleep是线程中的方法 但是wait是Object中的方法 sleep方法不会释放锁 但是wait会释放锁 sleep方法不依赖于同步器synchronized 但是wait需要依赖synch
  • 进程-进程标识符

    什么是进程标识符 系统给每个进程定义了一个唯一标识该进程的非负正数 称作进程标识符 进程标识符可以简单的表示为主进程表中的一个索引 当某一进程终止后 其标识符可以重新用作另一进程的标识符 不过 在任何时刻 一个标识符所代表的进程是唯一的 系
  • 在VMware Workstation Pro中安装Windows 11正式版(包括添加TPM 2.0支持,而不是忽略)

    目录 0 首先检查Windows 11需要的环境 1 创建一个虚拟机 1 1 选择使用下载好的Windows11镜像 1 2 选择操作系统为Windows 10 x64 1 3 给虚拟机系统起个名字并指定存放路径 1 4 把创建的虚拟硬盘大
  • JDBC程序具体实现步骤演示

    再熟悉JDBC的编程步骤后 接下来通过一个案例并依照上一小节所讲解的步骤来演示JDBC的使用 此案例会从tb user表中读取数据 并将结果打印在控制台 需要说明的是 Java中的JDBC是用来连接数据库从而执行相关数据相关操作的 因此在使
  • 如何科学地利用高光谱图像合成真彩色RGB图像?

    如何科学地利用高光谱图像合成真彩色RGB图像 1 前言 参考链接 色匹配函数是什么 知乎 zhihu com 23 颜色知识1 人类的视觉系统与颜色 知乎 zhihu com 色彩空间基础 知乎 zhihu com 色彩空间表示与转换 知乎