如何利用OpenCV4.9离散傅里叶变换

返回:OpenCV系列文章目录(持续更新中......)

上一篇:如何利用OpenCV4.9 更改图像的对比度和亮度

下一篇:OpenCV 如何使用 XML 和 YAML 文件的文件输入和输出

目标

我们将寻求以下问题的答案:

  • 什么是傅里叶变换,为什么要使用它?
  • 如何在 OpenCV 中做到这一点?
  • 使用以下函数: copyMakeBorder() , merge() , dft() , getOptimalDFTSize() , log()normalize() .

源代码

你可以在官方网站下载相关源代码。

以下 dft()  的用法示例:

C++

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp" 
#include <iostream> 
using namespace cv;
using namespace std; 
static void help(char ** argv)
{
 cout << endl
 << "This program demonstrated the use of the discrete Fourier transform (DFT). " << endl
 << "The dft of an image is taken and it's power spectrum is displayed." << endl << endl
 << "Usage:" << endl
 << argv[0] << " [image_name -- default lena.jpg]" << endl << endl;
} 
int main(int argc, char ** argv)
{
 help(argv); 
 const char* filename = argc >=2 ? argv[1] : "lena.jpg"; 
 Mat I = imread( samples::findFile( filename ), IMREAD_GRAYSCALE);
 if( I.empty()){
 cout << "Error opening image" << endl;
 return EXIT_FAILURE;
 } 
 Mat padded; //expand input image to optimal size
 int m = getOptimalDFTSize( I.rows );
 int n = getOptimalDFTSize( I.cols ); // on the border add zero values
 copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0)); 
 Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
 Mat complexI;
 merge(planes, 2, complexI); // Add to the expanded another plane with zeros 
 dft(complexI, complexI); // this way the result may fit in the source matrix 
 // compute the magnitude and switch to logarithmic scale
 // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
 split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
 magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
 Mat magI = planes[0]; 
 magI += Scalar::all(1); // switch to logarithmic scale
 log(magI, magI); 
 // crop the spectrum, if it has an odd number of rows or columns
 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); 
 // rearrange the quadrants of Fourier image so that the origin is at the image center
 int cx = magI.cols/2;
 int cy = magI.rows/2; 
 Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
 Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
 Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
 Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right 
 Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
 q0.copyTo(tmp);
 q3.copyTo(q0);
 tmp.copyTo(q3); 
 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
 q2.copyTo(q1);
 tmp.copyTo(q2); 
 normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a
 // viewable image form (float between values 0 and 1). 
 imshow("Input Image" , I ); // Show the result
 imshow("spectrum magnitude", magI);
 waitKey(); 
 return EXIT_SUCCESS;
}

Java

import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs; 
import java.util.List;
import java.util.*; 
class DiscreteFourierTransformRun{
 private void help() {
 System.out.println("" +
 "This program demonstrated the use of the discrete Fourier transform (DFT). \n" +
 "The dft of an image is taken and it's power spectrum is displayed.\n" +
 "Usage:\n" +
 "./DiscreteFourierTransform [image_name -- default ../data/lena.jpg]");
 } 
 public void run(String[] args){ 
 help(); 
 String filename = ((args.length > 0) ? args[0] : "../data/lena.jpg"); 
 Mat I = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);
 if( I.empty() ) {
 System.out.println("Error opening image");
 System.exit(-1);
 } 
 Mat padded = new Mat(); //expand input image to optimal size
 int m = Core.getOptimalDFTSize( I.rows() );
 int n = Core.getOptimalDFTSize( I.cols() ); // on the border add zero values
 Core.copyMakeBorder(I, padded, 0, m - I.rows(), 0, n - I.cols(), Core.BORDER_CONSTANT, Scalar.all(0)); 
 List<Mat> planes = new ArrayList<Mat>();
 padded.convertTo(padded, CvType.CV_32F);
 planes.add(padded);
 planes.add(Mat.zeros(padded.size(), CvType.CV_32F));
 Mat complexI = new Mat();
 Core.merge(planes, complexI); // Add to the expanded another plane with zeros 
 Core.dft(complexI, complexI); // this way the result may fit in the source matrix 
 // compute the magnitude and switch to logarithmic scale
 // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
 Core.split(complexI, planes); // planes.get(0) = Re(DFT(I)
 // planes.get(1) = Im(DFT(I))
 Core.magnitude(planes.get(0), planes.get(1), planes.get(0));// planes.get(0) = magnitude
 Mat magI = planes.get(0); 
 Mat matOfOnes = Mat.ones(magI.size(), magI.type());
 Core.add(matOfOnes, magI, magI); // switch to logarithmic scale
 Core.log(magI, magI); 
 // crop the spectrum, if it has an odd number of rows or columns
 magI = magI.submat(new Rect(0, 0, magI.cols() & -2, magI.rows() & -2)); 
 // rearrange the quadrants of Fourier image so that the origin is at the image center
 int cx = magI.cols()/2;
 int cy = magI.rows()/2; 
 Mat q0 = new Mat(magI, new Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
 Mat q1 = new Mat(magI, new Rect(cx, 0, cx, cy)); // Top-Right
 Mat q2 = new Mat(magI, new Rect(0, cy, cx, cy)); // Bottom-Left
 Mat q3 = new Mat(magI, new Rect(cx, cy, cx, cy)); // Bottom-Right 
 Mat tmp = new Mat(); // swap quadrants (Top-Left with Bottom-Right)
 q0.copyTo(tmp);
 q3.copyTo(q0);
 tmp.copyTo(q3); 
 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
 q2.copyTo(q1);
 tmp.copyTo(q2); 
 magI.convertTo(magI, CvType.CV_8UC1);
 Core.normalize(magI, magI, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC1); // Transform the matrix with float values
 // into a viewable image form (float between
 // values 0 and 255). 
 HighGui.imshow("Input Image" , I ); // Show the result
 HighGui.imshow("Spectrum Magnitude", magI);
 HighGui.waitKey(); 
 System.exit(0);
 }
} 
public class DiscreteFourierTransform {
 public static void main(String[] args) {
 // Load the native library.
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
 new DiscreteFourierTransformRun().run(args);
 }
}

