opencv之傅里叶变换

news2024/11/16 12:56:37

文章目录

  • 前言
  • 理论基础
  • Numpy实现傅里叶变换
    • 实现傅里叶变换
    • 实现逆傅里叶变换
  • 高通滤波示例
  • OpenCV实现傅里叶变换
    • 实现傅里叶变换
    • 实现逆傅里叶变换
  • 低通滤波示例


前言

图像处理一般分为空间域处理和频率域处理。

空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰度变换和空间滤波两种形式。灰度变换是对图像内的单个像素进行处理,比如调节对比度和处理阈值等。空间滤波涉及图像质量的改变,例如图像平滑处理。空间域处理的计算简单方便,运算速度更快。

频率域处理是先将图像变换到频率域,然后在频率域对图像进行处理,最后再通过反变换将图像从频率域变换到空间域。傅里叶变换是应用最广泛的一种频域变换,它能够将图像从空间域变换到频率域,而逆傅里叶变换能够将频率域信息变换到空间域内。傅里叶变换在图像处理领域内有着非常重要的作用。

理论基础

傅里叶变换非常抽象,很多人在工程中用了很多年的傅里叶变换也没有彻底理解傅里叶变换到底是怎么回事。为了更好地说明傅里叶变换,我们先看一个生活中的例子。

表1所示的是某饮料的配方,该配方是一个以时间形式表示的表格,表格很长,这里仅仅截取了其中的一部分内容。该表中记录了从时刻“00:00”开始到某个特定时间“00:11”内的操作。
在这里插入图片描述

表1

仔细分析该表格可以发现,该配方:

  • 每隔1分钟放1块冰糖。
  • 每隔2分钟放3粒红豆。
  • 每隔3分钟放2粒绿豆。
  • 每隔4分钟放4块西红柿。
  • 每隔5分钟放1杯纯净水。

上述文字是从操作频率的角度对配方的说明。

在数据的处理过程中,经常使用图表的形式表述信息。如果从时域的角度,该配方表可以表示为图1。图1仅仅展示了配方的前11分钟的操作,如果要完整地表示配方的操作,必须用图表绘制出全部时间内的操作步骤。
在这里插入图片描述

图1

如果从频率(周期)的角度表示,这个配方表可以表示为图2,图中横坐标是周期(频率的倒数),纵坐标是配料的份数。可以看到,图2可以完整地表示该配方的操作过程。
在这里插入图片描述

图2

对于函数,同样可以将其从时域变换到频域。图3是一个频率为5(1秒内5个周期)、振幅为1的正弦曲线。
在这里插入图片描述

图3

如果从频率的角度考虑,则可以将其绘制为图4所示的频域图,图中横坐标是频率,纵坐标是振幅。
在这里插入图片描述

图4

图3与图4是等价的,它们是同一个函数的不同表示形式。可以通过频域表示得到对应的时域表示,也可以通过时域表示得到对应的频域表示。法国数学家傅里叶指出,任何周期函数都可以表示为不同频率的正弦函数和的形式。在今天看来,这个理论是理所当然的,但是这个理论难以理解,在当时遭受了很大的质疑。

下面我们来看傅里叶变换的具体过程。例如,周期函数的曲线如图5左上角的图所示。该周期函数可以表示为:
在这里插入图片描述

图5

y = 3 ∗ n p . s i n ( 0.8 ∗ x ) + 7 ∗ n p . s i n ( 0.5 ∗ x ) + 2 ∗ n p . s i n ( 0.2 ∗ x ) y=3*np.sin(0.8*x) + 7*np.sin(0.5*x) + 2*np.sin(0.2*x) y=3np.sin(0.8x)+7np.sin(0.5x)+2np.sin(0.2x)

因此,该函数可以看成是由下列三个函数的和构成的:

  • y 1 = 3 ∗ n p . s i n ( 0.8 ∗ x ) y1=3*np.sin(0.8*x) y1=3np.sin(0.8x)(函数1)
  • y 2 = 7 ∗ n p . s i n ( 0.5 ∗ x ) y2=7*np.sin(0.5*x) y2=7np.sin(0.5x)(函数2)
  • y 3 = 2 ∗ n p . s i n ( 0.2 ∗ x ) y3=2*np.sin(0.2*x) y3=2np.sin(0.2x)(函数3)

