Android Studio C++/JNI/Kotlin 示例 二

MainActivity.kt

package com.demo.learn1import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivityclass MainActivity : ComponentActivity() {// 加载原生库init {System.loadLibrary("native_code")}// 声明原生方法// 数学运算private external fun computeFactorial(n: Int): Intprivate external fun computeFibonacci(n: Int): Int// 字符串处理private external fun reverseString(input: String): Stringprivate external fun countVowels(input: String): Int// 数组处理private external fun sumIntArray(array: IntArray): Int// 复杂对象处理data class User(val name: String, val age: Int)private external fun processUserData(user: User): Stringoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 计算5的阶乘和斐波那契数列第10项Log.d("Native", "5! = ${computeFactorial(5)}")Log.d("Native", "fib(10) = ${computeFibonacci(10)}")// 测试字符串反转和元音计数功能val testStr = "Hello, JNI!"Log.d("Native", "Reversed: ${reverseString(testStr)}")Log.d("Native", "Vowel count: ${countVowels(testStr)}")// 计算数组元素的和val numbers = intArrayOf(1, 2, 3, 4, 5)Log.d("Native", "Array sum: ${sumIntArray(numbers)}")// 创建User对象并传递给本地方法处理val user = User("张三", 25)Log.d("Native", processUserData(user))}
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1) #指定 CMake 的最低版本要求(这里是 3.4.1,Android NDK 的常见要求)
set(CMAKE_CXX_STANDARD 11)  # 启用C++11支持# 定义库和源文件
add_library( # 设置库名称native_code# 设置库类型为共享库SHARED# 提供源文件的相对路径jni_interface.cppmath_operations.cppstring_processor.cppdata_converter.cpp
)# 查找日志库
find_library( # 设置路径变量名称log-lib# 指定CMake要查找的NDK库名称log )# 指定库应该链接到的目标库
target_link_libraries( # 指定目标库native_code# 将目标库链接到日志库${log-lib} )

jni_interface.cpp

这段代码是用C++实现的JNI(Java Native Interface)接口,它连接了Java/Kotlin代码和本地C++代码。

#include "jni_interface.h"
#include <jni.h> //JNI核心头文件,提供与Java交互的所有必要定义
#include <string> //C++标准字符串库
#include <android/log.h> //Android日志输出功能
// 包含自定义类头文件
#include "math_operations.h"
#include "string_processor.h"
#include "data_converter.h"
//定义了日志宏LOGI,方便输出调试信息
#define LOG_TAG "NativeCode"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)extern "C" {// 数学运算示例
JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_computeFactorial(JNIEnv* env,jobject /* this */,jint n) {return math_operations::factorial(n);
}JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_computeFibonacci(JNIEnv* env,jobject /* this */,jint n) {return math_operations::fibonacci(n);
}// 字符串处理示例
JNIEXPORT jstring JNICALL
Java_com_demo_learn1_MainActivity_reverseString(JNIEnv* env,jobject /* this */,jstring input) {std::string cppStr = data_converter::convertJavaStringToCpp(env, input);std::string reversed = string_processor::reverseString(cppStr);return env->NewStringUTF(reversed.c_str());
}JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_countVowels(JNIEnv* env,jobject /* this */,jstring input) {std::string cppStr = data_converter::convertJavaStringToCpp(env, input);return string_processor::countVowels(cppStr);
}// 数组处理示例
JNIEXPORT jint JNICALL
Java_com_demo_learn1_MainActivity_sumIntArray(JNIEnv* env,jobject /* this */,jintArray array) {std::vector<int> numbers = data_converter::convertJavaArrayToVector(env, array);int sum = 0;for (int num : numbers) {sum += num;}return sum;
}// 复杂对象示例
JNIEXPORT jstring JNICALL
Java_com_demo_learn1_MainActivity_processUserData(JNIEnv* env,jobject /* this */,jobject user) {jclass userClass = env->GetObjectClass(user);// 获取字段IDjfieldID nameField = env->GetFieldID(userClass, "name", "Ljava/lang/String;");jfieldID ageField = env->GetFieldID(userClass, "age", "I");// 获取字段值jstring name = (jstring)env->GetObjectField(user, nameField);jint age = env->GetIntField(user, ageField);// 处理数据std::string cppName = data_converter::convertJavaStringToCpp(env, name);std::string processed = "User: " + cppName + ", Age: " + std::to_string(age);// 清理引用env->DeleteLocalRef(name);env->DeleteLocalRef(userClass);return env->NewStringUTF(processed.c_str());
}} // extern "C"

processUserData方法讲解

  • 参数

    • JNIEnv* env:JNI环境指针,提供所有JNI功能

    • jobject this:Java中调用该native方法的对象实例(本例未使用)

    • jobject user:传入的Java User对象

1.获取Java类信息

jclass userClass = env->GetObjectClass(user);
  • GetObjectClass:获取传入Java对象的类对象

  • 返回的jclass是Java中Class<User>的本地表示

  • 这是后续访问字段和方法的基础

2. 获取字段ID

jfieldID nameField = env->GetFieldID(userClass, "name", "Ljava/lang/String;");
jfieldID ageField = env->GetFieldID(userClass, "age", "I");
  • GetFieldID:获取字段标识符,需要:

    • 类对象(userClass)

    • 字段名("name""age")

    • 字段签名:

      • "Ljava/lang/String;":Java的String类型

      • "I":Java的int类型

  • 字段ID是后续访问字段的"钥匙"

3. 获取字段值

jstring name = (jstring)env->GetObjectField(user, nameField);
jint age = env->GetIntField(user, ageField);
  • GetObjectField:获取对象类型字段的值(如String)

    • 需要对象实例和字段ID

    • 返回jobject,需要转型为具体类型(如jstring

  • GetIntField:获取基本类型int字段的值

    • 直接返回对应的基本类型(jint实际上是int的别名)

4. 数据处理

std::string cppName = data_converter::convertJavaStringToCpp(env, name);
std::string processed = "User: " + cppName + ", Age: " + std::to_string(age);
  • 将Java字符串转换为C++字符串(使用辅助工具类)

  • 构造新的字符串信息,组合name和age

  • std::to_string:将数字转换为字符串

5. 资源清理

env->DeleteLocalRef(name);
env->DeleteLocalRef(userClass);
  • DeleteLocalRef:删除本地引用,防止内存泄漏

  • JNI中的本地引用在函数返回后不会自动释放

  • 虽然现代JVM通常能处理这些引用,但显式释放是良好实践

6. 返回结果

return env->NewStringUTF(processed.c_str());
  • NewStringUTF:将C字符串(UTF-8)转换为Java字符串(jstring)

  • 这个返回的jstring会被自动管理,不需要手动释放

1. 基本类型映射

JNI定义了与Java基本类型对应的C/C++类型:

Java类型JNI类型C/C++类型大小
booleanjbooleanunsigned char8位
bytejbytesigned char8位
charjcharunsigned short16位
shortjshortshort16位
intjintint32位
longjlonglong long64位
floatjfloatfloat32位
doublejdoubledouble64位

2. 理解类型转换

字符串转换

Java字符串(jstring)与C/C++字符串的转换是常见操作:

// Java String → C++ std::string
std::string jstringToStdString(JNIEnv* env, jstring jStr) {if (!jStr) return "";const char* cStr = env->GetStringUTFChars(jStr, nullptr);std::string cppStr(cStr);env->ReleaseStringUTFChars(jStr, cStr);return cppStr;
}// C++ std::string → Java String
jstring stdStringToJstring(JNIEnv* env, const std::string& cppStr) {return env->NewStringUTF(cppStr.c_str());
}

数组转换

处理Java数组更复杂一些:

// Java int[] → C++ std::vector<int>
std::vector<int> jintArrayToVector(JNIEnv* env, jintArray array) {std::vector<int> result;jsize length = env->GetArrayLength(array);if (length <= 0) return result;jint* elements = env->GetIntArrayElements(array, nullptr);result.assign(elements, elements + length);env->ReleaseIntArrayElements(array, elements, 0);return result;
}// C++ std::vector<int> → Java int[]
jintArray vectorToJintArray(JNIEnv* env, const std::vector<int>& vec) {jintArray result = env->NewIntArray(vec.size());env->SetIntArrayRegion(result, 0, vec.size(), vec.data());return result;
}

3. 内存管理和引用释放

引用类型

JNI有三种引用类型:

  1. 局部引用(Local Reference)

    • 默认创建的引用

    • 仅在当前native方法有效

    • 方法返回后自动释放,但应及时手动释放

  2. 全局引用(Global Reference)

    • 需要显式创建:env->NewGlobalRef()

    • 跨多个native调用有效

    • 必须显式释放:env->DeleteGlobalRef()

  3. 弱全局引用(Weak Global Reference)

    • 类似全局引用但不阻止GC

    • 创建:env->NewWeakGlobalRef()

    • 释放:env->DeleteWeakGlobalRef()

最佳实践

JNIEXPORT void JNICALL Java_Example_memoryExample(JNIEnv* env, jobject obj) {// 1. 创建局部引用jclass localClass = env->FindClass("java/lang/String");// 2. 提升为全局引用jclass globalClass = (jclass)env->NewGlobalRef(localClass);// 3. 不再需要局部引用env->DeleteLocalRef(localClass);// ...使用globalClass...// 4. 最后释放全局引用env->DeleteGlobalRef(globalClass);
}

4. 高级主题

缓存字段ID和方法ID

// 在全局变量中缓存
struct CachedIDs {jclass exampleClass;jmethodID callbackMethod;jfieldID valueField;
};bool cacheIds(JNIEnv* env) {static CachedIDs cached;cached.exampleClass = (jclass)env->NewGlobalRef(env->FindClass("com/example/Example"));cached.callbackMethod = env->GetMethodID(cached.exampleClass, "callback", "(I)V");cached.valueField = env->GetFieldID(cached.exampleClass, "value", "I");return cached.exampleClass && cached.callbackMethod && cached.valueField;
}JNIEXPORT void JNICALL Java_Example_useCachedIds(JNIEnv* env, jobject obj) {static bool cached = cacheIds(env);if (!cached) return;// 使用缓存的IDsjint value = env->GetIntField(obj, cached.valueField);env->CallVoidMethod(obj, cached.callbackMethod, value + 1);
}

多线程注意事项

// 获取JVM指针以便在其他线程使用
JavaVM* g_jvm = nullptr;JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {g_jvm = vm;return JNI_VERSION_1_6;
}void backgroundThreadFunction() {JNIEnv* env;int status = g_jvm->AttachCurrentThread(&env, nullptr);if (status < 0) {// 处理错误return;}// 在这里可以安全使用JNI// ...g_jvm->DetachCurrentThread();
}

math_operations.h

#ifndef LEARN1_MATH_OPERATIONS_H
#define LEARN1_MATH_OPERATIONS_Hclass math_operations {
public:// 声明为静态成员函数(可通过类名直接调用)static int factorial(int n);static int fibonacci(int n);static bool isPrime(int num);
};#endif //LEARN1_MATH_OPERATIONS_H

1.头文件保护宏

#ifndef LEARN1_MATH_OPERATIONS_H
#define LEARN1_MATH_OPERATIONS_H
// ...
#endif

这是防止头文件被多次包含的标准做法,避免重复定义错误。

2.类定义

class math_operations {
public:// ...
};

定义了一个名为math_operations的类,public:表示后续成员都是公开的。

3.静态成员函数

static int factorial(int n);
static int fibonacci(int n);
static bool isPrime(int num);

这些是静态成员函数的声明,特点是:

  1. static关键字:表示这些函数是静态成员函数

    • 属于类而不是类的实例

    • 可以直接通过类名调用,不需要创建对象实例

    • 不能访问类的非静态成员

  2. 函数声明

    • 只提供了函数原型(返回类型、函数名、参数列表)

    • 没有函数体实现(通常在对应的.cpp文件中实现)

为什么使用静态成员函数

  1. 工具类:当函数逻辑不依赖于对象状态时

  2. 命名空间替代:在C++中可以用来组织相关函数(替代命名空间)

  3. 无需实例化:可以直接调用,使用更方便


math_operations.cpp

#include "math_operations.h"int math_operations::factorial(int n) {if (n <= 1) return 1;return n * factorial(n - 1);
}int math_operations::fibonacci(int n) {if (n <= 1) return n;return fibonacci(n-1) + fibonacci(n-2);
}bool math_operations::isPrime(int num) {if (num <= 1) return false;for (int i = 2; i * i <= num; i++) {if (num % i == 0) return false;}return true;
}
#include "math_operations.h"
  • 作用:包含对应的头文件,确保函数声明与定义一致

  • 语法:使用引号""表示从当前目录或项目目录查找头文件

data_converter.h

#ifndef LEARN1_DATA_CONVERTER_H
#define LEARN1_DATA_CONVERTER_H#include <vector>
#include <string>
#include <jni.h>  // 必须包含JNI头文件class data_converter {
public:static std::vector<int> convertJavaArrayToVector(JNIEnv* env, jintArray array);static std::string convertJavaStringToCpp(JNIEnv* env, jstring jStr);
};#endif //LEARN1_DATA_CONVERTER_H
  • <vector>:提供C++标准向量容器支持

  • <string>:提供C++字符串支持

  • <jni.h>:JNI开发必需的头文件,定义了Java和本地代码交互的所有类型和函数

  • JNIEnv* env:JNI环境指针,提供所有JNI函数访问