Python 

from __future__ import print_function
import sys 
import cv2 as cv
import numpy as np 
def print_help():
 print('''
 This program demonstrated the use of the discrete Fourier transform (DFT).
 The dft of an image is taken and it's power spectrum is displayed.
 Usage:
 discrete_fourier_transform.py [image_name -- default lena.jpg]''') 
def main(argv): 
 print_help() 
 filename = argv[0] if len(argv) > 0 else 'lena.jpg' 
 I = cv.imread(cv.samples.findFile(filename), cv.IMREAD_GRAYSCALE)
 if I is None:
 print('Error opening image')
 return -1 
 rows, cols = I.shape
 m = cv.getOptimalDFTSize( rows )
 n = cv.getOptimalDFTSize( cols )
 padded = cv.copyMakeBorder(I, 0, m - rows, 0, n - cols, cv.BORDER_CONSTANT, value=[0, 0, 0]) 
 planes = [np.float32(padded), np.zeros(padded.shape, np.float32)]
 complexI = cv.merge(planes) # Add to the expanded another plane with zeros 
 cv.dft(complexI, complexI) # this way the result may fit in the source matrix 
 cv.split(complexI, planes) # planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
 cv.magnitude(planes[0], planes[1], planes[0])# planes[0] = magnitude
 magI = planes[0] 
 matOfOnes = np.ones(magI.shape, dtype=magI.dtype)
 cv.add(matOfOnes, magI, magI) # switch to logarithmic scale
 cv.log(magI, magI) 
 magI_rows, magI_cols = magI.shape
 # crop the spectrum, if it has an odd number of rows or columns
 magI = magI[0:(magI_rows & -2), 0:(magI_cols & -2)]
 cx = int(magI_rows/2)
 cy = int(magI_cols/2) 
 q0 = magI[0:cx, 0:cy] # Top-Left - Create a ROI per quadrant
 q1 = magI[cx:cx+cx, 0:cy] # Top-Right
 q2 = magI[0:cx, cy:cy+cy] # Bottom-Left
 q3 = magI[cx:cx+cx, cy:cy+cy] # Bottom-Right 
 tmp = np.copy(q0) # swap quadrants (Top-Left with Bottom-Right)
 magI[0:cx, 0:cy] = q3
 magI[cx:cx + cx, cy:cy + cy] = tmp 
 tmp = np.copy(q1) # swap quadrant (Top-Right with Bottom-Left)
 magI[cx:cx + cx, 0:cy] = q2
 magI[0:cx, cy:cy + cy] = tmp 
 cv.normalize(magI, magI, 0, 1, cv.NORM_MINMAX) # Transform the matrix with float values into a 
 cv.imshow("Input Image" , I ) # Show the result
 cv.imshow("spectrum magnitude", magI)
 cv.waitKey() 