上述三个函数对应的函数曲线分别如图5中右上角、左下角及右下角的图所示。如果从频域的角度考虑,上述三个正弦函数可以分别表示为图6中的三根柱子,图中横坐标是频率,纵坐标是振幅。
在这里插入图片描述

图6

通过以上分析可知,图5中左上角的函数曲线可以表示为图6所示的频域图。从图5左上角的时域函数图形,构造出如图6所示的频域图形的过程,就是傅里叶变换。图1与图2表示相同的信息,图1是时域图,而图2是频域图。图5左上角的时域函数图形,与图6所示的频域图形表示的页是完全相同的信息。傅里叶变换就是从频域的角度完整地表述时域信息。

除了上述的频率和振幅外,还要考虑时间差的问题。例如,饮料配方为了控制风味,需要严格控制加入配料的时间。表1中“00:00”时刻的操作,在更精细的控制下,实际上如表2所示。
在这里插入图片描述

表2

如果加入配料的时间发生了变化,饮料的风味就会发生变化。所以,在实际处理过程中,还要考虑时间差。这个时间差,在傅里叶变换里就是相位。相位表述的是与时间差相关的信息。

例如,图7中左上角图对应的函数可以表示为:
在这里插入图片描述

图7

y = 3 ∗ n p . s i n ( 0.8 ∗ x ) + 7 ∗ n p . s i n ( 0.5 ∗ x + 2 ) + 2 ∗ n p . s i n ( 0.2 ∗ x + 3 ) y=3*np.sin(0.8*x) + 7*np.sin(0.5*x+2) + 2*np.sin(0.2*x+3) y=3np.sin(0.8x)+7np.sin(0.5x+2)+2np.sin(0.2x+3)

因此,该函数可以看成是由下列3个函数的和构成的:

  • y 1 = 3 ∗ n p . s i n ( 0.8 ∗ x ) y1=3*np.sin(0.8*x) y1=3np.sin(0.8x)(函数1)
  • y 2 = 7 ∗ n p . s i n ( 0.5 ∗ x + 2 ) y2=7*np.sin(0.5*x+2) y2=7np.sin(0.5x+2)(函数2)
  • y 3 = 2 ∗ n p . s i n ( 0.2 ∗ x + 3 ) y3=2*np.sin(0.2*x+3) y3=2np.sin(0.2x+3)(函数3)

上述3个函数对应的函数曲线分别如图7中右上角、左下角和右下角的图所示。

在本例中,如果把横坐标看成开始时间,则构成函数y的三个正弦函数并不都是从0时刻开始的,它们之间存在时间差。如果直接使用没有时间差的函数,则无法构成图7左上角图所示的函数,而是会构成图5左上角图所示的函数。所以,相差也是傅里叶变换中非常重要的条件。

上面分别用饮料配方和函数的例子介绍了时域与频域转换的可行性,希望对大家理解傅里叶变换能有所帮助。

在图像处理过程中,傅里叶变换就是将图像分解为正弦分量和余弦分量两部分,即将图像从空间域转换到频率域(以下简称频域)。数字图像经过傅里叶变换后,得到的频域值是复数。因此,显示傅里叶变换的结果需要使用实数图像(real image)加虚数图像(complex image),或者幅度图像(magnitude image)加相位图像(phase image)的形式。

因为幅度图像包含了原图像中我们所需要的大部分信息,所以在图像处理过程中,通常仅使用幅度图像。当然,如果希望先在频域内对图像进行处理,再通过逆傅里叶变换得到修改后的空域图像,就必须同时保留幅度图像和相位图像。

对图像进行傅里叶变换后,我们会得到图像中的低频和高频信息。低频信息对应图像内变化缓慢的灰度分量。高频信息对应图像内变化越来越快的灰度分量,是由灰度的尖锐过渡造成的。例如,在一幅大草原的图像中有一头狮子,低频信息就对应着广袤的颜色趋于一致的草原等细节信息,而高频信息则对应着狮子的轮廓等各种边缘及噪声信息。

傅里叶变换的目的,就是为了将图像从空域转换到频域,并在频域内实现对图像内特定对象的处理,然后再对经过处理的频域图像进行逆傅里叶变换得到空域图像。傅里叶变换在图像处理领域发挥着非常关键的作用,可以实现图像增强、图像去噪、边缘检测、特征提取、图像压缩和加密等。

Numpy实现傅里叶变换