data_converter.cpp

#include "data_converter.h"
#include <vector>std::vector<int> data_converter::convertJavaArrayToVector(JNIEnv* env, jintArray array) {std::vector<int> result;jsize length = env->GetArrayLength(array);jint* elements = env->GetIntArrayElements(array, nullptr);result.assign(elements, elements + length);env->ReleaseIntArrayElements(array, elements, 0);return result;
}std::string data_converter::convertJavaStringToCpp(JNIEnv* env, jstring jStr) {const char* cStr = env->GetStringUTFChars(jStr, nullptr);std::string result(cStr);env->ReleaseStringUTFChars(jStr, cStr);return result;
}

1. convertJavaArrayToVector 方法

功能

将 Java 的 int[] 数组转换为 C++ 的 std::vector<int>

实现步骤:

  1. 创建空 vectorstd::vector<int> result

  2. 获取数组长度

    • env->GetArrayLength(array) 获取 Java 数组的长度

    • jsize 是 JNI 中表示大小的类型

  3. 获取数组元素指针

    • env->GetIntArrayElements(array, nullptr) 获取指向 Java 数组内容的指针

    • 第二个参数 nullptr 表示不关心是否复制了数组

  4. 填充 vector

    • result.assign(elements, elements + length) 将 Java 数组内容复制到 vector

  5. 释放资源

    • env->ReleaseIntArrayElements(array, elements, 0) 释放获取的数组指针

    • 参数 0 表示将内容复制回原数组并释放临时内存

  6. 返回结果:包含 Java 数组数据的 vector