if __name__ == "__main__":
 main(sys.argv[1:])

解释:

傅里叶变换会将图像分解为正弦和余弦分量。换句话说,它将图像从其空间域转换为其频域。这个想法是,任何函数都可以精确地近似于无限正弦和余弦函数的总和。傅里叶变换是一种如何做到这一点的方法。从数学上讲,二维图像傅里叶变换是:

这里 f 是其空间域中的图像值,F 是其频域中的图像值。变换的结果是复数。可以通过真实图像和数图像或通过幅度相位图像来显示这一点。然而,在整个图像处理算法中,只有幅度图像是有趣的,因为它包含了我们需要的有关图像几何结构的所有信息。但是,如果您打算以这些形式对图像进行一些修改,然后需要重新转换它,则需要保留这两种形式。

在此示例中,我将演示如何计算和显示傅里叶变换的幅度图像。在数字图像的情况下是离散的。这意味着它们可能会从给定的域值中获取一个值。例如,在基本灰度中,图像值通常介于 0 到 255 之间。因此,傅里叶变换也需要是离散类型的,从而产生离散傅里叶变换 (DFT)。每当您需要从几何角度确定图像的结构时,您都需要使用它。以下是要遵循的步骤(如果是灰度输入图像 I):

将图像扩展到最佳大小

DFT 的性能取决于图像大小。对于数字 2、3 和 5 的倍数的图像大小,它往往是最快的。因此,为了实现最佳性能,通常最好将边框值填充到图像上,以获得具有此类特征的大小。getOptimalDFTSize()返回这个最佳大小,我们可以使用 copyMakeBorder() 函数来扩展图像的边框(附加的像素以零初始化):

c++:

 Mat padded; //expand input image to optimal size
 int m = getOptimalDFTSize( I.rows );
 int n = getOptimalDFTSize( I.cols ); // on the border add zero values
 copyMakeBorder(I, padded, 0, m - I.rows, 0, n - I.cols, BORDER_CONSTANT, Scalar::all(0));

Java:

 Mat padded = new Mat(); //expand input image to optimal size
 int m = Core.getOptimalDFTSize( I.rows() );
 int n = Core.getOptimalDFTSize( I.cols() ); // on the border add zero values
 Core.copyMakeBorder(I, padded, 0, m - I.rows(), 0, n - I.cols(), Core.BORDER_CONSTANT, Scalar.all(0));

python: 

 rows, cols = I.shape
 m = cv.getOptimalDFTSize( rows )
 n = cv.getOptimalDFTSize( cols )
 padded = cv.copyMakeBorder(I, 0, m - rows, 0, n - cols, cv.BORDER_CONSTANT, value=[0, 0, 0])

为复杂价值和真实价值腾出空间

傅里叶变换的结果很复杂。这意味着对于每个图像值,结果是两个图像值(每个组件一个)。此外,频域范围比空间对应物大得多。因此,我们通常至少以浮点格式存储这些内容。因此,我们将输入图像转换为此类型,并使用另一个通道对其进行扩展以保存复数值:

c++:

 Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
 Mat complexI;
 merge(planes, 2, complexI); // Add to the expanded another plane with zeros

 Java:

 Mat padded = new Mat(); //expand input image to optimal size
 int m = Core.getOptimalDFTSize( I.rows() );
 int n = Core.getOptimalDFTSize( I.cols() ); // on the border add zero values
 Core.copyMakeBorder(I, padded, 0, m - I.rows(), 0, n - I.cols(), Core.BORDER_CONSTANT, Scalar.all(0));

Python:

 rows, cols = I.shape
 m = cv.getOptimalDFTSize( rows )
 n = cv.getOptimalDFTSize( cols )
 padded = cv.copyMakeBorder(I, 0, m - rows, 0, n - cols, cv.BORDER_CONSTANT, value=[0, 0, 0])

进行离散傅里叶变换

可以就地计算(输入与输出相同):

C++:

dft(complexI, complexI); // this way the result may fit in the source matrix

 Java:

 Core.dft(complexI, complexI); // this way the result may fit in the source matrix

Python: 

 cv.dft(complexI, complexI) # this way the result may fit in the source matrix

将实数值和复数值转换为量级

复数有一个实数(Re)和一个复数(虚数-Im)部分。DFT 的结果是复数。DFT 的量级为:

翻译成 OpenCV 代码:

C++:

 split(complexI, planes); // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
 magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
 Mat magI = planes[0];

