当前位置: 首页 > article >正文

用Camera2 API实现一个简易抖音拍摄功能:录制、预览与视频保存

用Camera2 API打造短视频拍摄功能从零实现抖音式交互体验在移动互联网时代短视频应用已经成为人们日常生活中不可或缺的娱乐方式。作为Android开发者掌握如何构建一个高效、流畅的短视频拍摄功能至关重要。本文将带你深入探索如何利用Camera2 API和MediaRecorder从零开始实现一个类似抖音的短视频拍摄模块涵盖实时预览、录制控制、视频保存等核心功能。1. Camera2 API基础与项目准备Camera2 API是Android 5.0API 21引入的全新相机框架相比传统的Camera API它提供了更精细的控制和更高的性能。在开始实现短视频拍摄功能前我们需要做好以下准备工作开发环境要求Android Studio最新稳定版目标API级别设置为21或更高测试设备运行Android 5.0及以上系统关键依赖与权限配置在AndroidManifest.xml中添加必要的权限声明uses-permission android:nameandroid.permission.CAMERA / uses-permission android:nameandroid.permission.RECORD_AUDIO / uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE /项目结构规划app/ ├── java/ │ ├── com.example.videorecorder/ │ │ ├── CameraController.kt // 相机控制核心逻辑 │ │ ├── VideoRecorder.kt // 视频录制处理 │ │ ├── PreviewView.kt // 自定义预览视图 │ │ └── MainActivity.kt // 主界面 └── res/ ├── layout/ │ └── activity_main.xml // 主界面布局Camera2 API的核心组件包括CameraManager管理系统中的所有摄像头设备CameraDevice代表单个摄像头设备CameraCharacteristics描述摄像头设备的特性CaptureRequest定义捕获图像的参数CameraCaptureSession管理摄像头捕获会话2. 实现相机预览功能相机预览是短视频拍摄的基础良好的预览体验直接影响用户的使用感受。下面我们一步步实现高质量的预览功能。2.1 初始化相机设备首先创建一个CameraController类来管理相机相关操作class CameraController(context: Context, textureView: TextureView) { private val cameraManager context.getSystemService(Context.CAMERA_SERVICE) as CameraManager private val cameraId: String private var cameraDevice: CameraDevice? null private var captureSession: CameraCaptureSession? null private lateinit var previewRequestBuilder: CaptureRequest.Builder init { // 获取后置摄像头ID cameraId cameraManager.cameraIdList.first { id - cameraManager.getCameraCharacteristics(id) .get(CameraCharacteristics.LENS_FACING) CameraCharacteristics.LENS_FACING_BACK } } private val stateCallback object : CameraDevice.StateCallback() { override fun onOpened(camera: CameraDevice) { cameraDevice camera startPreview() } override fun onDisconnected(camera: CameraDevice) { camera.close() cameraDevice null } override fun onError(camera: CameraDevice, error: Int) { camera.close() cameraDevice null } } fun openCamera() { if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) PackageManager.PERMISSION_GRANTED) { cameraManager.openCamera(cameraId, backgroundHandler, stateCallback) } } // 其他方法将在后续实现 }2.2 配置预览会话创建预览会话需要以下几个步骤创建SurfaceTexture并设置到TextureView配置预览尺寸和输出Surface创建CaptureRequest.Builder建立CameraCaptureSessionprivate fun startPreview() { val texture textureView.surfaceTexture ?: return // 设置默认缓冲区大小 val characteristics cameraManager.getCameraCharacteristics(cameraId) val map characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) val previewSize map?.getOutputSizes(SurfaceTexture::class.java)?.maxByOrNull { it.width * it.height } texture.setDefaultBufferSize(previewSize?.width ?: 1080, previewSize?.height ?: 1920) val surface Surface(texture) previewRequestBuilder cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) previewRequestBuilder.addTarget(surface) cameraDevice?.createCaptureSession( listOf(surface), object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { captureSession session previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) session.setRepeatingRequest(previewRequestBuilder.build(), null, backgroundHandler) } override fun onConfigureFailed(session: CameraCaptureSession) { Log.e(TAG, Failed to configure capture session) } }, backgroundHandler ) }2.3 处理生命周期和权限在Activity中正确处理生命周期和权限请求class MainActivity : AppCompatActivity() { private lateinit var cameraController: CameraController private lateinit var textureView: TextureView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) textureView findViewById(R.id.texture_view) cameraController CameraController(this, textureView) textureView.surfaceTextureListener object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { if (checkPermissions()) { cameraController.openCamera() } else { requestPermissions() } } // 其他回调方法... } } private fun checkPermissions(): Boolean { return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) PackageManager.PERMISSION_GRANTED ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) PackageManager.PERMISSION_GRANTED } private fun requestPermissions() { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO), REQUEST_CODE_PERMISSIONS ) } override fun onRequestPermissionsResult( requestCode: Int, permissions: Arrayout String, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode REQUEST_CODE_PERMISSIONS grantResults.all { it PackageManager.PERMISSION_GRANTED }) { cameraController.openCamera() } } companion object { private const val REQUEST_CODE_PERMISSIONS 1001 } }3. 实现视频录制功能视频录制是短视频应用的核心功能我们需要整合Camera2 API和MediaRecorder来实现高质量的录制体验。3.1 配置MediaRecorder创建一个VideoRecorder类来封装视频录制逻辑class VideoRecorder(private val context: Context) { private var mediaRecorder: MediaRecorder? null private var videoFile: File? null fun prepare(outputFile: File, width: Int, height: Int, surface: Surface): Surface { mediaRecorder MediaRecorder().apply { setAudioSource(MediaRecorder.AudioSource.MIC) setVideoSource(MediaRecorder.VideoSource.SURFACE) setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) setAudioEncoder(MediaRecorder.AudioEncoder.AAC) setVideoEncoder(MediaRecorder.VideoEncoder.H264) setVideoEncodingBitRate(5 * 1024 * 1024) // 5Mbps setVideoFrameRate(30) setVideoSize(width, height) setOrientationHint(90) // 竖屏录制 setOutputFile(outputFile.absolutePath) setPreviewDisplay(surface) prepare() } videoFile outputFile return mediaRecorder!!.surface } fun start() { mediaRecorder?.start() } fun stop() { mediaRecorder?.apply { stop() reset() release() } mediaRecorder null } fun getOutputFile(): File? videoFile }3.2 集成录制功能到CameraController在CameraController中添加录制相关逻辑class CameraController(context: Context, textureView: TextureView) { private val videoRecorder VideoRecorder(context) private var isRecording false fun startRecording() { if (isRecording) return val outputFile File(context.getExternalFilesDir(null), video_${System.currentTimeMillis()}.mp4) val recorderSurface videoRecorder.prepare( outputFile, previewSize.width, previewSize.height, Surface(textureView.surfaceTexture) ) captureSession?.stopRepeating() captureSession?.abortCaptures() val previewRequestBuilder cameraDevice!!.createCaptureRequest( CameraDevice.TEMPLATE_RECORD ).apply { addTarget(Surface(textureView.surfaceTexture)) addTarget(recorderSurface) set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) } cameraDevice?.createCaptureSession( listOf(Surface(textureView.surfaceTexture), recorderSurface), object : CameraCaptureSession.StateCallback() { override fun onConfigured(session: CameraCaptureSession) { captureSession session session.setRepeatingRequest(previewRequestBuilder.build(), null, null) videoRecorder.start() isRecording true } override fun onConfigureFailed(session: CameraCaptureSession) { Log.e(TAG, Failed to configure recording session) } }, null ) } fun stopRecording() { if (!isRecording) return videoRecorder.stop() isRecording false // 重启预览 startPreview() // 保存视频到媒体库 saveVideoToGallery(videoRecorder.getOutputFile()) } private fun saveVideoToGallery(file: File?) { file ?: return val values ContentValues().apply { put(MediaStore.Video.Media.TITLE, file.name) put(MediaStore.Video.Media.DISPLAY_NAME, file.name) put(MediaStore.Video.Media.MIME_TYPE, video/mp4) put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000) put(MediaStore.Video.Media.DATA, file.absolutePath) } context.contentResolver.insert( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values ) } }3.3 添加录制控制UI在布局文件中添加录制控制按钮androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:apphttp://schemas.android.com/apk/res-auto android:layout_widthmatch_parent android:layout_heightmatch_parent TextureView android:idid/texture_view android:layout_widthmatch_parent android:layout_heightmatch_parent app:layout_constraintBottom_toBottomOfparent app:layout_constraintEnd_toEndOfparent app:layout_constraintStart_toStartOfparent app:layout_constraintTop_toTopOfparent / com.google.android.material.floatingactionbutton.FloatingActionButton android:idid/record_button android:layout_widthwrap_content android:layout_heightwrap_content android:layout_marginBottom32dp android:srcdrawable/ic_record app:layout_constraintBottom_toBottomOfparent app:layout_constraintEnd_toEndOfparent app:layout_constraintStart_toStartOfparent / /androidx.constraintlayout.widget.ConstraintLayout在Activity中处理录制按钮点击事件record_button.setOnClickListener { if (cameraController.isRecording()) { cameraController.stopRecording() record_button.setImageResource(R.drawable.ic_record) } else { cameraController.startRecording() record_button.setImageResource(R.drawable.ic_stop) } }4. 优化用户体验与性能一个优秀的短视频拍摄功能不仅需要实现基本功能还需要考虑用户体验和性能优化。4.1 添加录制计时器在录制过程中显示已录制时间可以提升用户体验private var recordingStartTime 0L private val timerHandler Handler(Looper.getMainLooper()) private lateinit var timerTextView: TextView private val timerRunnable object : Runnable { override fun run() { val elapsedMillis System.currentTimeMillis() - recordingStartTime timerTextView.text SimpleDateFormat(mm:ss, Locale.getDefault()) .format(Date(elapsedMillis)) timerHandler.postDelayed(this, 1000) } } fun startRecording() { recordingStartTime System.currentTimeMillis() timerHandler.post(timerRunnable) // 其他录制逻辑... } fun stopRecording() { timerHandler.removeCallbacks(timerRunnable) timerTextView.text 00:00 // 其他停止录制逻辑... }4.2 实现闪光灯控制添加闪光灯控制功能可以增强拍摄灵活性fun toggleFlash(): Boolean { val characteristics cameraManager.getCameraCharacteristics(cameraId) val hasFlash characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) ?: false if (!hasFlash) return false isFlashOn !isFlashOn previewRequestBuilder.set( CaptureRequest.FLASH_MODE, if (isFlashOn) CaptureRequest.FLASH_MODE_TORCH else CaptureRequest.FLASH_MODE_OFF ) captureSession?.setRepeatingRequest(previewRequestBuilder.build(), null, null) return isFlashOn }4.3 优化录制性能为了确保录制过程流畅需要注意以下几点选择合适的视频参数// 在VideoRecorder.prepare()中设置 setVideoEncodingBitRate(5 * 1024 * 1024) // 5Mbps适合1080p视频 setVideoFrameRate(30) // 30fps是流畅视频的标准帧率处理设备旋转override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) // 重新配置相机方向 cameraController.updateOrientation() }内存管理override fun onPause() { super.onPause() if (isRecording) { stopRecording() } cameraController.closeCamera() }4.4 添加录制进度提示在UI中添加录制进度条可以提升用户体验ProgressBar android:idid/recording_progress stylestyle/Widget.AppCompat.ProgressBar.Horizontal android:layout_widthmatch_parent android:layout_height4dp android:layout_marginHorizontal16dp android:max15000 !-- 15秒最大录制时长 -- android:progressDrawabledrawable/progress_bar_recording app:layout_constraintTop_toTopOfparent /在录制过程中更新进度private val progressRunnable object : Runnable { override fun run() { val progress (System.currentTimeMillis() - recordingStartTime).toInt() recordingProgress.progress progress if (progress recordingProgress.max) { progressHandler.postDelayed(this, 50) } else { // 自动停止录制 stopRecording() } } }