关键点:

  • 必须成对调用 GetIntArrayElements 和 ReleaseIntArrayElements

  • assign 方法高效地将 C 风格数组复制到 vector

  • 最后一个参数 0 可以是:

    • 0:复制回原数组并释放临时内存

    • JNI_ABORT:不复制回原数组但释放内存

    • JNI_COMMIT:复制回原数组但不释放内存

2. convertJavaStringToCpp 方法

功能

将 Java 的 String 对象转换为 C++ 的 std::string

实现步骤:

  1. 获取 UTF-8 字符指针

    • env->GetStringUTFChars(jStr, nullptr) 获取指向 Java 字符串 UTF-8 编码的指针

    • 第二个参数 nullptr 表示不关心是否复制了字符串

  2. 创建 std::string

    • std::string result(cStr) 用获取的字符指针构造 C++ 字符串

  3. 释放资源

    • env->ReleaseStringUTFChars(jStr, cStr) 释放获取的字符指针

  4. 返回结果:包含 Java 字符串内容的 std::string

关键点:

  • 必须成对调用 GetStringUTFChars 和 ReleaseStringUTFChars

  • 使用 UTF-8 编码转换,这是 Java 和 C++ 之间最常用的编码方式

  • 如果 Java 字符串包含非 ASCII 字符,这种方式能正确处理