Numpy模块提供了傅里叶变换功能,Numpy模块中的fft2()函数可以实现图像的傅里叶变换。本节介绍如何用Numpy模块实现图像的傅里叶变换,以及在频域内过滤图像的低频信息,保留高频信息,实现高通滤波。

实现傅里叶变换

Numpy提供的实现傅里叶变换的函数是numpy.fft.fft2(),它的语法格式是:

返回值 = numpy.fft.fft2(原始图像)

这里需要注意的是,参数“原始图像”的类型是灰度图像,函数的返回值是一个复数数组(complex ndarray)。

经过该函数的处理,就能得到图像的频谱信息。此时,图像频谱中的零频率分量位于频谱图像(频域图像)的左上角,为了便于观察,通常会使用numpy.fft.fftshift()函数将零频率成分移动到频域图像的中心位置,如图8所示。
在这里插入图片描述

图8

函数numpy.fft.fftshift()的语法格式是:

返回值=numpy.fft.fftshift(原始频谱)

使用该函数处理后,图像频谱中的零频率分量会被移到频域图像的中心位置,对于观察傅里叶变换后频谱中的零频率部分非常有效。

对图像进行傅里叶变换后,得到的是一个复数数组。为了显示为图像,需要将它们的值调整到[0, 255]的灰度空间内,使用的公式为:

像素新值=20*np.log(np.abs(频谱值))

式中np是“numpy”的缩写,来源于“import numpy as np”,后面不再对此进行说明。

代码

用Numpy实现傅里叶变换,观察得到的频谱图像。

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('C:\\Users\\Administrator\\Desktop\\caonima.png',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121)
plt.imshow(img, cmap = 'gray')
plt.title('original')
plt.axis('off')
plt.subplot(122)
plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('result')
plt.axis('off')
plt.show()

在这里插入图片描述

图9

实现逆傅里叶变换

需要注意的是,如果在傅里叶变换过程中使用了numpy.fft.fftshift()函数移动零频率分量,那么在逆傅里叶变换过程中,需要先使用numpy.fft.ifftshift()函数将零频率分量移到原来的位置,再进行逆傅里叶变换,该过程如图10所示。
在这里插入图片描述

图10

函数numpy.fft.ifftshift()是numpy.fft.fftshift()的逆函数,其语法格式为:

调整后的频谱 = numpy.fft.ifftshift(原始频谱)

numpy.fft.ifft2()函数可以实现逆傅里叶变换,返回空域复数数组。它是numpy.fft.fft2()的逆函数,该函数的语法格式为:

返回值=numpy.fft.ifft2(频域数据)

函数numpy.fft.ifft2()的返回值仍旧是一个复数数组(complexndarray)。

逆傅里叶变换得到的空域信息是一个复数数组,需要将该信息调整至[0,255]灰度空间内,使用的公式为:

iimg = np.abs(逆傅里叶变换结果)

代码

在Numpy内实现傅里叶变换、逆傅里叶变换,观察逆傅里叶变换的结果图像。

# 逆变换
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('C:\\Users\\Administrator\\Desktop\\caonima.png', 0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
ishift = np.fft.ifftshift(fshift)
iimg = np.fft.ifft2(ishift)
# print(iimg)
iimg = np.abs(iimg)
# print(iimg)
plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iimg, cmap='gray')
plt.title('iimg'), plt.axis('off')
plt.show()

在这里插入图片描述

图11

高通滤波示例

在一幅图像内,同时存在着高频信号和低频信号。

  • 低频信号对应图像内变化缓慢的灰度分量。例如,在一幅大草原的图像中,低频信号对应着颜色趋于一致的广袤草原。
  • 高频信号对应图像内变化越来越快的灰度分量,是由灰度的尖锐过渡造成的。如果在上面的大草原图像中还有一头狮子,那么高频信号就对应着狮子的边缘等信息。

滤波器能够允许一定频率的分量通过或者拒绝其通过,按照其作用方式可以划分为低通滤波器和高通滤波器。

  • 允许低频信号通过的滤波器称为低通滤波器。低通滤波器使高频信号衰减而对低频信号放行,会使图像变模糊。
  • 允许高频信号通过的滤波器称为高通滤波器。高通滤波器使低频信号衰减而让高频信号通过,将增强图像中尖锐的细节,但是会导致图像的对比度降低。

