CUDA小白 - NPP(2) -图像处理-算数和逻辑操作

news2024/11/24 4:24:23

cuda小白
原文链接 NPP

GPU架构近些年也有不少的变化,具体的可以参考别的博主的介绍,都比较详细。还有一些cuda中的专有名词的含义,可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》

常见的NppStatus,可以看这里。

如有问题,请指出,谢谢

Arithmetic Operations

当前模块主要是加减乘除,abs,平方,矩阵相乘,开根,ln,exp等。不同相同功能,以其中一个为例进行介绍。

AddC

针对图像中每一个像素添加一个常量值。与之类似的还有MulC,SubC,DivC,AbsDiffC,MulScale
大概接口样式:

// 两个结果的区别在于,有I的结果可以就原始的图像地址进行操作,无需进行拷贝
// Sfs的含义 表示可以对图像的数值范围进行约束操作。
NppStatus nppiAddC_[数据类型]_C[通道数]RSfs_[是否使用流]
NppStatus nppiAddC_[数据类型]_C[通道数]IRSfs_[是否使用流]

以为三通道的uint8_t的图像数据为例子:

NppStatus nppiAddC_8u_C3RSfs(const Npp8u * pSrc1,
							 int nSrc1Step,
							 const Npp8u aConstants[3],
							 Npp8u *pDst,
							 int nDstStep,
							 NppiSize oSizeROI,
							 int nScaleFactor);
NppStatus nppiAddC_8u_C3RSfs(const Npp8u aConstants[3],
							 Npp8u *pDst,
							 int nDstStep,
							 NppiSize oSizeROI,
							 int nScaleFactor);	
code
#include <iostream>
#include <cuda_runtime.h>
#include <npp.h>
#include <opencv2/opencv.hpp>

#define CUDA_FREE(ptr) { if (ptr != nullptr) { cudaFree(ptr); ptr = nullptr; } }

int main() {
  std::string directory = "../";
  // =============== load image ===============
  cv::Mat image = cv::imread(directory + "dog.png");
  if (image.empty()) {
    std::cout << "Load image error!" << std::endl;
    return -1;
  }

  int image_width = image.cols;
  int image_height = image.rows;
  int image_size = image_width * image_height * 3 * sizeof(uint8_t);
  std::cout << "Image info : image_width = " << image_width
            << ", image_height = " << image_height << std::endl;

  // =============== malloc && cpy ===============
  uint8_t *in_ptr, *in_ptr2, *out_ptr, *roi_out_ptr;
  cudaMalloc((void**)&in_ptr, image_size);
  cudaMalloc((void**)&in_ptr2, image_size);
  cudaMalloc((void**)&out_ptr, image_size);
  cudaMalloc((void**)&roi_out_ptr, image_size);
  cudaMemcpy(in_ptr, image.data, image_size, cudaMemcpyHostToDevice);
  cudaMemcpy(in_ptr2, image.data, image_size, cudaMemcpyHostToDevice);

  uint8_t host_constant[3] = { (uint8_t)0, (uint8_t)20, (uint8_t)0 };

  NppiSize roi1, roi2;
  roi1.width = image_width;
  roi1.height = image_height;
  roi2.width = image_width / 2;
  roi2.height = image_height / 2;
  
  // nppiAddC_8u_C3RSfs
  cv::Mat out_image = cv::Mat::zeros(image_height, image_width, CV_8UC3);
  NppStatus status;
  status = nppiAddC_8u_C3RSfs(in_ptr, image_width * 3, host_constant, out_ptr, 
                              image_width * 3, roi1, 0);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAddC_8u_C3RSfs failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr, image_size, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "add_constant.jpg", out_image);

  status = nppiAddC_8u_C3RSfs(in_ptr, image_width * 3, host_constant, out_ptr, image_width * 3, 
                              roi1, 1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAddC_8u_C3RSfs failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr, image_size, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "add_constant_scale.jpg", out_image);

  status = nppiAddC_8u_C3RSfs(in_ptr, image_width * 3, host_constant, out_ptr, image_width * 3, 
                              roi2, 0);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAddC_8u_C3RSfs failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr, image_size, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "add_constant_roi.jpg", out_image);

  // free
  CUDA_FREE(in_ptr)
  CUDA_FREE(in_ptr2)
  CUDA_FREE(out_ptr)
  CUDA_FREE(roi_out_ptr)
}
make
cmake_minimum_required(VERSION 3.20)
project(test)

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

find_package(CUDA REQUIRED)
include_directories(${CUDA_INCLUDE_DIRS})
file(GLOB CUDA_LIBS "/usr/local/cuda/lib64/*.so")