3. 可能的改进

  1. 添加空指针检查

    if (!jStr) return std::string();
  2. 错误处理增强

    const char* cStr = env->GetStringUTFChars(jStr, nullptr);
    if (!cStr) {// 处理错误
    }

string_processor.h

#ifndef LEARN1_STRING_PROCESSOR_H
#define LEARN1_STRING_PROCESSOR_H#include <string>class string_processor {
public:// 1. 字符串反转static std::string reverseString(const std::string& input);// 2. 统计元音字母数量static int countVowels(const std::string& input);// 3. 凯撒加密(字母位移)static std::string encryptString(const std::string& input, int shift);
};#endif //LEARN1_STRING_PROCESSOR_H
  • const std::string& input:要反转的字符串(常量引用,避免拷贝)

const std::string& 讲解

1. 基本组成解析

可以分解为三个部分:

  1. std::string - C++标准库中的字符串类型

  2. & - 表示这是一个引用

  3. const - 表示这是一个常量(不可修改)

2. 为什么要使用这种形式

2.1 避免不必要的拷贝
  • 不使用引用void func(std::string str)
    传递参数时会创建字符串的完整副本(拷贝构造)

  • 使用引用void func(const std::string& str)
    只传递引用(内存地址),不创建副本

2.2 保证原字符串不被修改
  • const限定确保函数内不能修改原字符串

  • 既享受引用的高效,又保证数据安全