相关文章:

用Camera2 API实现一个简易抖音拍摄功能:录制、预览与视频保存

用Camera2 API打造短视频拍摄功能:从零实现抖音式交互体验 在移动互联网时代,短视频应用已经成为人们日常生活中不可或缺的娱乐方式。作为Android开发者,掌握如何构建一个高效、流畅的短视频拍摄功能至关重要。本文将带你深入探索如何利用Cam…...

别再死记硬背YOLO的9个anchors了!用Python可视化带你搞懂它在特征图上的调整过程

用Python动态可视化拆解YOLO anchors的调整逻辑 第一次看到YOLO的9个anchors参数时,我盯着那堆数字发呆了半小时——这些宽高组合到底如何影响最终检测框?为什么调整几像素就能让模型性能波动5%?直到我用Matplotlib逐帧绘制了特征图上的坐标变…...

5个专业技巧:掌握Inter字体家族打造完美数字界面体验

5个专业技巧:掌握Inter字体家族打造完美数字界面体验 【免费下载链接】inter The Inter font family 项目地址: https://gitcode.com/gh_mirrors/in/inter Inter字体家族是一款专为现代数字屏幕设计的无衬线字体系统,以其卓越的可读性、丰富的Ope…...

Ai2Psd终极指南:如何彻底解决Illustrator到Photoshop的矢量转换难题