Java:

 Core.split(complexI, planes); // planes.get(0) = Re(DFT(I)
 // planes.get(1) = Im(DFT(I))
 Core.magnitude(planes.get(0), planes.get(1), planes.get(0));// planes.get(0) = magnitude
 Mat magI = planes.get(0);

Python:

 cv.split(complexI, planes) # planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
 cv.magnitude(planes[0], planes[1], planes[0])# planes[0] = magnitude
 magI = planes[0]

切换到对数刻度

事实证明,傅里叶系数的动态范围太大,无法显示在屏幕上。我们有一些小的和一些高的变化值,我们无法像这样观察到。因此,高值将全部变成白点,而小值则变成黑点。为了使用灰度值进行可视化,我们可以将线性刻度转换为对数刻度:

翻译成 OpenCV 代码:

C++:

 magI += Scalar::all(1); // switch to logarithmic scale
 log(magI, magI);

Java:

 Mat matOfOnes = Mat.ones(magI.size(), magI.type());
 Core.add(matOfOnes, magI, magI); // switch to logarithmic scale
 Core.log(magI, magI);

Python : 

 matOfOnes = np.ones(magI.shape, dtype=magI.dtype)
 cv.add(matOfOnes, magI, magI) # switch to logarithmic scale
 cv.log(magI, magI)

裁剪和重新排列

还记得,在第一步,我们扩展了图像吗?好吧,是时候扔掉新引入的价值观了。出于可视化目的,我们还可以重新排列结果的象限,使原点(零,零)与图像中心相对应。

