拉普拉斯金字塔的频谱分析

1. 基本分析

拉普拉斯金字塔分解,主要由以下步骤组成:

  1. 对输入图像 L0 进行低通滤波,其中常采用高斯滤波;
  2. 对低通滤波后的图像进行 1/2 倍率的下采样,这里的下采样通常是指直接取偶行且偶列(以 0 开始计)的像素,获得低频图像 L1;
  3. 对低频图像 L1 进行 2 倍的插零上采样,等价于直接将第 1 步的低通滤波图像的奇行或奇列像素置零;
  4. 对第 3 步上采样所得图像进行低通滤波,注意此处的低通滤波方法可与第 1 步的不一样;
  5. 输入图像减去第 4 步的低通滤波图像,即可获得输入图像的高频图像 H0;
  6. 如果对第 2 步所得低频图像 L1 重复以上步骤,即可获得 L1 的低频图像 L2 与高频图像 H1;
  7. 因为 H0 的尺寸为输入尺寸,H1 的尺寸为输入尺寸的 1/2x1/2,L2 的尺寸为输入图像的 1/4x1/4,将 H0, H1, L2 按顺序堆叠起来,就形成一个金字塔的形状,我们称之为拉普拉斯金字塔;如果对 L2 继续分解,还可获得更高层次的金字塔;
  8. 仅凭 H0, H1, L2 就能无损地恢复输入图像 L0,这是显而易见的,将 L2 进行插零上采样以及与第 4 步相同的低通滤波后,与 H1 相加即可无损恢复到 L1,同理即有 L0;
  9. 因为 H0 是 L0 的高频,H1 是 L1 的高频,L2 是 L1 的低频,我们可以将 H0,H1, L2 分别称为输入图像的高频、中频、低频分量。

在以上拉普拉斯金字塔分解方法中,具体低/中/高频的意义并没有定量的描述。为此,我们可以基于傅里叶变换进行分析,因为以上的步骤都可以在频域通过简单的处理得到等价的结果。

图 1 图像下采样示例

首先看第 1 步低通滤波的必要性,因为在硬件中低通滤波需要用到 linebuffer,如果能够不滤波直接下采样是最好的。如图 1 所示,上行的左列是输入图像,这里为了突出高频分量的变化使用了比较极端的示例,中列是左列直接(不进行低通滤波)下采样再上采样的图像,其中只有偶行且偶列的像素是有效的,右列是左列偶行且偶列像素组成的图像,通过补零填充到一样的大小;下行的左列图像则是输入图像经过高斯低通滤波的结果,中列和右列的处理和上行一样。图 2 是图 1 各图像对应的离散傅里叶变换(DFT)结果,其中每个 DFT 图像的中心对应着低频分量,越往外则是高频分量,越亮代表越大的幅度。这里的频域分析涉及到一些数字信号处理的知识。简单地说,经过下采样以及上采样,中列图像的 DFT 是左列图像 DFT 经过 1/2 周期延拓并叠加的结果,这就会导致图像的高频分量部分发生混叠,造成一定的信号失真;右列图像的 DFT 是中列图像 DFT 中心 1/4 区域放大两倍的结果。

图 2 图 1 所示图像的 DFT

因为高斯滤波等价于在频域中与高斯函数相乘,所以输入图像经过低通滤波后,其高频分量有所衰减,可以从图 2 左下角看到一个弥散圆的轮廓,其半径由高斯滤波核的方差决定,方差越大也就是滤波核半径越大,此时频域中的弥散圆半径反而越小,即有更多的高频分量被衰减。可以看到,原图像(左上角)由于纹理比较丰富,所以在高频区域也有较大的幅度。如果不进行低通滤波而直接下采样(右上角),其 DFT 相比于低通滤波后下采样(右下角)可以保留更多的高频分量,这似乎是更好的选择。但问题在于,右上角虽然保留了更多的高频分量,但相较于左上角(原图)有很大一部分高频分量是不一致的,这首先要明白右列的 DFT 只是中列 DFT 中心 1/4 区域放大的结果,也就是说左列 DFT 中心 1/4 区域以外的高频分量已经被混叠到中心 1/4 区域而消失了。对于右下角,尽管高频分量损失了很多,但正因此没有因为下采样而发生混叠,我们看到的只是一幅相对模糊的图像;而对于右上角,因为混叠而可能出现高频分量一部分被衰减而另一部分被增强的情况,反而会导致图像产生很多意想不到的伪纹理,其中主要是锯齿等等。因此,我们倾向于在下采样前首先进行低通滤波。