Ai2Psd终极指南:如何彻底解决Illustrator到Photoshop的矢量转换难题 【免费下载链接】ai-to-psd A script for prepare export of vector objects from Adobe Illustrator to Photoshop 项目地址: https://gitcode.com/gh_mirrors/ai/ai-to-psd 你是否曾为Il…...

3分钟掌握ZeroOmega:跨浏览器智能代理管理的终极指南

3分钟掌握ZeroOmega:跨浏览器智能代理管理的终极指南 【免费下载链接】ZeroOmega Manage and switch between multiple proxies quickly & easily. 项目地址: https://gitcode.com/gh_mirrors/ze/ZeroOmega ZeroOmega是一款基于manifest v3标准的开源浏览…...

终极免费打字学习工具:用Qwerty Learner打造你的键盘肌肉记忆系统

终极免费打字学习工具:用Qwerty Learner打造你的键盘肌肉记忆系统 【免费下载链接】qwerty-learner 为键盘工作者设计的单词记忆与英语肌肉记忆锻炼软件 / Words learning and English muscle memory training software designed for keyboard workers 项目地址: …...

鸣潮自动化工具ok-ww:5分钟搞定每日重复任务的终极解决方案

鸣潮自动化工具ok-ww:5分钟搞定每日重复任务的终极解决方案 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸 一键日常 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 你是否厌倦…...