add_executable(test test.cpp)
target_link_libraries(test
                      ${OpenCV_LIBS}
                      ${CUDA_LIBS}
)
result

请添加图片描述
注意点:

  1. 对图像的进行值的范围进行一定的约束,最初的图像RGB的值都是[0, 255],如果对应的scale设置为1的时候,相当于将数值的范围变为2的-nScaleFactor倍数,即[0, 128],超过128的会变成128,因此整体的图像色调会变暗;同样的,如果设置为-1,则整体的会变为2倍,因为存图的限制只能是[0, 255],所以整体看起来会变亮。
  2. 如果指定的roi不是整张图的时候,由于roi的类型是NppiSize(width, height),因此输入的指针不是指向图像的起始位置,而是roi的起始位置。
  3. MulScale相较于MulC来说,默认nScaleFactor为0;
  4. AbsDiffC中主要功能就是得到整张图像与host_constant的绝对差值。
  5. 每个结果都有一个对应的包含cudastream的版本,按需使用。

Add

与AddC不同的是,Add输入的是两张图像。同样的还有Mul,MulScale,Sub,Div,Div_round,Abs,AbsDiff,Sqr,Sqrt,Ln,Exp。(由于Abs,AbsDiff,Sqr,Sqrt,Ln,Exp在图像出列方面使用的不是很多,就不细述)。
以uint8_t的三通道图像为例:

// 命名规则与nppiAddC*类似
NppStatus nppiAdd_8u_C3RSfs(const Npp8u * pSrc1,
							int nSrc1Step,
						    const Npp8u *pSrc2,
							int nSrc2Step,
							Npp8u * pDst,
							int nDstStep,
							NppiSize oSizeROI,
							int nScaleFactor);
NppStatus nppiAdd_8u_C3IRSfs(const Npp8u *pSrc,
							 int nSrcStep,
							 Npp8u *pSrcDst,
							 int nSrcDstStep,
							 NppiSize oSizeROI,
							 int nScaleFactor);
code
#include <iostream>
#include <cuda_runtime.h>
#include <npp.h>
#include <opencv2/opencv.hpp>

#define PRINT_VALUE(value) {  \
  std::cout << "[GPU] " << #value << " = " << value << std::endl; }

#define CUDA_FREE(ptr) { if (ptr != nullptr) { cudaFree(ptr); ptr = nullptr; } }

int main() {
  std::string directory = "../";
  // =============== load image ===============
  cv::Mat image = cv::imread(directory + "dog.png");
  if (image.empty()) {
    std::cout << "Load image error!" << std::endl;
    return -1;
  }

  int image_width = image.cols;
  int image_height = image.rows;
  int image_size = image_width * image_height * 3 * sizeof(uint8_t);
  std::cout << "Image info : image_width = " << image_width
            << ", image_height = " << image_height << std::endl;

  // =============== malloc && cpy ===============
  uint8_t *in_ptr, *in_ptr2, *out_ptr, *roi_out_ptr;
  cudaMalloc((void**)&in_ptr, image_size);
  cudaMalloc((void**)&in_ptr2, image_size);
  cudaMalloc((void**)&out_ptr, image_size);
  cudaMalloc((void**)&roi_out_ptr, image_size);
  cudaMemcpy(in_ptr, image.data, image_size, cudaMemcpyHostToDevice);
  cudaMemcpy(in_ptr2, image.data, image_size, cudaMemcpyHostToDevice);

  NppiSize roi1, roi2;
  roi1.width = image_width;
  roi1.height = image_height;
  roi2.width = image_width / 2;
  roi2.height = image_height / 2;
  
  // nppiAdd_8u_C3RSfs
  cv::Mat out_image = cv::Mat::zeros(image_height, image_width, CV_8UC3);
  NppStatus status;
  status = nppiAdd_8u_C3RSfs(in_ptr, image_width * 3, in_ptr2, image_width * 3, out_ptr, 
                             image_width * 3, roi1, 0);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAdd_8u_C3RSfs failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr, image_size, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "add.jpg", out_image);

  status = nppiAdd_8u_C3RSfs(in_ptr, image_width * 3, in_ptr2, image_width * 3, out_ptr, 
                             image_width * 3, roi1, 1);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAdd_8u_C3RSfs failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr, image_size, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "add_scale.jpg", out_image);

  status = nppiAdd_8u_C3RSfs(in_ptr, image_width * 3, in_ptr2, image_width * 3, out_ptr, 
                             image_width * 3, roi2, 0);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAdd_8u_C3RSfs failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr, image_size, cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "add_roi.jpg", out_image);

  // free
  CUDA_FREE(in_ptr)
  CUDA_FREE(in_ptr2)
  CUDA_FREE(out_ptr)
  CUDA_FREE(roi_out_ptr)
}
make
cmake_minimum_required(VERSION 3.20)
project(test)

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