不过要注意的是,即便我们不进行低通滤波而直接下采样,也照样可以执行拉普拉斯分解的余下步骤,得到相应的高频图像。只要高频图像的内容不发生改变,我们就可以无损地恢复到原图像,和下采样之前是否进行低通滤波并无关系。但问题也出在此处,例如当我们需要进行图像降噪的任务时,高频分量往往是被抑制的,而最极端的情况就是拉普拉斯分解所得的高频图像完全被消除,那么重构图像只取决于下采样所得图像,这自然地又回到了前面所说的高频混叠问题。因此从实际应用的角度出发,下采样之前的低通滤波是必不可少的。另外要注意的是,低通滤波的具体实现有很多种选择,常用的包括高斯滤波与均值滤波等等。高斯滤波的优点在于其在频域同样是高斯函数,因此其幅度曲线十分平滑,不会出现均值滤波所具有的高频区域震荡;缺点是在同样的滤波核长度下对于中低频分量的衰减幅度要低于均值滤波。关于滤波核长度为 5 的高斯滤波与均值滤波的频谱曲线如图 3 所示。

图 3 高斯滤波与均值滤波的频谱曲线

在理解了为什么要在下采样之前进行低通滤波后,我们还要理解拉普拉斯分解第 4 步中为什么上采样后还要进行一次低通滤波。回到图 1,经过第 3 步的上采样后,我们得到的图像的奇行或奇列都是 0,这时我们不能直接与原图像相减,否则得到的结果就是偶行且偶列的像素几乎为 0,而奇行或奇列的像素等同于原图像像素,因此我们需要一个插值的步骤。图像插值有很多种方法,包括最近邻插值、双线性插值等等,但是这些插值方法对于频域的分析不太方便。如果对数字信号处理比较熟悉,我们就知道离散信号可通过低通滤波实现线性内插。具体地,我们可以发现图 2 的中列图像的 DFT 中心 1/4 区域与左列图像的 DFT 十分相像,只是在四个角落以及四边中点出现了与中心重复的 DFT 分量,而这些重复的 DFT 分量正是上采样图像的奇行或奇列为 0 的原因,因此我们只要使用一个理想的低通滤波器把重复的 DFT 分量去除,只保留中心 1/4 区域的 DFT 分量,就能把图 1 的中列图像恢复到左列图像,当然已经发生混叠的高频分量是无法恢复的。由于理想低通滤波器需要在频域进行操作,而在实际应用中我们不可能有足够的算力把图像转换到频域,所以一般在时域使用普通的低通滤波器即可,例如最常用的也是高斯滤波。

图 4 低通滤波实现线性内插示例

如图 4 所示,上行的左列及中列图像为图 1 下行的左列及中列,而右列为中列图像经过高斯滤波的结果,图中下行即为三者对应的 DFT 图像。可以看到,只需一个简单的高斯滤波,即可实现上采样图像中奇行或奇列像素的插值,得到的结果除了稍微模糊以外与下采样之前的图像并没有太大的区别,而稍微模糊的原因也是由于此处的高斯滤波同样会导致一部分的高频信号衰减。实际上,如前面所述使用其他的插值方法比如最近邻插值也是可行的,只是最近邻插值不是一种零相位滤波器,其对于频谱的影响要比高斯滤波等零相位滤波器要复杂得多,并且容易导致锯齿以及伪纹理的产生。实际上,如果考虑长度为 3 的高斯滤波核即 [1, 2, 1],我们可以发现此时高斯滤波插值的结果和双线性插值是一样的,这个只需简单推理即可。相比于双线性插值,高斯滤波的优点是可以轻松地扩展滤波核的长度,从而灵活地调整高频分量衰减的范围,当然代价就是其所需的计算复杂度要更高一些。至此,我们就理解了拉普拉斯分解第 4 步上采样后进行低通滤波的意义。

图 5 拉普拉斯分解的高频图像示例

