一篇文章实现Android图片拼接并保存至相册

系列文章目录

一篇文章实现Android图片拼接并保存至相册


在这里插入图片描述

文章目录

  • 系列文章目录
  • 前言
  • 实现功能
  • 类定义和成员变量
    • onCreate方法
    • 权限检查和图片选择
    • 处理选择的图片
    • 图片拼接功能
    • 图片保存功能
  • 使用ImageStitcher类拼接图片
  • 代码解释:ImageStitcher.java
    • 类定义和方法
    • 计算拼接后图片的尺寸
    • 计算逻辑
    • 创建并绘制拼接后的图片
    • 绘制过程
    • 注意事项
  • 效果图
  • 源码
    • MainActivity.java
    • ImageStitcher.java
    • AndroidManifest权限申明
    • activity_main.xml
  • 总结


前言

好久没有写Android系列的文章了,最近有小伙伴问到了Android图片拼接的问题,写一篇相关的博客。

在Android应用中实现图片拼接功能并保存到相册是一个常见的需求,比如制作全景图、拼图应用或照片编辑工具。本文将介绍如何实现一个完整的图片拼接应用,包括图片选择、拼接和保存功能。


实现功能

  1. 检查并请求必要的存储权限
  2. 允许用户从相册选择一张或多张图片
  3. 异步加载选中的图片
  4. 使用ImageStitcher类拼接图片
  5. 将拼接后的图片保存到相册
  6. 在整个过程中显示适当的进度指示和操作反馈

类定义和成员变量

其中包括图片选择请求码,读取权限请求码, 写入权限请求码,保存目录名称,以及相关控件。

public class MainActivity extends AppCompatActivity {private static final int PICK_IMAGE_REQUEST = 1;  // 图片选择请求码private static final int REQUEST_PERMISSION = 2;  // 读取权限请求码private static final int REQUEST_WRITE_PERMISSION = 3;  // 写入权限请求码private static final String SAVE_DIRECTORY = "ImageStitcher";  // 保存目录名称private List<Bitmap> selectedImages = new ArrayList<>();  // 存储选择的图片private ImageView resultView;  // 显示拼接结果的ImageViewprivate ProgressBar progressBar;  // 进度条private Button selectBtn, stitchBtn, saveBtn;  // 按钮控件

onCreate方法

初始化控件以及设置监听

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);  // 设置布局文件// 初始化视图控件resultView = findViewById(R.id.jm_result_image);progressBar = findViewById(R.id.jm_progress_bar);selectBtn = findViewById(R.id.jm_select_btn);stitchBtn = findViewById(R.id.jm_stitch_btn);saveBtn = findViewById(R.id.jm_save_btn);saveBtn.setVisibility(View.GONE);  // 初始时隐藏保存按钮// 设置按钮点击监听器selectBtn.setOnClickListener(v -> checkPermissionAndOpenChooser());stitchBtn.setOnClickListener(v -> stitchImagesAsync());
}

权限检查和图片选择

不动态申请权限小心报错:has no access to content
需在AndroidManifest.xml声明READ_EXTERNAL_STORAGE权限,Android Q及以上版本必须使用MediaStore API访问公共目录文件。

private void checkPermissionAndOpenChooser() {// 检查是否有读取外部存储权限if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {openImageChooser();  // 有权限则直接打开图片选择器} else {// 没有权限则请求权限ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},REQUEST_PERMISSION);}
}private void openImageChooser() {// 创建选择图片的IntentIntent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("image/*");  // 设置类型为图片intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);  // 允许多选startActivityForResult(Intent.createChooser(intent, "选择图片"), PICK_IMAGE_REQUEST);
}// 权限请求结果回调
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_PERMISSION && grantResults.length > 0&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {openImageChooser();  // 权限被授予后打开图片选择器}
}