find_package(CUDA REQUIRED)
include_directories(${CUDA_INCLUDE_DIRS})
file(GLOB CUDA_LIBS "/usr/local/cuda/lib64/*.so")

add_executable(test test.cpp)
target_link_libraries(test
                      ${OpenCV_LIBS}
                      ${CUDA_LIBS}
)
result

请添加图片描述
注意点:

  1. nScaleFactor与AddC中的功能一致。roi的操作也与AddC中的一致。
  2. 由于使用的是两个相同的图片进行相加,因此在nScaleFactor为1的时候,所有的数值都变成原来的值,因此保存的图像与原图一致。
  3. 同样有cudastream版本,按需使用。

AddWeighted

将特定区域的图像进行填充weight

NppStatus nppiAddWeighted_8u32f_C1IR(const Npp8u *pSrc,
									 int nSrcStep,
									 Npp32f * pSrcDst,
									 int nSrcDstStep,
									 NppiSize oSizeROI,
								     Npp32f nAlpha);
NppStatus nppiAddWeighted_8u32f_C1IMR(const Npp8u *pSrc,
									  int nSrcStep,
									  const Npp8u *pMask,
									  int nMaskStep,
									  Npp32f * pSrcDst,
									  int nSrcDstStep,
									  NppiSize oSizeROI,
									  Npp32f nAlpha);	
code
#include <iostream>
#include <cuda_runtime.h>
#include <npp.h>
#include <opencv2/opencv.hpp>

#define PRINT_VALUE(value) {  \
  std::cout << "[GPU] " << #value << " = " << value << std::endl; }

#define CUDA_FREE(ptr) { if (ptr != nullptr) { cudaFree(ptr); ptr = nullptr; } }

int main() {
  std::string directory = "../";
  // =============== load image ===============
  cv::Mat image = cv::imread(directory + "dog.png");
  if (image.empty()) {
    std::cout << "Load image error!" << std::endl;
    return -1;
  }

  cv::Mat gray;
  cv::cvtColor(image, gray, CV_BGR2GRAY);
  cv::imwrite(directory + "gray.jpg", gray);

  int image_width = gray.cols;
  int image_height = gray.rows;
  int image_size = image_width * image_height;
  std::cout << "Image info : image_width = " << image_width
            << ", image_height = " << image_height << std::endl;

  cv::Mat mat_mask = cv::Mat::ones(image_height, image_width, CV_8UC1);

  cv::Rect rc_center = cv::Rect(image_width / 4, image_height / 4, 
                                image_width / 2, image_height / 2);
  mat_mask(rc_center) = cv::Mat::ones(image_height / 2, image_width / 2, CV_8UC1) * 255;
  cv::imwrite(directory + "mask.jpg", mat_mask);

  // =============== malloc && cpy ===============
  uint8_t *in_ptr, *mask;
  cudaMalloc((void**)&in_ptr, image_size * sizeof(uint8_t));
  cudaMalloc((void**)&mask, image_size * sizeof(uint8_t));
  cudaMemcpy(in_ptr, gray.data, image_size, cudaMemcpyHostToDevice);
  cudaMemcpy(mask, mat_mask.data, image_size, cudaMemcpyHostToDevice);

  float *out_ptr, *out_ptr1, *out_ptr2;
  cudaMalloc((void**)&out_ptr, image_size * sizeof(float));
  cudaMalloc((void**)&out_ptr1, image_size * sizeof(float));
  cudaMalloc((void**)&out_ptr2, image_size * sizeof(float));
  
  NppiSize roi1, roi2;
  roi1.width = image_width;
  roi1.height = image_height;
  roi2.width = image_width / 2;
  roi2.height = image_height / 2;
  
  // nppiAdd_8u_C3RSfs
  cv::Mat out_image = cv::Mat::zeros(image_height, image_width, CV_32FC1);
  NppStatus status;
  status = nppiAddWeighted_8u32f_C1IMR(in_ptr, image_width * sizeof(uint8_t), 
                                       mask, image_width * sizeof(uint8_t), 
                                       out_ptr, image_width * sizeof(float), 
                                       roi1, 1.0);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAddWeighted_8u32f_C1IMR failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr, image_size * sizeof(float), cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "addweight.jpg", out_image);

  status = nppiAddWeighted_8u32f_C1IMR(in_ptr, image_width * sizeof(uint8_t), 
                                       mask, image_width * sizeof(uint8_t), 
                                       out_ptr1, image_width * sizeof(float), 
                                       roi1, 0.5);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAddWeighted_8u32f_C1IMR failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr1, image_size * sizeof(float), cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "addweight_scale.jpg", out_image);

  status = nppiAddWeighted_8u32f_C1IMR(in_ptr, image_width * sizeof(uint8_t), 
                                       mask, image_width * sizeof(uint8_t), 
                                       out_ptr2, image_width * sizeof(float), 
                                       roi2, 0.5);
  if (status != NPP_SUCCESS) {
    std::cout << "[GPU] ERROR nppiAddWeighted_8u32f_C1IMR failed, status = " << status << std::endl;
    return false;
  }
  cudaMemcpy(out_image.data, out_ptr2, image_size * sizeof(float), cudaMemcpyDeviceToHost);
  cv::imwrite(directory + "addweight_roi_scale.jpg", out_image);

  // free
  CUDA_FREE(in_ptr)
  CUDA_FREE(mask)
  CUDA_FREE(out_ptr)
  CUDA_FREE(out_ptr1)
  CUDA_FREE(out_ptr2)
}
make
cmake_minimum_required(VERSION 3.20)
project(test)

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