可以看到,拉普拉斯分解需要进行两次低通滤波,每一次滤波都会导致一部分高频分量衰减,因此第 5 步的原图像与最后一次低通滤波图像的相减就是要提取损失的高频分量。如图 5 所示,左列是原图像及其 DFT,中列是拉普拉斯分解第 4 步所得图像及其 DFT,右列是第 5 步所得高频图像及其 DFT。从右上角可以看出,高频图像主要对应着原图像的边缘和纹理,这是一个十分良好的性质,因为人眼主观感受系统往往更加喜欢锐利的边缘,所以我们在进行图像处理,如降噪时,可以对低频图像应用更高的降噪强度以获得更加平滑的背景,而对高频图像应用相对更弱的降噪强度,尽可能保证图像边缘细节的锐度,这样就能获得更好的主观降噪质量。实际上拉普拉斯分解的名字来自拉普拉斯算子,即二阶微分算子,对图像进行二阶微分同样能够实现边缘提取,因此我们常把能够提取图像边缘的方法称为拉普拉斯方法,尽管不一定需要用到二阶微分。

在很多应用中,单层的拉普拉斯分解并不满足我们对于不同尺度纹理的质量把控,这是因为有些大尺度的纹理在计算机看来也是属于低频内容。这里涉及到一个算法的可视域,也就是算法处理当前像素时能够访问的邻域像素的范围,当我们把图像不断缩小,算法的可视域就会越来越大,这样才能发现更多大尺度的信息。举个例子,一张白纸挡在面前,我们只会看到白茫茫的一片,没有任何细节,而当我们把白纸拿远一点,白纸占据的视野面积就会越来越小,最后我们就能发现白纸的四周是有边缘以及拐角的。因此,当我们完成单层的拉普拉斯分解后,如果对下采样所得低频图像继续分解,那么在继续分解所得的低频图像及高频图像上的算法处理,就等价于在一个更大的可视域上对原图像进行处理,这往往可以获得更好的主观效果,这就是为什么我们要使用拉普拉斯金字塔的原因。如图 6 所示,当我们进行两次拉普拉斯分解以后,分别可获得第一次分解所得高频图像 H0,第二次分解所得高频图像 H1,以及第二次分解所得低频图像 L2,它们的 DFT 图像刚好大致对应了原图像 DFT 的外沿带,中间带,以及中心区,也就是 H0 主要对应了原图像的极高频分量,H1 主要对应了原图像的中高频分量,L2 主要对应了原图像的中低频分量。由此,我们可简单地将 H0,H1,L2 分别称为原图像的高频、中频以及低频分量。

图 6 两次拉普拉斯分解金字塔示例

2. 测试脚本

# -*- coding: utf-8 -*-
import numpy as np
import cv2

def periodic_gaussian_blur(img, ksize, sigma=0, ktype=0):
    kr = ksize // 2
    h, w = img.shape[:2]
    '''
    # mannual wrap padding
    tmp = np.zeros([h+2*kr, w+2*kr], dtype=img.dtype)
    tmp[kr:h+kr, kr:w+kr] = img
    tmp[kr:h+kr, :kr] = img[:, -kr:]
    tmp[kr:h+kr, -kr:] = img[:, :kr]
    tmp[:kr,  :] = tmp[-2*kr:-kr, :]
    tmp[-kr:, :] = tmp[kr:2*kr,   :]
    '''
    tmp = np.pad(img, ((kr, kr), (kr, kr)), 'wrap')
    if ktype == 0:
        tmp = cv2.GaussianBlur(tmp, (ksize, ksize), sigma)
    else:
        tmp = cv2.boxFilter(tmp, -1, (ksize, ksize), normalize=True)
    img = tmp[kr:h+kr, kr:w+kr]
    return img

ksize = 5
sigma = 0
lvs = 2

img = cv2.imread('test2.png', 0).astype('float32') - 128
np.random.seed(0)
#img = img + np.random.randn(*img.shape) * 30

eps = 1e-15
vmax = 50000
freqs = []
valus = []