处理选择的图片

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {handleSelectedImages(data);  // 处理选择的图片}
}private void handleSelectedImages(Intent data) {progressBar.setVisibility(View.VISIBLE);  // 显示进度条ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {try {if (data.getClipData() != null) {processMultipleImages(data.getClipData());  // 处理多张图片} else if (data.getData() != null) {processSingleImage(data.getData());  // 处理单张图片}} finally {runOnUiThread(() -> progressBar.setVisibility(View.GONE));  // 隐藏进度条}});
}private void processMultipleImages(ClipData clipData) {for (int i = 0; i < clipData.getItemCount(); i++) {loadAndAddImage(clipData.getItemAt(i).getUri());  // 加载并添加每张图片}
}private void processSingleImage(Uri uri) {loadAndAddImage(uri);  // 加载并添加单张图片
}private void loadAndAddImage(Uri uri) {try (InputStream is = getContentResolver().openInputStream(uri)) {Bitmap bitmap = BitmapFactory.decodeStream(is);  // 从URI加载图片runOnUiThread(() -> {selectedImages.add(bitmap);  // 添加到图片列表Toast.makeText(this, "成功加载图片", Toast.LENGTH_SHORT).show();});} catch (Exception e) {runOnUiThread(() ->Toast.makeText(this, "加载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show());}
}

图片拼接功能

private void stitchImagesAsync() {if (selectedImages.isEmpty()) return;  // 如果没有选择图片则返回saveBtn.setVisibility(View.VISIBLE);  // 显示保存按钮progressBar.setVisibility(View.VISIBLE);  // 显示进度条ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {// 调用ImageStitcher类拼接图片Bitmap stitched = ImageStitcher.stitchImages(selectedImages.toArray(new Bitmap[0]), 0);runOnUiThread(() -> {resultView.setImageBitmap(stitched);  // 显示拼接结果progressBar.setVisibility(View.GONE);  // 隐藏进度条saveBtn.setVisibility(View.VISIBLE);  // 确保保存按钮可见// 设置保存按钮点击监听器saveBtn.setOnClickListener(v -> saveImageToGallery(stitched));});});
}

图片保存功能

private void saveImageToGallery(Bitmap bitmap) {// 检查是否有写入外部存储权限if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {// 没有权限则请求权限ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_PERMISSION);return;}// 在新线程中执行保存操作new Thread(() -> {String fileName = "stitched_" + System.currentTimeMillis() + ".jpg";ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");// 对于Android Q及以上版本if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + SAVE_DIRECTORY);values.put(MediaStore.Images.Media.IS_PENDING, 1);}try {// 插入媒体库记录Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);try (OutputStream os = getContentResolver().openOutputStream(uri)) {// 压缩并写入图片数据bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);// 对于Android Q及以上版本,更新IS_PENDING标志if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.IS_PENDING, 0);getContentResolver().update(uri, values, null, null);}// 显示保存成功提示runOnUiThread(() ->Toast.makeText(this, "图片已保存至相册", Toast.LENGTH_SHORT).show());}} catch (Exception e) {// 显示保存失败提示runOnUiThread(() ->Toast.makeText(this, "保存失败: " + e.getMessage(), Toast.LENGTH_SHORT).show());}}).start();
}

使用ImageStitcher类拼接图片

代码解释:ImageStitcher.java

这是一个用于拼接多张图片的工具类,提供了将多张图片横向或纵向拼接成一张大图的功能。下面是对代码的详细解释:

类定义和方法

public class ImageStitcher {public static Bitmap stitchImages(Bitmap[] images, int direction) {// 检查输入参数是否有效if (images == null || images.length == 0) return null;

计算拼接后图片的尺寸

        int width = images[0].getWidth();int height = images[0].getHeight();// 计算拼接后图片的总尺寸if (direction == 0) { // 横向拼接for (int i = 1; i < images.length; i++) {width += images[i].getWidth();  // 累加宽度height = Math.max(height, images[i].getHeight());  // 取最大高度}} else { // 纵向拼接for (int i = 1; i < images.length; i++) {height += images[i].getHeight();  // 累加高度width = Math.max(width, images[i].getWidth());  // 取最大宽度}}

计算逻辑

  • 横向拼接:总宽度为所有图片宽度之和,高度为所有图片中的最大高度
  • 纵向拼接:总高度为所有图片高度之和,宽度为所有图片中的最大宽度

创建并绘制拼接后的图片

        // 创建拼接后的BitmapBitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(result);// 绘制图片int currentPos = 0;for (Bitmap image : images) {if (direction == 0) { // 横向拼接canvas.drawBitmap(image, currentPos, 0, null);  // 在当前位置绘制图片currentPos += image.getWidth();  // 更新横向位置} else { // 纵向拼接canvas.drawBitmap(image, 0, currentPos, null);  // 在当前位置绘制图片currentPos += image.getHeight();  // 更新纵向位置}}return result;  // 返回拼接后的图片}
}

绘制过程

  1. 创建一个新的空白Bitmap,大小为之前计算的总尺寸
  2. 使用Canvas在这个Bitmap上绘制所有输入图片
  3. 根据拼接方向,依次将每张图片绘制到正确的位置
  4. 更新当前位置指针(currentPos),以便下一张图片绘制在正确的位置

注意事项

  • 所有输入图片应为非空且尺寸相同(代码中未做严格检查)
  • 拼接方向通过简单的int值判断(0为横向,非0为纵向)
  • 使用了ARGB_8888配置创建Bitmap,保证图片质量
  • 这是一个基础实现,没有处理图片尺寸不一致时的缩放或裁剪

效果图

在这里插入图片描述

源码

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;import android.Manifest;
import android.content.ClipData;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class MainActivity extends AppCompatActivity {private static final int PICK_IMAGE_REQUEST = 1;private static final int REQUEST_PERMISSION = 2;private List<Bitmap> selectedImages = new ArrayList<>();private ImageView resultView;private ProgressBar progressBar;private static final int REQUEST_WRITE_PERMISSION = 3;private static final String SAVE_DIRECTORY = "JmImgStitcher";private Button selectBtn,stitchBtn,saveBtn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);resultView = findViewById(R.id.jm_result_image);progressBar = findViewById(R.id.jm_progress_bar);selectBtn = findViewById(R.id.jm_select_btn);stitchBtn = findViewById(R.id.jm_stitch_btn);// 初始化保存按钮saveBtn = findViewById(R.id.jm_save_btn);saveBtn.setVisibility(View.GONE);selectBtn.setOnClickListener(v -> checkPermissionAndOpenChooser());stitchBtn.setOnClickListener(v -> stitchImagesAsync());}private void checkPermissionAndOpenChooser() {if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)== PackageManager.PERMISSION_GRANTED) {openImageChooser();} else {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},REQUEST_PERMISSION);}}private void openImageChooser() {Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("image/*");intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);startActivityForResult(Intent.createChooser(intent, "选择图片"), PICK_IMAGE_REQUEST);}@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == REQUEST_PERMISSION && grantResults.length > 0&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {openImageChooser();}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {handleSelectedImages(data);}}private void handleSelectedImages(Intent data) {progressBar.setVisibility(View.VISIBLE);ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {try {if (data.getClipData() != null) {processMultipleImages(data.getClipData());} else if (data.getData() != null) {processSingleImage(data.getData());}} finally {runOnUiThread(() -> progressBar.setVisibility(View.GONE));}});}private void processMultipleImages(ClipData clipData) {for (int i = 0; i < clipData.getItemCount(); i++) {loadAndAddImage(clipData.getItemAt(i).getUri());}}private void processSingleImage(Uri uri) {loadAndAddImage(uri);}private void loadAndAddImage(Uri uri) {try (InputStream is = getContentResolver().openInputStream(uri)) {Bitmap bitmap = BitmapFactory.decodeStream(is);runOnUiThread(() -> {selectedImages.add(bitmap);Toast.makeText(this, "成功加载图片", Toast.LENGTH_SHORT).show();});} catch (Exception e) {runOnUiThread(() ->Toast.makeText(this, "加载失败: " + e.getMessage(), Toast.LENGTH_SHORT).show());}}// 修改stitchImagesAsync方法private void stitchImagesAsync() {if (selectedImages.isEmpty()) return;saveBtn.setVisibility(View.VISIBLE);progressBar.setVisibility(View.VISIBLE);ExecutorService executor = Executors.newSingleThreadExecutor();executor.execute(() -> {Bitmap stitched = ImageStitcher.stitchImages(selectedImages.toArray(new Bitmap[0]), 0);runOnUiThread(() -> {resultView.setImageBitmap(stitched);progressBar.setVisibility(View.GONE);//设置出现saveBtn.setVisibility(View.VISIBLE);saveBtn.setOnClickListener(v -> saveImageToGallery(stitched));});});}private void saveImageToGallery(Bitmap bitmap) {if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_WRITE_PERMISSION);return;}new Thread(() -> {String fileName = "stitched_" + System.currentTimeMillis() + ".jpg";ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + File.separator + SAVE_DIRECTORY);values.put(MediaStore.Images.Media.IS_PENDING, 1);}try {Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);try (OutputStream os = getContentResolver().openOutputStream(uri)) {bitmap.compress(Bitmap.CompressFormat.JPEG, 90, os);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {values.put(MediaStore.Images.Media.IS_PENDING, 0);getContentResolver().update(uri, values, null, null);}runOnUiThread(() ->Toast.makeText(this, "图片已保存至相册", Toast.LENGTH_SHORT).show());}} catch (Exception e) {runOnUiThread(() ->Toast.makeText(this, "保存失败: " + e.getMessage(), Toast.LENGTH_SHORT).show());}}).start();}}

ImageStitcher.java


import android.graphics.Bitmap;
import android.graphics.Canvas;public class ImageStitcher {public static Bitmap stitchImages(Bitmap[] images, int direction) {if (images == null || images.length == 0) return null;int width = images[0].getWidth();int height = images[0].getHeight();// 计算拼接后图片的总尺寸if (direction == 0) { // 横向拼接for (int i = 1; i < images.length; i++) {width += images[i].getWidth();height = Math.max(height, images[i].getHeight());}} else { // 纵向拼接for (int i = 1; i < images.length; i++) {height += images[i].getHeight();width = Math.max(width, images[i].getWidth());}}// 创建拼接后的BitmapBitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(result);// 绘制图片int currentPos = 0;for (Bitmap image : images) {if (direction == 0) { // 横向拼接canvas.drawBitmap(image, currentPos, 0, null);currentPos += image.getWidth();} else { // 纵向拼接canvas.drawBitmap(image, 0, currentPos, null);currentPos += image.getHeight();}}return result;}
}

AndroidManifest权限申明

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- Android 10+ 需要添加 --><uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"android:maxSdkVersion="29" />

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ProgressBarandroid:id="@+id/jm_progress_bar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:visibility="gone"/><Buttonandroid:id="@+id/jm_select_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="选择要拼接的图片"/><Buttonandroid:id="@+id/jm_stitch_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="开始拼接图片"/><Buttonandroid:id="@+id/jm_save_btn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="保存图片"android:visibility="gone"/><ImageViewandroid:id="@+id/jm_result_image"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="centerInside"/>
</LinearLayout>

总结

此文章可以作为基础,根据具体需求进行扩展和优化。欢迎留言,如有问题可以联系计蒙。

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

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

相关文章

2025.06.06【Ribo-seq】|riboWaltz:P-site定位与三碱基周期性分析流程

文章目录 一、前言二、riboWaltz简介三、安装与依赖四、分析流程总览1. 数据准备2. 典型分析流程2.1 读取注释和BAM2.2 P-site定位2.3 三碱基周期性与元分析2.4 密码子使用偏好分析 五、可视化与结果解读六、常见问题与注意事项七、实战经验与建议八、参考资料九、结语 一、前言…

思维链的 内部机制和简单理解

思维链的 内部机制和简单理解 思维链是对解决问题的步骤进行规划,规划后将作为上下文 在LLM中继续输出。因为Transform都是一个一个单词生成,没新生成一个单词都会将新生的作为上下文。 可以这么理解,但更准确的简化描述是: 思维链是让模型在回答问题时,先“内部生成”或…

Charles 全流程指南:安装、设置、抓包与注意事项

Charles 是一款功能强大的网络抓包工具&#xff0c;支持 HTTP/HTTPS 流量监控、请求/响应分析、断点调试等功能。本文将从安装到实战抓包&#xff0c;提供完整流程及关键注意事项。 一、安装 Charles 官网下载&#xff1a;访问 Charles 官网&#xff0c;选择对应系统版本&…

全球长序列高分辨率光合有效辐射(PAR)(1984-2018)

时间分辨率&#xff1a;时空间分辨率&#xff1a;1km - 10km共享方式&#xff1a;开放获取数据大小&#xff1a;188.92 GB数据时间范围&#xff1a;1984-01-01 — 2018-12-31元数据更新时间&#xff1a;2022-04-29 数据集摘要 本数据集是一个包含接近35年&#xff08;1984-201…

【Zephyr 系列 11】使用 NVS 实现 BLE 参数持久化:掉电不丢配置,开机自动加载

🧠关键词:Zephyr、NVS、非易失存储、掉电保持、Flash、AT命令保存、配置管理 📌目标读者:希望在 BLE 模块中实现掉电不丢配置、支持产测参数注入与自动加载功能的开发者 📊文章长度:约 5200 字 🔍 为什么要使用 NVS? 在实际产品中,我们经常面临以下场景: 用户或…

解锁Java线程池:性能优化的关键

一、引言 在 Java 并发编程的世界里&#xff0c;线程池是一个至关重要的概念。简单来说&#xff0c;线程池就是一个可以复用线程的 “池子”&#xff0c;它维护着一组线程&#xff0c;这些线程可以被重复使用来执行多个任务&#xff0c;而不是为每个任务都创建一个新的线程。​…

一站式直播工具:助力内容创作者高效开启直播新时代

近年来&#xff0c;随着互联网技术的不断进步和短视频、直播行业的爆发式增长&#xff0c;越来越多的企业和个人投入到直播电商、互动娱乐、在线教育等场景。直播运营过程中&#xff0c;涉及到数据统计、弹幕互动、流程自动化、内容同步等诸多环节。如何提升运营效率、减少人工…

数论——同余问题全家桶3 __int128和同余方程组

数论——同余问题全家桶3 __int128和同余方程组 快速读写和__int128快速读写__int128 中国剩余定理和线性同余方程组中国剩余定理(CRT)中国剩余定理OJ示例模板题曹冲养猪 - 洛谷模板题猜数字 - 洛谷 扩展中国剩余定理扩展中国剩余定理OJ示例模板题扩展中国剩余定理&#xff08;…

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…

㊗️高考加油

以下是极为详细的高考注意事项清单&#xff0c;涵盖考前、考中、考后全流程&#xff0c;建议逐条核对&#xff1a; 一、考前准备 1. 证件与物品 必带清单&#xff1a; 准考证&#xff1a;打印2份&#xff08;1份备用&#xff09;&#xff0c;塑封或夹在透明文件袋中防皱湿。身…

学习路之PHP--webman安装及使用、webman/admin安装

学习路之PHP--webman安装及使用、webman/admin安装 一、安装webman二、运行三、安装webman/admin四、效果五、配置Nginx反向代理&#xff08;生产环境&#xff1a;可选&#xff09;六、win10运行问题集七、使用 一、安装webman 准备&#xff1a; PHP > 8.1 Composer > 2…

mamba架构和transformer区别

Mamba 架构和 Transformer 架构存在多方面的区别&#xff0c;具体如下&#xff1a; 计算复杂度1 Transformer&#xff1a;自注意力机制的计算量会随着上下文长度的增加呈平方级增长&#xff0c;例如上下文增加 32 倍时&#xff0c;计算量可能增长 1000 倍&#xff0c;在处理长序…

Python爬虫实战:研究mechanize库相关技术

1. 引言 随着互联网数据量的爆炸式增长,网络爬虫已成为数据采集和信息挖掘的重要工具。Python 作为一种功能强大且易于学习的编程语言,拥有丰富的爬虫相关库,如 Requests、BeautifulSoup、Scrapy 等。Mechanize 库作为其中的一员,特别擅长处理复杂的表单提交和会话管理,为…

如何使用索引和条件批量更改Series数据

视频演示 如何通过索引与布尔条件修改 pandas Series&#xff1f;实操演示来了 一、前言&#xff1a;掌握Series数据修改是数据处理的基础 在使用Python进行数据分析时&#xff0c;Pandas库的Series对象是最常用的结构之一。在上一个视频中我们已经学习了如何创建Series对象&a…

CentOS 7 如何安装llvm-project-10.0.0?

CentOS 7 如何安装llvm-project-10.0.0&#xff1f; 需要先升级gcc至7.5版本&#xff0c;详见CentOS 7如何编译安装升级gcc版本?一文 # 备份之前的yum .repo文件至 /tmp/repo_bak 目录 mkdir -p /tmp/repo_bak && cd /etc/yum.repo.d && /bin/mv ./*.repo …

6个月Python学习计划 Day 15 - 函数式编程、高阶函数、生成器/迭代器

第三周 Day 1 &#x1f3af; 今日目标 掌握 Python 中函数式编程的核心概念熟悉 map()、filter()、reduce() 等高阶函数结合 lambda 和 列表/字典 进行数据处理练习了解生成器与迭代器基础&#xff0c;初步掌握惰性计算概念 &#x1f9e0; 函数式编程基础 函数式编程是一种…

SpringCloud Gateway 集成 Sentinel 详解 及实现动态监听Nacos规则配置实时更新流控规则

目录 一、前言二、版本选择和适配 2.1、本文使用各组件版本2.2、官方推荐版本 三、部署sentinel-dashboard 3.1、下载 sentinel-dashboard jar包3.2、启动 sentinel-dashboard 四、Gateway 集成 Sentinel实现控制台配置流控规则测试 4.1、添加Gateway 集成 Sentinel 包4.2、添加…

Linux八股【1】-----虚拟内存

参考&#xff1a;小林coding 虚拟内存存在的目的&#xff1f; 为了能够同时运行多个进程同时进程之间互不干扰 虚拟地址通过MMU找到物理地址 物理内存怎么映射的&#xff1f; 物理内存的映射方法主要有两种&#xff0c;内存分段和内存分页 内存分段 把程序的不同区&#…

惊艳呈现:探索数据可视化的艺术与科学

一张图表真能胜过千言万语&#xff1f;当超市销售数据变成跳动的热力图&#xff0c;当城市交通拥堵状况化作流动的光带&#xff0c;数据可视化正以超乎想象的方式重塑我们认知世界的维度。但你是否想过&#xff0c;那些看似精美直观的图表背后&#xff0c;藏着怎样精密的科学逻…

06-排序

排序 1. 排序的概念及其应用 1.1 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键…