C++:

 // crop the spectrum, if it has an odd number of rows or columns
 magI = magI(Rect(0, 0, magI.cols & -2, magI.rows & -2)); 
 // rearrange the quadrants of Fourier image so that the origin is at the image center
 int cx = magI.cols/2;
 int cy = magI.rows/2; 
 Mat q0(magI, Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
 Mat q1(magI, Rect(cx, 0, cx, cy)); // Top-Right
 Mat q2(magI, Rect(0, cy, cx, cy)); // Bottom-Left
 Mat q3(magI, Rect(cx, cy, cx, cy)); // Bottom-Right 
 Mat tmp; // swap quadrants (Top-Left with Bottom-Right)
 q0.copyTo(tmp);
 q3.copyTo(q0);
 tmp.copyTo(q3); 
 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
 q2.copyTo(q1);
 tmp.copyTo(q2);

 Java:

 // crop the spectrum, if it has an odd number of rows or columns
 magI = magI.submat(new Rect(0, 0, magI.cols() & -2, magI.rows() & -2));
  // rearrange the quadrants of Fourier image so that the origin is at the image center
 int cx = magI.cols()/2;
 int cy = magI.rows()/2; 
 Mat q0 = new Mat(magI, new Rect(0, 0, cx, cy)); // Top-Left - Create a ROI per quadrant
 Mat q1 = new Mat(magI, new Rect(cx, 0, cx, cy)); // Top-Right
 Mat q2 = new Mat(magI, new Rect(0, cy, cx, cy)); // Bottom-Left
 Mat q3 = new Mat(magI, new Rect(cx, cy, cx, cy)); // Bottom-Right 
 Mat tmp = new Mat(); // swap quadrants (Top-Left with Bottom-Right)
 q0.copyTo(tmp);
 q3.copyTo(q0);
 tmp.copyTo(q3); 
 q1.copyTo(tmp); // swap quadrant (Top-Right with Bottom-Left)
 q2.copyTo(q1);
 tmp.copyTo(q2);

Python: 

 magI_rows, magI_cols = magI.shape
 # crop the spectrum, if it has an odd number of rows or columns
 magI = magI[0:(magI_rows & -2), 0:(magI_cols & -2)]
 cx = int(magI_rows/2)
 cy = int(magI_cols/2) 
 q0 = magI[0:cx, 0:cy] # Top-Left - Create a ROI per quadrant
 q1 = magI[cx:cx+cx, 0:cy] # Top-Right
 q2 = magI[0:cx, cy:cy+cy] # Bottom-Left
 q3 = magI[cx:cx+cx, cy:cy+cy] # Bottom-Right 
 tmp = np.copy(q0) # swap quadrants (Top-Left with Bottom-Right)
 magI[0:cx, 0:cy] = q3
 magI[cx:cx + cx, cy:cy + cy] = tmp 
 tmp = np.copy(q1) # swap quadrant (Top-Right with Bottom-Left)
 magI[cx:cx + cx, 0:cy] = q2
 magI[0:cx, cy:cy + cy] = tmp

正常化

出于可视化目的,再次执行此操作。我们现在有了星等,但这仍然超出了我们的图像显示范围 0 到 1。我们使用 cv::normalize() 函数将我们的值规范化到这个范围。

C++:

 normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a
 // viewable image form (float between values 0 and 1).

Java:

 Core.normalize(magI, magI, 0, 255, Core.NORM_MINMAX, CvType.CV_8UC1); // Transform the matrix with float values
 // into a viewable image form (float between
 // values 0 and 255).

python:

 cv.normalize(magI, magI, 0, 1, cv.NORM_MINMAX) # Transform the matrix with float values into a

结果

一个应用思路是确定图像中存在的几何方向。例如,让我们找出文本是否是水平的?看一些文本,你会注意到文本线条也形成了水平线,字母形成了垂直线条。在傅里叶变换的情况下,也可以看到文本片段的这两个主要组成部分。让我们使用这个水平和这个旋转的图像来描述一个文本。

如果是横向文本:

如果文本旋转:

您可以看到,频域中最有影响力的分量(幅度图像上最亮的点)遵循图像上物体的几何旋转。由此我们可以计算偏移量并执行图像旋转以校正最终的未对齐。

参考文献:

1、《Discrete Fourier Transform》-----Bernát Gábor

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

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

相关文章

《数据结构学习笔记---第五篇》---链表OJ练习下

step1:思路分析 1.实现复制&#xff0c;且是两个独立的复制&#xff0c;我们必须要理清指针之间的逻辑&#xff0c;注意random的新指针要链接到复制体的后面。 2.我们先完成对于结点的复制&#xff0c;并将复制后的结点放在原节点的后面&#xff0c;并链接。 3.完成random结点…

黑马鸿蒙笔记1

这里与前端类似。

斜率优化dp 笔记

任务安排1 有 N 个任务排成一个序列在一台机器上等待执行&#xff0c;它们的顺序不得改变。 机器会把这 N 个任务分成若干批&#xff0c;每一批包含连续的若干个任务。 从时刻 00 开始&#xff0c;任务被分批加工&#xff0c;执行第 i 个任务所需的时间是 Ti。 另外&#x…

PHP开发全新29网课交单平台源码修复全开源版本,支持聚合登陆易支付

这是一套最新版本的PHP开发的网课交单平台源代码&#xff0c;已进行全开源修复&#xff0c;支持聚合登录和易支付功能。 项目 地 址 &#xff1a; runruncode.com/php/19721.html 以下是对该套代码的主要更新和修复&#xff1a; 1. 移除了论文编辑功能。 2. 移除了强国接码…

linux之进程

一、背景 冯.诺依曼体系结构 输入设备键盘、鼠标、摄像头、话筒、磁盘、网卡...输出设备显示器、声卡、磁盘、网卡...CPU运算器、控制器存储器一般就是内存 数据在计算机的体系结构进行流动&#xff0c;流动过程中&#xff0c;进行数据的加工处理&#xff0c;从一个设备到另一…

网上兼职赚钱攻略:六种方式让你轻松上手

在互联网时代&#xff0c;网上兼职已经成为一种非常流行的赚钱方式。对于许多想要在家里挣钱的人来说&#xff0c;网上兼职不仅可以提供灵活的工作时间&#xff0c;还可以让他们在自己的兴趣领域中寻求机会&#xff0c;实现自己的财务自由。 在这里&#xff0c;我将为您介绍六…

OpenGL 实现“人像背景虚化“效果

手机上的人像模式,也被人们称作“背景虚化”或 ”双摄虚化“ 模式,也称为 Bokeh 模式,能够在保持画面中指定的人或物体清晰的同时,将其他的背景模糊掉。突出画面的主体部分,主观上美感更强烈。 人像模式的一般实现原理是,利用双摄系统获取景深信息,并通过深度传感器和图…

带流量主功能的外卖菜谱小程序源码:助你轻松领取优惠券,个人使用也可通过审查

外卖菜谱小程序源码-带流量主功能-外卖领劵个人也可过审 这套小程序优点就带很多菜谱&#xff0c;各种你爱吃菜的做法与各类食材介绍营养搭配&#xff0c;相信很多小姐姐会感兴趣。 宝妈宝爸这个小程序肯定能留的住这个群体的人脉流量&#xff0c;这是小程序最大的亮点&#…

深圳区块链交易所app系统开发,撮合交易系统开发

随着区块链技术的迅速发展和数字资产市场的蓬勃发展&#xff0c;区块链交易所成为了数字资产交易的核心场所之一。在这个快速发展的领域中&#xff0c;区块链交易所App系统的开发和撮合交易系统的建设至关重要。本文将探讨区块链交易所App系统开发及撮合交易系统的重要性&#…

【QGIS从shp文件中筛选目标区域导出为shp】

文章目录 1、写在前面2、QGIS将shp文件中目标区域输出为shp2.1、手动点选2.2、高级过滤 3、上述shp完成后&#xff0c;配合python的shp文件&#xff0c;即可凸显研究区域了 1、写在前面 利用shp文件制作研究区域mask&#xff0c;Matlab版本&#xff0c;请点击 Matlab利用shp文…

【Leetcode】单链表常见题

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;Leetcode刷题 本节内容我们来讲解常见的几道单链表的题型&#xff0c;文末会赋上单链表增删查&#xff0c;初始化等代码 目录 1.移除链表元素2.链表的中间节点3.返回倒数第K个节点&#xff1a;4.环…

【Java - 框架 - Lombok】(1) 普通Java项目通过Lombok+Logback完成日志的创建使用 - 快速上手

普通Java项目通过"Lombok""Logback"完成日志的创建使用 - 快速上手&#xff1b; 步骤A 说明 创建"Maven"项目&#xff1b; 图片 步骤B 说明 添加相关依赖项&#xff1b; 图片 代码 <!-- "Lombok"依赖项--> <dependency>&…

C语言--动态内存管理

为什么存在动态内存管理&#xff1f; 在之前我们讲到的类型创建的变量再空间开辟好之后就不能再改变了&#xff0c;但是有时候我们希望能够自由地为某个变量分配空间&#xff0c;就比如上一篇文章中的通讯录&#xff0c;在没有动态内存管理情况下&#xff0c;我们就只能为通讯…

18.字面量

文章目录 一、字面量二、区分技巧三、扩展&#xff1a; /t 制表符 一、字面量 在有些资料&#xff0c;会把字面量说成常量、字面值常量&#xff0c;这种叫法都不是很正确&#xff0c;最正确的叫法还是叫做&#xff1a;字面量。 作用&#xff1a;告诉程序员&#xff0c;数据在…

地物波谱库共享网站汇总

ENVI自5.2版本重新梳理了原有的标准波谱库&#xff0c;新增一些物质波谱&#xff0c;在ENVI5.6中存放在…\Harris\ENVI56\ resource\speclib&#xff0c;分别存放在四个文件夹中&#xff0c;储存为ENVI波谱库格式&#xff0c;有两个文件组成&#xff1a;.sli和.hdr。 ENVI保留…

小米还涉足了哪些领域

小米作为一家全球性的移动互联网企业&#xff0c;其业务领域相当广泛&#xff0c;除了核心的智能手机业务外&#xff0c;还涉足了许多其他领域。以下是对小米涉足领域的简要介绍&#xff1a; 智能硬件与IoT平台&#xff1a;小米是全球领先的智能硬件和IoT平台公司&#xff0c;致…

linux:线程同步

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言线程同步条件变量接口简单示例pthread_cond_wait为什么要有mutex伪唤醒问题的解决 (if->while) 总结 前言 本文作为我对于线程同步知识总结 线程同步 同步&…

资讯头条P3自媒体搭建

自媒体素材管理与文章管理 一.后台搭建 1.1 搭建自媒体网关 导入网关模块>>>在网关模块的pom.xml文件中添加该子模块>>>刷新maven <modules><module>heima-leadnews-app-gateway</module><!--新增--><module>heima-leadnew…

Aurora插件安装

介绍 Latext是一种基于TEX的排版系统。 CTeX中文套装是基于Windows下的MiKTeX系统&#xff0c;集成了编辑器WinEdt和PostScrip处理软件Ghostscript和GSview等主要工具。CTeX中文套装在MikTeX的基础上增加了对中文的完整支持。 CTeX&#xff1a; CTeX套装 - CTEX 下载安装 然后…

【Java程序设计】【C00345】基于Springboot的船舶监造管理系统(有论文)

基于Springboot的船舶监造管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 项目获取 &#x1f345;文末点击卡片获取源码&#x1f345; 开发环境 运行环境&#xff1a;推荐jdk1.8&#xff1b; 开发工具&#xff1a;eclipse以及i…