for i in range(lvs):
    h, w = img.shape[:2]
    fft_img = np.fft.fft2(img)
    fft_img = np.fft.fftshift(fft_img)
    abs_img = np.abs(fft_img)
    abs_img = np.clip(abs_img + eps, 0, vmax)

    dns1 = np.zeros_like(img)
    dns1[::2, ::2] = img[::2, ::2] * 4
    fft_dns1 = np.fft.fft2(dns1)
    fft_dns1 = np.fft.fftshift(fft_dns1)
    abs_dns1 = np.abs(fft_dns1)
    abs_dns1 = np.clip(abs_dns1 + eps, 0, vmax)

    dns2 = np.zeros_like(img)
    dns2[:h//2, :w//2] = img[::2, ::2] * 4
    fft_dns2 = np.fft.fft2(dns2)
    fft_dns2 = np.fft.fftshift(fft_dns2)
    abs_dns2 = np.abs(fft_dns2)
    abs_dns2 = np.clip(abs_dns2 + eps, 0, vmax)

    gau = periodic_gaussian_blur(img, ksize, sigma)
    fft_gau = np.fft.fft2(gau)
    fft_gau = np.fft.fftshift(fft_gau)
    abs_gau = np.abs(fft_gau)
    abs_gau = np.clip(abs_gau + eps, 0, vmax)

    dng1 = np.zeros_like(gau)
    dng1[::2, ::2] = gau[::2, ::2] * 4
    fft_dng1 = np.fft.fft2(dng1)
    fft_dng1 = np.fft.fftshift(fft_dng1)
    abs_dng1 = np.abs(fft_dng1)
    abs_dng1 = np.clip(abs_dng1 + eps, 0, vmax)

    dng2 = np.zeros_like(gau)
    dng2[:h//2, :w//2] = gau[::2, ::2] * 4
    fft_dng2 = np.fft.fft2(dng2)
    fft_dng2 = np.fft.fftshift(fft_dng2)
    abs_dng2 = np.abs(fft_dng2)
    abs_dng2 = np.clip(abs_dng2 + eps, 0, vmax)

    disp1 = np.hstack((img, dns1, dns2))
    disp2 = np.hstack((gau, dng1, dng2))
    disp = np.vstack((disp1, disp2))
    disp = np.clip(disp + 128.5, 0, 255).astype('uint8')
    cv2.imwrite('img_down_{}.png'.format(i), disp)

    disp1 = np.hstack((abs_img, abs_dns1, abs_dns2))
    disp2 = np.hstack((abs_gau, abs_dng1, abs_dng2))
    disp = np.vstack((disp1, disp2))
    disp = np.clip(disp, 0, vmax)
    disp = (disp / vmax * 255 + 0.5).astype('uint8')
    cv2.imwrite('fft_down_{}.png'.format(i), disp)

    upg1 = periodic_gaussian_blur(dng1, ksize, sigma)
    fft_upg1 = np.fft.fft2(upg1)
    fft_upg1 = np.fft.fftshift(fft_upg1)
    abs_upg1 = np.abs(fft_upg1)
    abs_upg1 = np.clip(abs_upg1 + eps, 0, vmax)

    disp1 = np.hstack((gau, dng1, upg1)) + 128.5
    disp2 = np.hstack((abs_gau, abs_dng1, abs_upg1)) / vmax * 255 + 0.5
    disp = np.vstack((disp1, disp2))
    disp = np.clip(disp, 0, 255).astype('uint8')
    cv2.imwrite('gau_up_{}.png'.format(i), disp)

    dif1 = img - upg1
    fft_dif1 = np.fft.fft2(dif1)
    fft_dif1 = np.fft.fftshift(fft_dif1)
    abs_dif1 = np.abs(fft_dif1)
    abs_dif1 = np.clip(abs_dif1 + eps, 0, vmax)

    if i == 0:
        freqs.append(abs_dif1)
        valus.append(np.abs(dif1))
    else:
        freq = np.zeros_like(freqs[0])
        valu = np.zeros_like(valus[0])
        h0, w0 = freq.shape[:2]
        freq[::(2**(i)), ::(2**(i))] = dif1 * (4**i)
        fft_freq1 = np.fft.fft2(freq)
        fft_freq1 = np.fft.fftshift(fft_freq1)
        abs_freq1 = np.abs(fft_freq1)
        abs_freq1 = np.clip(abs_freq1 + eps, 0, vmax)
        freq *= 0
        freq[h0//2-h//2:h0//2-h//2+h, w0//2-w//2:w0//2-w//2+w] = abs_freq1[h0//2-h//2:h0//2-h//2+h, w0//2-w//2:w0//2-w//2+w]
        freqs.append(freq)
        valu[h0//2-h//2:h0//2-h//2+h, w0//2-w//2:w0//2-w//2+w] = np.abs(dif1)
        valus.append(valu)
    if i == lvs - 1:
        freq = np.zeros_like(freqs[0])
        valu = np.zeros_like(valus[0])
        freq[::(2**(i+1)), ::(2**(i+1))] = gau[::2, ::2] * (4**(i+1))
        fft_freq1 = np.fft.fft2(freq)
        fft_freq1 = np.fft.fftshift(fft_freq1)
        abs_freq1 = np.abs(fft_freq1)
        abs_freq1 = np.clip(abs_freq1 + eps, 0, vmax)
        freq *= 0
        freq[h0//2-h//4:h0//2-h//4+h//2, w0//2-w//4:w0//2-w//4+w//2] = abs_freq1[h0//2-h//4:h0//2-h//4+h//2, w0//2-w//4:w0//2-w//4+w//2]
        freqs.append(freq)
        valu[h0//2-h//4:h0//2-h//4+h//2, w0//2-w//4:w0//2-w//4+w//2] = gau[::2, ::2] + 128
        valus.append(valu)

    disp1 = np.hstack((img+128, upg1+128, np.abs(dif1))) + 0.5
    disp2 = np.hstack((abs_img, abs_upg1, abs_dif1)) / vmax * 255 + 0.5
    disp = np.vstack((disp1, disp2))
    disp = np.clip(disp, 0, 255).astype('uint8')
    cv2.imwrite('diff_{}.png'.format(i), disp)

    img = gau[::2, ::2]

disp1 = np.hstack(tuple(valus)) + 0.5
disp2 = np.hstack(tuple(freqs)) / vmax * 255 + 0.5
disp = np.vstack((disp1, disp2))
disp = np.clip(disp, 0, 255).astype('uint8')
cv2.imwrite('diff_low.png', disp)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/549108.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

惯用Python的5个技巧(循环)

在这篇文章中,你将看到5种方法可以使你的python循环更习惯,运行得更快,内存效率更高。 在我看来,Python是计算机科学中最简单、最通用的语言之一。如果你正确地编写python代码,很难区分python代码和伪代码。但有时&…

免单优选电商模式:激发购买欲望的创新销售策略

免单优选电商模式,作为一种创新的销售策略,其核心在于通过价格优惠、渐进式激励和社交网络结合,有效刺激消费者的购买行为,进而推动销售业绩的快速增长。 一、合法合规,规避多层次奖励风险 该模式坚持合法合规的运营原…

【从浅学到熟知Linux】进程控制下篇=>进程程序替换与简易Shell实现(含替换原理、execve、execvp等接口详解)

🏠关于专栏:Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程等内容。 🎯每天努力一点点,技术变化看得见 文章目录 进程程序替换什么是程序替换及其原理替换函数execlexeclpexecleexecvexecvpexecvpeexecve 替换函数总结实现…

3D视觉引导麻袋拆垛破包 | 某大型化工厂

客户需求 此项目为大型化工厂,客户现场每日有大量麻袋拆垛破包需求,麻袋软包由于自身易变形、码放垛型不规则、运输后松散等情况,无法依靠机器人示教位置完成拆垛。客户遂引入3D视觉进行自动化改造。 工作流程: 3D视觉对紧密贴合…

公司文件加密软件有监视功能吗?

公司文件加密软件不仅提供了强大的文件加密能力,还具备了监视功能,确保文件在使用过程中的安全性。华企盾DSC数据防泄密系统中的监控功能体现在以下几个方面: 加密文件操作日志:记录所有加密文件的申请、审批、扫描加解密、自动备…

数据分析

数据分析流程 数据分析开发流程一般分为下面5个阶段,主要包含:数据采集、数据处理、数据建模、数据分析、数据可视化 数据采集: 数据通常来自于企业内部或外部,企业内部数据可以直接从系统获得,外部数据则需要购买&a…

【面试经典 150 | 链表】删除链表的倒数第 N 个结点

文章目录 写在前面Tag题目来源解题思路方法一:统计节点个数方法二:双指针 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对于本…

Python 爬虫:如何用 BeautifulSoup 爬取网页数据

在网络时代,数据是最宝贵的资源之一。而爬虫技术就是一种获取数据的重要手段。Python 作为一门高效、易学、易用的编程语言,自然成为了爬虫技术的首选语言之一。而 BeautifulSoup 则是 Python 中最常用的爬虫库之一,它能够帮助我们快速、简单…

【Java探索之旅】数组使用 初探JVM内存布局

🎥 屿小夏 : 个人主页 🔥个人专栏 : Java编程秘籍 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一、数组的使用1.1 元素访问1.2 数组遍历 二、JVM的内存布局🌤️全篇总结 …

Java面试题目和答案【终极篇】

Java面向对象有哪些特征,如何应用 ​ 面向对象编程是利用类和对象编程的一种思想。万物可归类,类是对于世界事物的高度抽象 ,不同的事物之间有不同的关系 ,一个类自身与外界的封装关系,一个父类和子类的继承关系, 一个类和多个类的多态关系。万物皆对象,对象是具体的世…

Linux 删除文件或文件夹命令(新手)

一、删除文件夹 rm -rf 路径/目录名 1 强制删除文件夹及其子文件。 二、删除文件/文件夹:rm 命令 rm 删除命令,它可以永久删除文件系统中指定的文件或目录。 rm [选项] 文件或目录 选项: -f:强制删除(force&am…

我们试用了6款最佳Appium替代工具,有些甚至比Appium更好

Appium是一款知名的自动化测试工具,用于在iOS、Android和Windows等移动平台上运行测试。就开源移动测试自动化工具而言,虽然替代品有限,但它们确实存在。我们找到了一些优秀的Appium替代品,它们也可以满足自动化测试要求&#xff…

聚道云软件连接器助力医疗器械有限公司打通金蝶云星辰与飞书

摘要 聚道云软件连接器成功将金蝶云星辰与飞书实现无缝对接,为某医疗器械有限公司解决采购订单、付款单同步、审批结果回传、报错推送等难题,实现数字化转型升级。 客户介绍 某医疗器械有限公司是一家集研发、生产、销售为一体的综合性医疗器械企业。…

BackTrader 中文文档(一)

原文:www.backtrader.com/ 主页 欢迎来到 backtrader! 原文:www.backtrader.com/ 一个功能丰富的 Python 框架,用于回测和交易 backtrader允许您专注于编写可重复使用的交易策略、指标和分析器,而不必花时间构建基础…

打一把王者的时间,学会web页面测试方法与测试用例编写

一、输入框 1、字符型输入框: (1)字符型输入框:英文全角、英文半角、数字、空或者空格、特殊字符“~!#¥%……&*?[]{}”特别要注意单引号和&符号。禁止直接输入特殊字符时,…

Web App 入门指南:构建预测模型 App 的利器(shiny)

Web App 入门指南:构建预测模型 App 的利器 简介 近年来,随着机器学习和人工智能技术的快速发展,预测模型在各行各业得到了广泛应用。为了方便地部署和使用预测模型,将模型构建成 Web App 是一种非常好的选择。Web App 无需下载…

27.8k Star,AI智能体项目GPT Pilot:第一个真正的人工智能开发者(附部署视频教程)

作者:Aitrainee | AI进修生 排版太难了,请点击这里查看原文:27.8k Star,AI智能体项目GPT Pilot:第一个真正的人工智能开发者(附部署视频教程) 今天介绍一下一个人工智能智能体的项目GPT Pilot。…

Postman 环境变量配置初始调用登录脚本赋值Token

效果 新建环境 切换 Environments 标签下 点击上面加号增加环境变量 使用环境变量 使用{{变量名}}引用变量使用 Pre-request Script 全局 一般授权接口都需要再调用接口前,进行登录授权,这里使用了全局的请求前脚本调用。 脚本示例 // 基础地址 var…

前端跨域怎么办?

如果网上搜到的方法都不可行或者比较麻烦,可以尝试改变浏览器的设置(仅为临时方案) 1.新建一个Chrome浏览器的快捷方式 2.鼠标右键,进入属性,将以下命令复制粘贴到目标位置(可根据Chrome实际存放位置修改…

数据结构DAY4--哈希表

哈希表 概念:相当于字典,可以根据数据的关键字来寻找相关数据的查找表。 步骤:建立->插入->遍历->查找->销毁 建立 建立数据,形式随意,但一般为结构体(储存的数据量大)&#xff…