2.3 支持临时对象
  • 可以接受临时字符串对象(右值)

  • 例如:func("temporary string")

3. 与替代方案的对比

参数形式拷贝开销可修改原值接受临时对象备注
std::string副本可修改最安全但效率最低
std::string&可以修改需要非常量左值
const std::string&不可修改最佳平衡方案
std::string_view (C++17)不可修改现代替代方案

4. 典型使用场景

4.1 作为输入参数
void printString(const std::string& str) {std::cout << str;  // 只能读取,不能修改
}
4.2 与STL算法配合
bool contains(const std::string& str, const std::string& substr) {return str.find(substr) != std::string::npos;
}
4.3 类成员函数
class TextProcessor {
public:void process(const std::string& input) {// 处理输入但不修改它}
};

5. 注意事项

  1. 生命周期管理
    • 引用必须确保指向的对象在函数使用期间有效

    • 不要返回局部变量的const引用

  2. C++17后的替代方案
    • 考虑使用std::string_view作为只读参数

    • 更轻量级,支持更多类型的字符串数据

  3. 与移动语义的关系
    • 对于需要"夺取"所有权的情况,应使用std::string&&(右值引用)

    • const&会阻止移动语义的应用

  4. NULL问题
    • 不能直接传递NULL/nullptr

    • 如果需要可空引用,应使用指针或std::optional

string_processor.cpp

#include "string_processor.h"
#include <algorithm> // 提供std::reverse
#include <string>  // 提供std::stringstd::string string_processor::reverseString(const std::string& input) {std::string reversed = input;std::reverse(reversed.begin(), reversed.end());return reversed;
}int string_processor::countVowels(const std::string& input) {int count = 0;const std::string vowels = "aeiouAEIOU";for (char c : input) {if (vowels.find(c) != std::string::npos) {count++;}}return count;
}std::string string_processor::encryptString(const std::string& input, int shift) {std::string result;for (char c : input) {if (isalpha(c)) {char base = isupper(c) ? 'A' : 'a';c = ((c - base + shift) % 26) + base;}result += c;}return result;
}