find_package(CUDA REQUIRED)
include_directories(${CUDA_INCLUDE_DIRS})
file(GLOB CUDA_LIBS "/usr/local/cuda/lib64/*.so")

add_executable(test test.cpp)
target_link_libraries(test
                      ${OpenCV_LIBS}
                      ${CUDA_LIBS}
)
result

请添加图片描述
注意点:
1.nAlpha是针对原图中的每一个像素的值需要添加的权重,mask仅影响目标位置中那些部分需要输出。
2. roi表示输入的区域约束。

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

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

相关文章

手机无人直播软件有哪些,又有哪些优势?

如今&#xff0c;随着智能手机的普及和移动互联网的发展&#xff0c;手机无人直播成为了一个炙手可热的领域。手机无人直播软件为用户提供了便捷、灵活的直播方式&#xff0c;让更多商家人能够实现自己的直播带货的梦想。接下来&#xff0c;我们将探讨手机无人直播软件有哪些&a…

解密算法与数据结构面试:程序员如何应对挑战

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

el-upload调用内部方法删除文件

从Element UI 的官方文档中&#xff0c; Upload 上传组组件提供了on-remove和before-remove的文件删除的钩子属性&#xff08;回调方法名&#xff09;&#xff0c;但如何调用组件删除方法&#xff08;让该方法删除本地上传文件列表以及触发这两个钩子&#xff09;并无相关说明。…

解锁安全高效办公——私有化部署的WorkPlus即时通讯软件

在当今信息时代&#xff0c;高效的沟通与协作对于企业的成功至关重要。然而&#xff0c;随着信息技术的发展&#xff0c;保护敏感信息和数据安全也变得越来越重要。为了满足企业对于安全沟通和高效办公的需求&#xff0c;我们隆重推出私有化部署的WorkPlus即时通讯软件&#xf…

Marin说PCB之如何使用CAM350做Gerber compare ?

最近小编在追一部东北武侠喜剧&#xff08;鹊刀门传奇&#xff09;&#xff0c;大部分人员都是乡村爱情的人员演的&#xff0c;这部剧真的是超级搞笑&#xff0c;小编我以人格担保要是不搞笑的话&#xff0c;你来找我。 正当小编我周日在家里追剧的时候&#xff0c;手机上弹出了…

Git仓库简介

1、工作区、暂存区、仓库 工作区&#xff1a;电脑里能看到的目录。 暂存区&#xff1a;工作区有一个隐藏目录.git&#xff0c;是Git的版本库&#xff0c;Git的版本库里存了很多东西&#xff0c;其中最重要的就是称为stage&#xff08;或者叫index&#xff09;的暂存区&#xf…

【技术】SpringBoot Word 模板替换

SpringBoot Word 模板替换 什么是 Word 模板替换如何实现 Word 模板替换 什么是 Word 模板替换 模板一般是具有固定格式的内容&#xff0c;其中一部分需要替换。Word 模板通俗的讲是以 Word 的形式制作模板&#xff0c;固定格式和内容&#xff0c;然后将其中的一部分数据替换掉…

第 1 章 绪论 (三元组)

1. 示例代码&#xff1a; 1&#xff09;status.h /* DataStructure 预定义常量和类型头文件 */#ifndef STATUS_H #define STATUS_H/* 函数结果状态码 */ #define TRUE 1 /* 返回值为真 */ #define FALSE 0 /* 返回值为假 */ #define RET_OK 0 /* 返回值…