傅里叶变换可以将图像的高频信号和低频信号分离。例如,傅里叶变换可以将低频信号放置到傅里叶变换图像的中心位置,如图9所示,低频信号位于右图的中心位置。可以对傅里叶变换得到的高频信号和低频信号分别进行处理,例如高通滤波或者低通滤波。在对图像的高频或低频信号进行处理后,再进行逆傅里叶变换返回空域,就完成了对图像的频域处理。通过对图像的频域处理,可以实现图像增强、图像去噪、边缘检测、特征提取、压缩和加密等操作。

例如,在图11中,左图original是原始图像,中间的图像result是对左图original进行傅里叶变化后得到的结果,右图则是对result进行高通滤波后的结果。将傅里叶变换结果图像result中的低频分量值都替换为0(处理为黑色),就屏蔽了低频信号,只保留高频信号,实现高通滤波。

要将图12中右图中间的像素值都置零,需要先计算其中心位置的坐标,然后选取以该坐标为中心,上下左右各30个像素大小的区域,将这个区域内的像素值置零。该滤波器的实现方法为:

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0
# 逆变换
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('C:\\Users\\Administrator\\Desktop\\caonima.png', 0)


f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0

ishift = np.fft.ifftshift(fshift)
iimg = np.fft.ifft2(ishift)
# print(iimg)
iimg = np.abs(iimg)
# print(iimg)
plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iimg, cmap='gray')
plt.title('iimg'), plt.axis('off')
plt.show()

在这里插入图片描述

图12

代码

在Numpy内对图像进行傅里叶变换,得到其频域图像。然后,在频域内将低频分量的值处理为0,实现高通滤波。最后,对图像进行逆傅里叶变换,得到恢复的原始图像。观察傅里叶变换前后图像的差异。

import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('image\\boat.bmp',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0
ishift = np.fft.ifftshift(fshift)
iimg = np.fft.ifft2(ishift)
iimg = np.abs(iimg)
plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iimg, cmap = 'gray')
plt.title('iimg'), plt.axis('off')
plt.show()

运行上述代码后,得到如图13所示的傅里叶变换对比图。从图中可以看到,经过高通滤波后,图像的边缘信息得以保留。
在这里插入图片描述

图13

OpenCV实现傅里叶变换

OpenCV提供了函数cv2.dft()和cv2.idft()来实现傅里叶变换和逆傅里叶变换,下面分别展开介绍。

实现傅里叶变换

函数cv2.dft()的语法格式为:

返回结果=cv2.dft(原始图像,转换标识)

在使用该函数时,需要注意参数的使用规范:

  • 对于参数“原始图像”,要首先使用np.float32()函数将图像转换成np.float32格式。
  • “转换标识”的值通常为“cv2.DFT_COMPLEX_OUTPUT”,用来输出一个复数阵列。

函数cv2.dft()返回的结果与使用Numpy进行傅里叶变换得到的结果是一致的,但是它返回的值是双通道的,第1个通道是结果的实数部分,第2个通道是结果的虚数部分。

经过函数cv2.dft()的变换后,我们得到了原始图像的频谱信息。此时,零频率分量并不在中心位置,为了处理方便需要将其移至中心位置,可以用函数numpy.fft.fftshift()实现。例如,如下语句将频谱图像dft中的零频率分量移到频谱中心,得到了零频率分量位于中心的频谱图像dftshift。

dftShift = np.fft.fftshift(dft)

经过上述处理后,频谱图像还只是一个由实部和虚部构成的值。要将其显示出来,还要做进一步的处理才行。

函数cv2.magnitude()可以计算频谱信息的幅度。该函数的语法格式为:

返回值=cv2.magnitude(参数1,参数2)

式中两个参数的含义如下:

  • ● 参数1:浮点型x坐标值,也就是实部。
  • ● 参数2:浮点型y坐标值,也就是虚部,它必须和参数1具有相同的大小(size值的大小,不是value值的大小)。

函数cv2.magnitude()的返回值是参数1和参数2的平方和的平方根,公式为:
在这里插入图片描述

式中,I表示原始图像,dst表示目标图像。

得到频谱信息的幅度后,通常还要对幅度值做进一步的转换,以便将频谱信息以图像的形式展示出来。简单来说,就是需要将幅度值映射到灰度图像的灰度空间[0, 255]内,使其以灰度图像的形式显示出来。