保姆级教程:手把手为嵌入式Linux移植NAU8810音频Codec驱动(基于ALSA ASoC框架)

嵌入式Linux音频驱动实战:NAU8810 Codec移植全流程解析 当一块崭新的开发板放在你面前,而客户要求在下周之前完成音频功能的集成时,那种既兴奋又紧张的感觉,相信每个嵌入式工程师都深有体会。NAU8810作为一款高性能低功耗的音频编…...

保姆级教程:在Ubuntu 18.04上为Firefly RK3399 ProC交叉编译Python 3.7.10(含zlib、numpy、pyserial)

嵌入式开发实战:为Firefly RK3399 ProC构建定制Python 3.7环境 当你在Firefly RK3399 ProC开发板上尝试运行Python科学计算脚本时,是否遇到过性能瓶颈或依赖缺失的困扰?不同于x86平台的即装即用,ARM架构的嵌入式设备往往需要从源码…...

从‘炼丹’到‘工程’:复盘InceptionV3论文中那些被验证与‘打脸’的设计(附代码对比)

从‘炼丹’到‘工程’:InceptionV3设计思想的现代验证与技术启示 当我们在2023年回望2015年问世的InceptionV3架构,会发现它像一座横跨深度学习"炼丹时代"与"工程时代"的桥梁。这篇论文最珍贵的遗产不是某个具体模块,而是…...