结果

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

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

相关文章

B树和B+树

B树B树&#xff0c;⼜称多路平衡查找树&#xff0c;B树中所被允许的孩⼦个数的最⼤值称为B树的阶&#xff0c;通常⽤m表示。⼀棵m阶B树或为空树&#xff0c;或为满⾜如下特性的m叉树&#xff1a; 1&#xff09;树中每个结点⾄多有m棵⼦树&#xff0c;即⾄多含有m-1个关键字。 2…

【版本控制】Perforce Helix Core (P4V) 完全入门指南(含虚幻引擎实战)

目录引言第一章&#xff1a;认识 Perforce Helix Core1.1 什么是 Perforce&#xff1f;1.2 P4V 是什么&#xff1f;1.3 核心概念速览1.4 为什么选择 Perforce&#xff1f;1.5 与 Git 的核心区别本章总结第二章&#xff1a;安装与配置2.1 安装原则&#xff1a;先服务端后客户端2…

LlamaFactory/unsloth Demo

内部叫Tuning-Factory 参数文档https://llamafactory.readthedocs.io/zh-cn/latest/index.html 高级技巧&#xff0c;如加速&#xff1a;https://llamafactory.readthedocs.io/zh-cn/latest/advanced/acceleration.html 0.环境 conda env list conda remove --name llm --all c…

水务工程中自动化应用:EtherNet/IP转PROFIBUS DP连接超声波流量计

在水务工程领域&#xff0c;自动化技术的应用愈发广泛。随着工业4.0概念的普及&#xff0c;不同通信协议的设备之间实现高效互联互通变得尤为关键。EtherNet/IP和PROFIBUS DP作为两种常见的工业通信协议&#xff0c;各有优势&#xff0c;在实际应用中&#xff0c;常需要将它们进…

网络协议和基础通信原理

网络协议和基础通信原理是理解互联网和各种网络应用的关键。让我用通俗易懂的方式&#xff0c;带你逐一深入讲解这些内容。 一、基础概念总览 TCP/IP协议族&#xff1a;互联网通信的基础&#xff0c;由一组协议组成&#xff0c;包括TCP、IP、UDP等。HTTP协议&#xff1a;基于T…

T16IZ遥控器教程__遥控器与无人机对频

文章目录前言一、准备设备二、对频步骤总结前言 在使用自组PX4无人机时&#xff0c;有的小伙伴可能会遇到遥控器无法与无人机对频连接的问题&#xff0c;别担心&#xff0c;这篇文章会解决它。 一、准备设备 如下图&#xff0c;无人机信号接收器&#xff0c;与无人机。 遥控器…

pyspark中map算子和flatmap算子

在 PySpark 中&#xff0c;map 和 flatMap 是两个常用的转换算子&#xff0c;它们都用于对 RDD&#xff08;弹性分布式数据集&#xff09;或 DataFrame 中的元素进行处理&#xff0c;但处理方式和应用场景有所不同。下面详细讲解它们的用法和适用场景。1. map 算子功能对 RDD 或…

jenkins部署前端vue项目使用Docker+Jenkinsfile方式

文章目录前言一、前提准备二、准备构建文件三、Jenkins中构建项目总结前言 前面通过jenkinsdocker的方式部署了若依前端vue项目&#xff0c;接下来接着学习使用Jenkinsfile的方式部署前端vue项目。 一、前提准备 已经安装好centos服务器&#xff0c;并且安装了jenkins和docke…

Cadence操作说明

一.allegro修改丝印字体大小的方法 1.选择Edit–>Change&#xff0c;右侧弹出Options选项&#xff0c;选择Class : New subclass Ref Des : Silkscreen_Top&#xff0c;设置Text block&#xff0c;后面的数字代表字号的大小。菜单菜单栏选择Setup–>Design Parameters&a…

使用Stitch来生成CrypyTrack的app程序