这里使用的公式为:

result = 20*np.log(cv2.magnitude(实部,虚部))

下面对一幅图像进行傅里叶变换,帮助读者观察上述处理过程。如下代码针对图像“lena”进行傅里叶变换,并且计算了幅度值,对幅度值进行了规范化处理:

import numpy as np
import cv2
img = cv2.imread('image\\lena.bmp',0)
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
print(dft)
dftShift = np.fft.fftshift(dft)
print(dftShift)
result = 20*np.log(cv2.magnitude(dftShift[:, :,0], dftShift[:, :,1]))
print(result)

得到的值范围分别如图14所示。其中:
在这里插入图片描述

图14
  • 左图显示的是函数cv2.dft()得到的频谱值,该值是由实部和虚部构成的。
  • 中间的图显示的是函数cv2.magnitude()计算得到的频谱幅度值,这些值不在标准的图像灰度空间[0, 255]内。
  • 右图显示的是对函数cv2.magnitude()计算得到的频谱幅度值进一步规范的结果,现在值的范围在[0, 255]内。

代码

用OpenCV函数对图像进行傅里叶变换,并展示其频谱信息。

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image\\lena.bmp',0)
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
dftShift = np.fft.fftshift(dft)
result = 20*np.log(cv2.magnitude(dftShift[:, :,0], dftShift[:, :,1]))
plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(result, cmap = 'gray')
plt.title('result'), plt.axis('off')
plt.show()

在这里插入图片描述

图15
  • 左图是原始图像。
  • 右图是频谱图像,是使用函数np.fft.fftshift()将零频率分量移至频谱图像中心位置的结果。

实现逆傅里叶变换

在OpenCV中,使用函数cv2.idft()实现逆傅里叶变换,该函数是傅里叶变换函数cv2.dft()的逆函数。其语法格式为:

返回结果=cv2.idft(原始数据)

对图像进行傅里叶变换后,通常会将零频率分量移至频谱图像的中心位置。如果使用函数numpy.fft.fftshift()移动了零频率分量,那么在进行逆傅里叶变换前,要使用函数numpy.fft.ifftshift()将零频率分量恢复到原来位置。还要注意,在进行逆傅里叶变换后,得到的值仍旧是复数,需要使用函数cv2.magnitude()计算其幅度。

代码

用OpenCV函数对图像进行傅里叶变换、逆傅里叶变换,并展示原始图像及经过逆傅里叶变换后得到的图像。

根据题目的要求,编写代码如下:

import numpy as np
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image\\lena.bmp',0)
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
dftShift = np.fft.fftshift(dft)
ishift = np.fft.ifftshift(dftShift)
iImg = cv2.idft(ishift)
iImg= cv2.magnitude(iImg[:, :,0], iImg[:, :,1])
plt.subplot(121), plt.imshow(img, cmap = 'gray')
plt.title('original'), plt.axis('off')
plt.subplot(122), plt.imshow(iImg, cmap = 'gray')
plt.title('inverse'), plt.axis('off')
plt.show()

低通滤波示例

前面讲过,在一幅图像内,低频信号对应图像内变化缓慢的灰度分量。例如,在一幅大草原的图像中,低频信号对应着颜色趋于一致的广袤草原。低通滤波器让高频信号衰减而让低频信号通过,图像进行低通滤波后会变模糊。

例如,在图16中,左图original是原始图像,中间的图像result是对original进行傅里叶变换后得到的结果,右图是低通滤波后的图像。将傅里叶变换结果图像result中的高频信号值都替换为0(处理为黑色),就屏蔽了高频信号,只保留低频信号,从而实现了低通滤波。
在这里插入图片描述

图16

在实现低通滤波时,可以专门构造一个如图17中左图所示的图像,用它与原图的傅里叶变换频谱图像进行与运算,就能将频谱图像中的高频信号过滤掉。
在这里插入图片描述

图17