Inspirit Capital将收购Kaplan Languages Group

专注于企业分拆业务投资的Inspirit Capital欣然宣布,计划从Kaplan手中收购全球领先的语言教育平台KLG Kaplan Languages Group (“KLG”)。本次出售的所有条件均已达成,预计交易将于5月1日完成。 KLG旗下拥有Kaplan International Languages、Alpadia L…...

别再混淆了!用Keil MDK调试Cortex-M3/M4时,MSP和PSP到底怎么切换的?

别再混淆了!用Keil MDK调试Cortex-M3/M4时,MSP和PSP到底怎么切换的? 调试嵌入式系统时,堆栈指针的切换问题常常让开发者头疼。特别是在RTOS环境下,MSP(主堆栈指针)和PSP(进程堆栈指针…...

文科生逆袭!零基础转行AI,我靠AI工具直接涨薪50%!

本文分享了作者从文科背景转行AI的成功经验。作者首先打破文科生不适合进入AI行业的误区,选定AI产品和提示词工程师作为切入点。接着,作者通过大量使用AI工具建立AI体感,并制作了一个轻量级的项目作品集,展示了如何利用AI工具梳理…...

告别书签混乱:3步打造你的Chrome浏览器高效书签管理系统

告别书签混乱:3步打造你的Chrome浏览器高效书签管理系统 【免费下载链接】neat-bookmarks A neat bookmarks tree popup extension for Chrome [DISCONTINUED] 项目地址: https://gitcode.com/gh_mirrors/ne/neat-bookmarks 你是否经常在浏览器中迷失方向&am…...

废旧元件DIY太阳能光控LED灯串设计

1. 项目概述这个用废旧零件拼凑起来的模拟电路项目,完美诠释了"变废为宝"的DIY精神。它由太阳能板、锂电池和几颗白光LED组成,打造出了一串既环保又充满魅力的装饰灯串。在这个被各种专用芯片和微控制器统治的时代,这个项目提醒我们…...

别再被老视频的“毛边”困扰了!手把手教你用TW9912芯片搞定隔行转逐行(附原理详解)

告别隔行扫描困扰:TW9912芯片实战指南与画质优化 想象一下,当你翻出珍藏多年的家庭录像带,满怀期待地将其数字化后,却发现播放时画面布满锯齿和闪烁——这种失落感恐怕只有经历过的人才能体会。隔行扫描技术曾是电视黄金时代的基石…...

Cadence Virtuoso 新手避坑指南:从原理图到版图,手把手搞定 AMI 0.6u 工艺下的 MOS 管仿真

Cadence Virtuoso 新手避坑指南:从原理图到版图,手把手搞定 AMI 0.6u 工艺下的 MOS 管仿真 第一次打开 Cadence Virtuoso 时,复杂的界面和密密麻麻的菜单栏让不少集成电路专业的学生望而生畏。尤其是当教授要求用 AMI 0.6u 工艺完成 MOS 管仿…...

从调光到伽马校正:手把手教你用ILI9341命令优化TFT屏幕显示效果(实战避坑)

从调光到伽马校正:手把手教你用ILI9341命令优化TFT屏幕显示效果(实战避坑) 在嵌入式开发中,TFT屏幕的显示效果往往直接影响用户体验。许多开发者在使用ILI9341驱动芯片时,虽然能够完成基础显示功能,却常常忽…...

拆解一块TFT-LCD屏幕:聊聊驱动板上那颗Power IC是怎么‘发电’的

拆解一块TFT-LCD屏幕:驱动板上那颗Power IC的电力魔法 站在电子爱好者的视角,拆解一块TFT-LCD屏幕总能带来意想不到的惊喜。当我们小心翼翼地剥离背光模组和偏光片,露出那块布满精密电路的PCB时,最引人注目的往往是那颗被众多电容…...

用MPX4115气压传感器和51单片机做个简易气压计(附完整代码与电路图)

从零构建基于MPX4115的智能气压监测系统:硬件连接、代码解析与实战调试 气压监测在气象观测、无人机高度控制、工业设备监控等领域有着广泛应用。今天我们将使用经典的51单片机(以STC89C52为例)和MPX4115气压传感器,打造一个具备实…...

智能补光灯DIY:用STM32和BH1750传感器自动调节LED亮度(含PID算法)

智能补光灯DIY:用STM32和BH1750传感器实现闭环调光系统 深夜伏案工作时,你是否经常因为环境光线不足导致眼睛疲劳?传统台灯需要手动调节亮度,而市面上的智能灯具价格昂贵且功能单一。今天我们将用STM32单片机和BH1750光照传感器&a…...

AI智能体的正确打开方式

先说结论2026年,AI不再只是"你问我答"的聊天框,而是能自己干活、自己决策的智能体。不会用智能体的人,就像有驾照却只会骑自行车。这个东西是什么想象一下:你有一个实习生,你不用手把手教他每一步&#xff0…...

别再乱打拍了!从亚稳态到异步FIFO,手把手教你搞定FPGA跨时钟域信号处理

从亚稳态到异步FIFO:FPGA跨时钟域信号处理实战指南 在FPGA和数字IC设计中,跨时钟域信号处理是一个永恒的话题。每当项目进度紧张、调试压力增大时,工程师们最不愿看到的就是时序报告里那些令人头疼的违例警告。我曾在一个高速数据采集项目中…...

你的FOC电机为啥抖?可能是电角度算错了!聊聊编码器安装与极对数那些坑

你的FOC电机为啥抖?可能是电角度算错了!聊聊编码器安装与极对数那些坑 调试FOC电机时,最让人头疼的莫过于电机运行时抖动、噪音大甚至无法启动。很多工程师在搭建完FOC系统后,发现电机运行效果远不如预期,这时候问题往…...

告别手动输入!用ABAP OOALV事件给报表字段加个“智能下拉框”

告别手动输入!用ABAP OOALV事件给报表字段加个"智能下拉框" 在SAP系统的日常操作中,物料编码、供应商编号等字段的输入是高频且容易出错的操作环节。传统的手工输入不仅效率低下,还容易因记忆偏差导致数据错误。本文将深入探讨如何…...

保姆级教程:用示波器和CAN分析仪抓取并解析错误帧(附波形图)

实战指南:用示波器与CAN分析仪精准捕获错误帧的完整流程 在汽车电子和工业控制领域,CAN总线就像神经系统的传导通路,而错误帧则是这条通路上最需要警惕的异常信号。想象一下,当你驾驶的汽车突然出现仪表盘闪烁或动力系统报警&…...

统信UOS桌面效率翻倍秘籍:用好工作区和窗口分屏,告别杂乱无章的桌面

统信UOS桌面效率革命:工作区与分屏的进阶玩法 刚接触统信UOS的Windows/macOS用户,面对全新的桌面环境往往手足无措——浏览器、文档、聊天软件窗口杂乱堆叠,频繁切换导致效率低下。其实,UOS内置的工作区(虚拟桌面&…...

统信UOS蓝牙管理实战:从服务控制到硬件开关

1. 统信UOS蓝牙管理入门指南 第一次接触统信UOS的蓝牙管理时,我完全被各种专业术语搞晕了。后来才发现,其实掌握几个核心命令就能解决90%的日常问题。作为国产操作系统的代表,统信UOS在蓝牙管理方面提供了完整的命令行工具链,特别…...

用户习惯报告:UG/NX用户使用习惯与模块偏好分析

又抢不到软件许可了?别急,别急,我来跟你唠唠过往在项目上线前,我跟团队蹲在机房门口,眼巴巴看着别人用着许可,自己这边却偏偏连个空位都抢不到。你说心塞不?这一年的加班,一半是赶进…...

Autolabel:如何用3步流程解决数据标注的世纪难题?

Autolabel:如何用3步流程解决数据标注的世纪难题? 【免费下载链接】autolabel Label, clean and enrich text datasets with LLMs. 项目地址: https://gitcode.com/gh_mirrors/au/autolabel 想象一下,你的机器学习团队正在构建一个银行…...