结果&#xff1a; &#x1f9ed; 第一步&#xff1a;访问 Stitch 平台 打开网址&#xff1a;stitch.withgoogle.com使用你的 Google 账号登录&#xff0c;无需安装任何软件 &#x1f9f1; 第二步&#xff1a;选择设计模式 Stitch 提供两种模式&#xff1a; 标准模式&#xf…

告别繁琐:API全生命周期管理的新范式——apiSQL

API&#xff08;应用程序接口&#xff09;是连接数据与服务的生命线&#xff0c;是数字世界的基石。然而&#xff0c;一个高质量API的诞生并非易事&#xff0c;它涉及一个漫长而复杂的全生命周期——从规划设计到最终退役&#xff0c;每个环节都需要专门的工具和技能&#xff0…

R 语言科研绘图第 64 期 --- 哑铃图

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…

基于MaxCompute MaxFrame 汽车自动驾驶数据预处理最佳实践

一、背景及挑战在汽车自动驾驶场景中&#xff0c;车端&#xff08;量产车、研采车&#xff09;持续产生并采集海量数据&#xff0c;包括图片、音视频、雷达、GPS等内容&#xff0c;这些数据通常以 ROSbag文件形式进行存储。行业需求&#xff1a;自动驾驶依赖海量多模态数据&…

NLP:RNN文本生成案例分享

本文目录&#xff1a;一、导入工具包二、数据集三、 构建词表四、 构建数据集对象五、 构建网络模型六、 构建训练函数七、构建预测函数前言&#xff1a;上篇文章讲解了RNN&#xff0c;这篇文章分享文本生成任务案例&#xff1a;文本生成是一种常见的自然语言处理任务&#xff…

AI时代的接口自动化优化实践:如何突破Postman的局限性

编者语&#xff1a;本文作者为某非银金融测试团队负责人。其团队自 2024 年起局部试用 Apipost&#xff0c;目前已在全团队正式投入使用 。在推进微服务 API 自动化测试的过程中&#xff0c;研发和测试人员常常需要在接口请求中动态构造带有特定业务规则的数据。我们团队就遇到…

动态规划题解_将一个数字表示成幂的和的方案数【LeetCode】

2787. 将一个数字表示成幂的和的方案数 给你两个正整数 n 和 x 。 请你返回将 n 表示成一些 互不相同 正整数的 x 次幂之和的方案数。换句话说&#xff0c;你需要返回互不相同整数 [n1, n2, ..., nk] 的集合数目&#xff0c;满足 n n1x n2x ... nkx 。 由于答案可能非常…

C#常用的LinQ方法

LINQ&#xff08;Language Integrated Query&#xff09;是 .NET 中用于处理集合的强大工具&#xff0c;它提供了多种方法来简化数据查询和操作。以下是一些常用的 LINQ 方法及其功能&#xff1a;Where: 根据指定的条件筛选集合中的元素。var filteredResults matchResults.Wh…

目标检测之数据增强

数据翻转&#xff0c;需要把bbox相应的坐标值也进行交换代码&#xff1a;import random from torchvision.transforms import functional as Fclass Compose(object):"""组合多个transform函数"""def __init__(self, transforms):self.transform…

DiffDet4SAR——首次将扩散模型用于SAR图像目标检测,来自2024 GRSL(ESI高被引1%论文)

一. 论文摘要 合成孔径雷达&#xff08;SAR&#xff09;图像中的飞机目标检测是一项具有挑战性的任务&#xff0c;由于离散的散射点和严重的背景杂波干扰。目前&#xff0c;基于卷积或基于变换的方法不能充分解决这些问题。 本文首次探讨了SAR图像飞机目标检测的扩散模型&#…

html案例:编写一个用于发布CSDN文章时,生成有关缩略图

CSDN博客文章缩略图生成器起因&#xff1a;之前注意到CSDN可以随机选取文章缩略图&#xff0c;但后来这个功能似乎取消了。于是我想调整一下缩略图的配色方案。html制作界面 界面分上下两块区域&#xff0c;上面是参数配置&#xff0c;下面是效果预览图。参数配置&#xff1a; …