对于图17中的左图,可以采用如下方式构造:

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)
mask = np.zeros((rows, cols,2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

然后,将其与频谱图像进行运算,实现低通滤波。这里采用的运算形式是:

fShift = dftShift*mask

代码

使用函数cv2.dft()对图像进行傅里叶变换,得到其频谱图像。然后,在频域内将其高频分量的值处理为0,实现低通滤波。最后,对图像进行逆傅里叶变换,得到恢复的原始图像。观察傅里叶变换前后图像的差异。

    import numpy as np
    import cv2
    import matplotlib.pyplot as plt
    img = cv2.imread('image\\lena.bmp',0)
    dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
    dftShift = np.fft.fftshift(dft)
    rows, cols = img.shape
    crow, ccol = int(rows/2) , int(cols/2)
    mask = np.zeros((rows, cols,2), np.uint8)
    #两个通道,与频域图像匹配
    mask[crow-30:crow+30, ccol-30:ccol+30] = 1
    fShift = dftShift*mask
    ishift = np.fft.ifftshift(fShift)
    iImg = cv2.idft(ishift)
    iImg= cv2.magnitude(iImg[:, :,0], iImg[:, :,1])
    plt.subplot(121), plt.imshow(img, cmap = 'gray')
    plt.title('original'), plt.axis('off')
    plt.subplot(122), plt.imshow(iImg, cmap = 'gray')
    plt.title('inverse'), plt.axis('off')
    plt.show()

运行上述代码,得到如图18所示的结果,左图为原始图像,右图为变换后的图像。可以看到,经过低通滤波后,图像的边缘信息被削弱了。
在这里插入图片描述

图18

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql基础练习题 1757.可回收且低脂的产品(力扣)

编写解决方案找出既是低脂又是可回收的产品编号。 题目链接: https://leetcode.cn/problems/recyclable-and-low-fat-products/description/ 建表插入数据: Create table If Not Exists Products (product_id int, low_fats ENUM(Y, N), recyclable …

Kernel 内核 BUG_ON()和WARN_ON()

WARN_ON() DEBUG_ON() 不是一个标准的 Linux 内核宏,它可能是特定内核版本或者特定内核配置中的一个宏,或者在某些内核代码中自定义的宏。一般来说,如果存在 DEBUG_ON(),它可能被用作一个调试开关,用于在调试版本中启…

2024.9.11

时钟 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QTimer> #include <QPainter> #include <QPen> #include <QBrush> #include <QTime> #include <QDebug> QT_BEGIN_NA…

国内如何优雅的用Google?无需安装任何工具!

前言 Google可以说时每个程序猿的标配&#xff0c;但由于网络问题&#xff0c;在访问Google的时候或多或少都会遇到一系列的问题&#xff0c;接下来介绍一个非常“炸裂”的Google打开方式。 LiteIcoding 在此之前&#xff0c;你需要访问这个地址 https://lite.icoding.ink 这…

【Qt】QSS的设置方式

QSS的设置方式 QWidget 中包含了 setStyleSheet ⽅法, 可以直接设置样式. 上述代码我们已经演⽰了上述设置⽅式 还可以通过 QApplication 的 setStyleSheet ⽅法设置整个程序的全局样式. 设置全局样式&#xff0c;可以将界面上所有的样式都集中到一起来组织。 全局样式优点:…

56 - II. 数组中数字出现的次数 II

comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9856%20-%20II.%20%E6%95%B0%E7%BB%84%E4%B8%AD%E6%95%B0%E5%AD%97%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0%20II/README.md 面试题 56 - II. 数…

大屏可视化常用图标效果表达

1-echarts-雷达图 2-echarts-仪表盘 3-echarts-水球图&#xff08;利用插件&#xff0c;echarts-liquidfill&#xff09; 4-element UI tree 添加连接线&#xff0c;修改样式或使用插件&#xff08;element-tree-line&#xff09; 5-echarts-漏斗图 6-echarts-饼状图嵌套 optio…

力扣刷题之2181.合并零之间的节点

题干描述 给你一个链表的头节点 head &#xff0c;该链表包含由 0 分隔开的一连串整数。链表的 开端 和 末尾 的节点都满足 Node.val 0 。 对于每两个相邻的 0 &#xff0c;请你将它们之间的所有节点合并成一个节点&#xff0c;其值是所有已合并节点的值之和。然后将所有 0 …

为什么 1T 的硬盘容量只有 931G?真相在这里!

硬盘容量疑问 以一个容量为 1T 的硬盘为例&#xff0c;在 Windows 系统下&#xff0c;容量显示只有 931G&#xff0c;不应该是 1024GB 吗&#xff1f;这到底是为什么呢&#xff1f;是商家在欺骗消费者吗&#xff1f; 按照之前内存大小的计算逻辑&#xff08;1MB 1024KB&…

AI电商,如何提高设计效率?

第一步&#xff1a;找参考 第二步&#xff1a;提取关键词 我用的文心一言 第三步&#xff1a;选择AI绘画工具&#xff08;千鹿 设计助手&#xff09; 千鹿设计助手——FLux文生图&#xff0c;你也可以选择你手上的AI绘画工具 这个新用户注册会赠送1000积分 第四步生图

[笔记] 电机工作制以及软硬特性的本质推导

原始资料来源&#xff1a;某电机厂商 1.电机非常规操作术语和许可次数 1.1 电机操作术语 点动&#xff1a;通电后立即关停&#xff0c;最终速度不到额定转速的1/4电制动&#xff1a;制动到额定转速的1/3逆转&#xff1a;也就是打反车&#xff0c;不等停车&#xff0c;立即翻…

Java、python、php三个版本 抗震救灾物资管理系统 抗洪救灾物资分配系统 救援物资申请平台(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

在 Web 中判断页面是不是刷新

在 Web 开发中&#xff0c;我们经常需要区分用户是否通过刷新操作重新加载了页面。这一操作可能是由用户手动刷新&#xff08;如按下 F5 键或点击浏览器刷新按钮&#xff09;或通过浏览器自动重新加载。判断页面是否刷新有助于开发者优化用户体验&#xff0c;例如在使用 vue 的…

超详细,手把手带你源码启动 Thingsboard-Gateway + MQTT 接入设备

超详细&#xff0c;手把手带你源码启动 Thingsboard-Gateway MQTT 接入设备 前置条件 thingsboard&#xff0c;我这里选择的是本地源码启动postgresql&#xff0c;这里采用的是个人服务器部署的公共服务EMQX&#xff0c;这里同样采用服务器部署的公共服务MQTTX 客户端Mysql【…

Fiddle的使用------一个非常好用且正规的抓包工具

Fiddle的下载安装&#xff08;看完再去下载安装&#xff09; https://www.telerik.com/download/fiddler 1.点击连接&#xff0c;在表格填上数据&#xff0c;点击下载&#xff0c;下载结束了就安装&#xff0c;一路next就可以了。 2.修改一下设置 以上跟我一样设置&#xff…

Unity 是否能和黑神话悟空一样,接入Nivida的DLSS,用NSight Graphics实际测试

NSight作为Nivida 显卡的调试工具&#xff0c;因为国内都是手游开发盛行的年代&#xff0c;远没有RenderDoc或者高通的QuatXXX 出名 选择NSight的原因很简单&#xff1a; Nividia 财大气粗&#xff0c;倒不是主因&#xff0c; 因为其CEO爱出名&#xff0c;所以手下的人只…

视觉SLAM ch5——相机与图像

一、单目模型 前言&#xff1a;本大标题下1~4部分讲述的都是单目针孔相机 SLAM的数学本质可以抽象为运动方程&#xff08;x&#xff09;和观测方程&#xff08;z&#xff09;&#xff08;书上的第二部分&#xff09; 教材第二章截图 书中P24页截图 其中的未知量为xk&#xff…

828华为云征文|几分钟,即可在华为云Flexus X服务器部署安全稳定的——水果生鲜商城配送小程序

最近由于公司需要开发一个水果生鲜同城配送的小程序&#xff0c;源码代码已经有了&#xff0c;相对于应的功能也开发的七七八八了&#xff0c;随着生鲜商城小程序的相对于应的功能开发逐渐接近尾声。 然而&#xff0c;在这个关键时刻&#xff0c;一个至关重要的决定摆在了团队面…

javase复习day22泛型、set、数据结构

泛型 package MyGenerics;import java.util.ArrayList; import java.util.Iterator;public class GenericsTest1 {public static void main(String[] args) {//没有泛型的情况ArrayList list new ArrayList();//所有数据都被认为是Object类型&#xff0c;都可以加入集合中list…

【操作系统】汇总二、进程管理

进程管理 二、进程与线程 文章目录 进程管理二、进程与线程1.程序1.1顺序执行的特征1.2并发执行的特征1.3 C语言编写的程序 2.进程Process2.1定义&#xff08;组织&#xff09;2.1.1程序段2.1.2数据段❗2.1.3进程控制块PCB1&#xff09;内容2&#xff09;作用3&#xff09;进程…