电脑不安装软件,怎么将手机文件传输到电脑?

很多人都知道&#xff0c;AirDroid有网页版&#xff08;web.airdroid.com&#xff09;。 想要文件传输&#xff0c;却不想在电脑安装软件时&#xff0c;AirDroid的网页版其实也可以传输文件。 然而&#xff0c;要将文件从手机传输文件到网页端所在的电脑时&#xff0c;如果按…

Vue05_关于插槽和指令封装的运用

Vue_05 文章目录 Vue_05Vue 插槽01-插槽-默认插槽默认插槽-基本语法 02-插槽-后备内容&#xff08;默认值&#xff09;默认值设置方法 03-插槽-具名插槽具名插槽-语法 04-插槽-作用域插槽默认插槽-语法代码示例 Vue自定义指令- v-loading封装01-自定义指令自定义指令的两种注册…

【算法专题突破】双指针 - 盛最多水的容器(4)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;11. 盛最多水的容器 - 力扣&#xff08;Leetcode&#xff09; 这道题目也不难理解&#xff0c; 两边的柱子的盛水量是根据短的那边的柱子决定的&#xff0c; 而盛水量…

如何清空小程序会员卡的电子票

​电子票不仅方便了用户的购票和消费&#xff0c;还提升了用户的购物体验和忠诚度。然而&#xff0c;在一些特殊情况下&#xff0c;可能需要手动清空会员的电子票。那么&#xff0c;下面我们就来探讨一下在小程序中如何手动清空会员的电子票。 1. 找到指定的会员卡。在管理员后…

15.CSS发光按钮的悬停特效

效果 源码 <!DOCTYPE html> <html> <head><title>CSS Modern Button</title><link rel="stylesheet" type="text/css" href="style.css"> </head> <body><a href="#" style=&quo…

Flink CDC学习笔记

第一章 CDC简介 1.1 什么是CDC ​ CDC (Change Data Capture 变更数据获取&#xff09;的简称。核心思想就是&#xff0c;检测并获取数据库的变动&#xff08;增删查改&#xff09;&#xff0c;将这些变更按发生的顺序记录下来&#xff0c;写入到消息中间件以供其它服务进行订…

公网远程访问局域网SQL Server数据库

文章目录 1.前言2.本地安装和设置SQL Server2.1 SQL Server下载2.2 SQL Server本地连接测试2.3 Cpolar内网穿透的下载和安装2.3 Cpolar内网穿透的注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 数据库的重要性相信大家都有所了解&…

Deep Learning With Pytorch - 数据预处理,以导入LUNA16数据集为例

文章目录 数据集简介什么是CT扫描&#xff1f;导入大型数据集并不是一份轻松的工作 在Jupyter Notebook中导入LUNA16数据集导入可能用到的第三方库&#xff1a;LUNA16存放路径&#xff1a;用 pandas 读取 candidates.csv&#xff1b;读取 annotations.csv导入subset0和subset1的…

[FPGA IP系列] BRAM IP参数配置与使用示例

FPGA开发中使用频率非常高的两个IP就是FIFO和BRAM&#xff0c;上一篇文章中已经详细介绍了Vivado FIFO IP&#xff0c;今天我们来聊一聊BRAM IP。 本文将详细介绍Vivado中BRAM IP的配置方式和使用技巧。 一、BRAM IP核的配置 1、打开BRAM IP核 在Vivado的IP Catalog中找到B…

ubuntu上安装nginx

这篇文章主要介绍怎么在ubuntu上安装nginx服务器&#xff0c;并配置简单的反向代理功能。 第一步&#xff1a;准备好一台ubuntu操作系统的虚拟机 注意&#xff1a;如果你还没有安装好ubuntu&#xff0c;个人推荐阅读以下文章完成unbutu安装&#xff0c;vm的版本不用刻意安装文…

Python ArcPy将多个文件夹内大量遥感影像批量四等分裁剪或切割为N×M个部分

本文介绍基于Python中的ArcPy模块&#xff0c;基于一个大文件夹&#xff0c;遍历其中每一个子文件夹中所有的遥感影像栅格文件&#xff0c;并将原本的每一景遥感影像文件四等分切割&#xff0c;或裁剪为其他指定个数的小块的方法。 首先明确一下我们的需求。现有一个大文件夹&a…

数据结构之单链表java实现

基本概念 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中指针链接次序实现的。和数组相比较&#xff0c;链表不需要指定大小&#xff0c;也不需要连续的地址。 单链表的基本设计思维是&#xff0c;利用结构体的设置&#xff0c…