Vue3水印(Watermark)
APIs
| 参数 | 说明 | 类型 | 默认值 | 必传 |
|---|---|---|---|---|
| width | 水印的宽度,默认值为 content 自身的宽度 | number | undefined | false |
| height | 水印的高度,默认值为 content 自身的高度 | number | undefined | false |
| rotate | 水印绘制时,旋转的角度,单位 ° | number | -22 | false |
| zIndex | 追加的水印元素的 z-index | number | 9 | false |
| image | 图片源,建议使用 2 倍或 3 倍图,优先级高于文字 | string | undefined | false |
| content | 水印文字内容 | string | string[] | ‘’ | false |
| color | 字体颜色 | string | ‘rgba(0,0,0,.15)’ | false |
| fontSize | 字体大小,单位px | number | 16 | false |
| fontWeight | 字体粗细 | ‘normal’ | ‘light’ | ‘weight’ | number | ‘normal’ | false |
| fontFamily | 字体类型 | string | ‘sans-serif’ | false |
| fontStyle | 字体样式 | ‘none’ | ‘normal’ | ‘italic’ | ‘oblique’ | ‘normal’ | false |
| gap | 水印之间的间距 | [number, number] | [100, 100] | false |
| offset | 水印距离容器左上角的偏移量,默认为 gap/2 | [number, number] | [50, 50] | false |
效果如下图:在线预览




创建水印组件Watermark.vue
<script setup lang="ts">
import {unref,shallowRef,computed,watch,onMounted,onBeforeUnmount,nextTick,getCurrentInstance,getCurrentScope,onScopeDispose
} from 'vue'
import type { CSSProperties } from 'vue'
interface Props {width?: number // 水印的宽度,默认值为 content 自身的宽度height?: number // 水印的高度,默认值为 content 自身的高度rotate?: number // 水印绘制时,旋转的角度,单位 °zIndex?: number // 追加的水印元素的 z-indeximage?: string // 图片源,建议使用 2 倍或 3 倍图,优先级高于文字content?: string|string[] // 水印文字内容color?: string // 字体颜色fontSize?: number // 字体大小fontWeight?: 'normal'|'light'|'weight'|number // 字体粗细fontFamily?: string // 字体类型fontStyle?: 'none'|'normal'|'italic'|'oblique' // 字体样式gap?: [number, number] // 水印之间的间距offset?: [number, number] // 水印距离容器左上角的偏移量,默认为 gap/2
}
const props = withDefaults(defineProps<Props>(), {width: undefined,height: undefined,rotate: -22,zIndex: 9,image: undefined,content: '',color: 'rgba(0,0,0,.15)',fontSize: 16,fontWeight: 'normal',fontFamily: 'sans-serif',fontStyle: 'normal',gap: () => [100, 100],offset: () => [50, 50]
})
/*** Base size of the canvas, 1 for parallel layout and 2 for alternate layout* Only alternate layout is currently supported*/
const BaseSize = 2
const FontGap = 3
// 和 ref() 不同,浅层 ref 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对 .value 的访问是响应式的。
const containerRef = shallowRef() // ref() 的浅层作用形式
const watermarkRef = shallowRef()
const stopObservation = shallowRef(false)
const gapX = computed(() => props.gap?.[0] ?? 100)
const gapY = computed(() => props.gap?.[1] ?? 100)
const gapXCenter = computed(() => gapX.value / 2)
const gapYCenter = computed(() => gapY.value / 2)
const offsetLeft = computed(() => props.offset?.[0] ?? gapXCenter.value)
const offsetTop = computed(() => props.offset?.[1] ?? gapYCenter.value)
const markStyle = computed(() => {const markStyle: CSSProperties = {zIndex: props.zIndex ?? 9,position: 'absolute',left: 0,top: 0,width: '100%',height: '100%',pointerEvents: 'none',backgroundRepeat: 'repeat'}/** Calculate the style of the offset */let positionLeft = offsetLeft.value - gapXCenter.valuelet positionTop = offsetTop.value - gapYCenter.valueif (positionLeft > 0) {markStyle.left = `${positionLeft}px`markStyle.width = `calc(100% - ${positionLeft}px)`positionLeft = 0}if (positionTop > 0) {markStyle.top = `${positionTop}px`markStyle.height = `calc(100% - ${positionTop}px)`positionTop = 0}markStyle.backgroundPosition = `${positionLeft}px ${positionTop}px`return markStyle
})
const destroyWatermark = () => {if (watermarkRef.value) {watermarkRef.value.remove()watermarkRef.value = undefined}
}
const appendWatermark = (base64Url: string, markWidth: number) => {if (containerRef.value && watermarkRef.value) {stopObservation.value = truewatermarkRef.value.setAttribute('style',getStyleStr({...markStyle.value,backgroundImage: `url('${base64Url}')`,backgroundSize: `${(gapX.value + markWidth) * BaseSize}px`}))containerRef.value?.append(watermarkRef.value)// Delayed executionsetTimeout(() => {stopObservation.value = false})}
}
// converting camel-cased strings to be lowercase and link it with Separato
function toLowercaseSeparator(key: string) {return key.replace(/([A-Z])/g, '-$1').toLowerCase()
}
function getStyleStr(style: CSSProperties): string {return Object.keys(style).map((key: any) => `${toLowercaseSeparator(key)}: ${style[key]};`).join(' ')
}
/*Get the width and height of the watermark. The default values are as followsImage: [120, 64]; Content: It's calculated by content
*/
const getMarkSize = (ctx: CanvasRenderingContext2D) => {let defaultWidth = 120let defaultHeight = 64const content = props.contentconst image = props.imageconst width = props.widthconst height = props.heightconst fontSize = props.fontSizeconst fontFamily = props.fontFamilyif (!image && ctx.measureText) {ctx.font = `${Number(fontSize)}px ${fontFamily}`const contents = Array.isArray(content) ? content : [content]const widths = contents.map(item => ctx.measureText(item!).width)defaultWidth = Math.ceil(Math.max(...widths))defaultHeight = Number(fontSize) * contents.length + (contents.length - 1) * FontGap}return [width ?? defaultWidth, height ?? defaultHeight] as const
}
// Returns the ratio of the device's physical pixel resolution to the css pixel resolution
function getPixelRatio () {return window.devicePixelRatio || 1
}
const fillTexts = (ctx: CanvasRenderingContext2D,drawX: number,drawY: number,drawWidth: number,drawHeight: number,
) => {const ratio = getPixelRatio()const content = props.contentconst fontSize = props.fontSizeconst fontWeight = props.fontWeightconst fontFamily = props.fontFamilyconst fontStyle = props.fontStyleconst color = props.colorconst mergedFontSize = Number(fontSize) * ratioctx.font = `${fontStyle} normal ${fontWeight} ${mergedFontSize}px/${drawHeight}px ${fontFamily}`ctx.fillStyle = colorctx.textAlign = 'center'ctx.textBaseline = 'top'ctx.translate(drawWidth / 2, 0)const contents = Array.isArray(content) ? content : [content]contents?.forEach((item, index) => {ctx.fillText(item ?? '', drawX, drawY + index * (mergedFontSize + FontGap * ratio))})
}
const renderWatermark = () => {const canvas = document.createElement('canvas')const ctx = canvas.getContext('2d')const image = props.imageconst rotate = props.rotate ?? -22if (ctx) {if (!watermarkRef.value) {watermarkRef.value = document.createElement('div')}const ratio = getPixelRatio()const [markWidth, markHeight] = getMarkSize(ctx)const canvasWidth = (gapX.value + markWidth) * ratioconst canvasHeight = (gapY.value + markHeight) * ratiocanvas.setAttribute('width', `${canvasWidth * BaseSize}px`)canvas.setAttribute('height', `${canvasHeight * BaseSize}px`)const drawX = (gapX.value * ratio) / 2const drawY = (gapY.value * ratio) / 2const drawWidth = markWidth * ratioconst drawHeight = markHeight * ratioconst rotateX = (drawWidth + gapX.value * ratio) / 2const rotateY = (drawHeight + gapY.value * ratio) / 2/** Alternate drawing parameters */const alternateDrawX = drawX + canvasWidthconst alternateDrawY = drawY + canvasHeightconst alternateRotateX = rotateX + canvasWidthconst alternateRotateY = rotateY + canvasHeightctx.save()rotateWatermark(ctx, rotateX, rotateY, rotate)if (image) {const img = new Image()img.onload = () => {ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight)/** Draw interleaved pictures after rotation */ctx.restore()rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate)ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight)appendWatermark(canvas.toDataURL(), markWidth)}img.crossOrigin = 'anonymous'img.referrerPolicy = 'no-referrer'img.src = image} else {fillTexts(ctx, drawX, drawY, drawWidth, drawHeight)/** Fill the interleaved text after rotation */ctx.restore()rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate)fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight)appendWatermark(canvas.toDataURL(), markWidth)}}
}
// Rotate with the watermark as the center point
function rotateWatermark(ctx: CanvasRenderingContext2D,rotateX: number,rotateY: number,rotate: number
) {ctx.translate(rotateX, rotateY)ctx.rotate((Math.PI / 180) * Number(rotate))ctx.translate(-rotateX, -rotateY)
}
onMounted(() => {renderWatermark()
})
watch(() => [props],() => {renderWatermark()},{deep: true, // 强制转成深层侦听器flush: 'post' // 在侦听器回调中访问被 Vue 更新之后的 DOM},
)
onBeforeUnmount(() => {destroyWatermark()
})
// Whether to re-render the watermark
const reRendering = (mutation: MutationRecord, watermarkElement?: HTMLElement) => {let flag = false// Whether to delete the watermark nodeif (mutation.removedNodes.length) {flag = Array.from(mutation.removedNodes).some(node => node === watermarkElement)}// Whether the watermark dom property value has been modifiedif (mutation.type === 'attributes' && mutation.target === watermarkElement) {flag = true}return flag
}
const onMutate = (mutations: MutationRecord[]) => {if (stopObservation.value) {return}mutations.forEach(mutation => {if (reRendering(mutation, watermarkRef.value)) {destroyWatermark()renderWatermark()}})
}
const defaultWindow = typeof window !== 'undefined' ? window : undefined
type Fn = () => void
function tryOnMounted(fn: Fn, sync = true) {if (getCurrentInstance()) onMounted(fn)else if (sync) fn()else nextTick(fn)
}
function useSupported(callback: () => unknown, sync = false) {const isSupported = shallowRef<boolean>()const update = () => (isSupported.value = Boolean(callback()))update()tryOnMounted(update, sync)return isSupported
}
function useMutationObserver(target: any,callback: MutationCallback,options: any,
) {const { window = defaultWindow, ...mutationOptions } = optionslet observer: MutationObserver | undefinedconst isSupported = useSupported(() => window && 'MutationObserver' in window)const cleanup = () => {if (observer) {observer.disconnect()observer = undefined}}const stopWatch = watch(() => unref(target),el => {cleanup()if (isSupported.value && window && el) {observer = new MutationObserver(callback)observer!.observe(el, mutationOptions)}},{ immediate: true })const stop = () => {cleanup()stopWatch()}tryOnScopeDispose(stop)return {isSupported,stop}
}
function tryOnScopeDispose(fn: Fn) {if (getCurrentScope()) {onScopeDispose(fn)return true}return false
}
useMutationObserver(containerRef, onMutate, {attributes: true // 观察所有监听的节点属性值的变化
})
</script>
<template><div ref="containerRef" style="position: relative;"><slot></slot></div>
</template>
在要使用的页面引入
<script setup lang="ts">
import Watermark from './Watermark.vue'
import { reactive } from 'vue'
const model = reactive({content: 'Vue Amazing UI',color: 'rgba(0,0,0,.15)',fontSize: 16,fontWeight: 400,zIndex: 9,rotate: -22,gap: [100, 100] as [number, number],offset: []
})
</script>
<template><div><h1>Watermark 水印</h1><h2 class="mt30 mb10">基本使用</h2><Watermark content="Vue Amazing UI"><div style="height: 360px" /></Watermark><h2 class="mt30 mb10">多行水印</h2><h3 class="mb10">通过 content 设置 字符串数组 指定多行文字水印内容。</h3><Watermark :content="['Vue Amazing UI', 'Hello World']"><div style="height: 400px" /></Watermark><h2 class="mt30 mb10">图片水印</h2><h3 class="mb10">通过 image 指定图片地址。为保证图片高清且不被拉伸,请设置 width 和 height, 并上传至少两倍的宽高的 logo 图片地址。</h3><Watermark:height="30":width="130"image="https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*lkAoRbywo0oAAAAAAAAAAAAADrJ8AQ/original"><div style="height: 360px" /></Watermark><h2 class="mt30 mb10">自定义配置</h2><h3 class="mb10">通过自定义参数配置预览水印效果。</h3><Flex><Watermark v-bind="model"><p class="u-paragraph">The light-speed iteration of the digital world makes products more complex. However, humanconsciousness and attention resources are limited. Facing this design contradiction, thepursuit of natural interaction will be the consistent direction of Ant Design.</p><p class="u-paragraph">Natural user cognition: According to cognitive psychology, about 80% of externalinformation is obtained through visual channels. The most important visual elements in theinterface design, including layout, colors, illustrations, icons, etc., should fullyabsorb the laws of nature, thereby reducing the user's cognitive cost and bringingauthentic and smooth feelings. In some scenarios, opportunely adding other sensorychannels such as hearing, touch can create a richer and more natural product experience.</p><p class="u-paragraph">Natural user behavior: In the interaction with the system, the designer should fullyunderstand the relationship between users, system roles, and task objectives, and alsocontextually organize system functions and services. At the same time, a series of methodssuch as behavior analysis, artificial intelligence and sensors could be applied to assistusers to make effective decisions and reduce extra operations of users, to saveusers' mental and physical resources and make human-computer interaction morenatural.</p><imgstyle=" position: relative; z-index: 1; width: 100%; max-width: 800px;"src="https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.3/6.jpg"alt="示例图片"/></Watermark><Flexstyle="width: 25%;flex-shrink: 0;border-left: 1px solid #eee;padding-left: 20px;margin-left: 20px;"verticalgap="middle"><p>Content</p><Input v-model:value="model.content" /><p>Color</p><Input v-model:value="model.color" /><p>FontSize</p><Slider v-model:value="model.fontSize" :step="1" :min="0" :max="100" /><p>FontWeight</p><InputNumber v-model:value="model.fontWeight" :step="100" :min="100" :max="1000" /><p>zIndex</p><Slider v-model:value="model.zIndex" :step="1" :min="0" :max="100" /><p>Rotate</p><Slider v-model:value="model.rotate" :step="1" :min="-180" :max="180" /><p>Gap</p><Space style="display: flex" align="baseline"><InputNumber v-model:value="model.gap[0]" placeholder="gapX" /><InputNumber v-model:value="model.gap[1]" placeholder="gapY" /></Space><p>Offset</p><Space style="display: flex" align="baseline"><InputNumber v-model:value="model.offset[0]" placeholder="offsetLeft" /><InputNumber v-model:value="model.offset[1]" placeholder="offsetTop" /></Space></Flex></Flex></div>
</template>
<style>
.u-paragraph {margin-bottom: 1em;color: rgba(0, 0, 0, .88);word-break: break-word;line-height: 1.5714285714285714;
}
</style>
相关文章:
Vue3水印(Watermark)
APIs 参数说明类型默认值必传width水印的宽度,默认值为 content 自身的宽度numberundefinedfalseheight水印的高度,默认值为 content 自身的高度numberundefinedfalserotate水印绘制时,旋转的角度,单位 number-22falsezIndex追加…...
redis的性能管理、主从复制和哨兵模式
一、redis的性能管理 redis的数据时缓存在内存中的 查看系统内存情况 info memory used_memory:853688 redis中数据占用的内存 used_memory_rss:10522624 redis向操作系统申请的内存 used_memory_peak:853688 redis使用内存的峰值 系统巡检:硬件巡检、数据库 n…...
排序算法:归并排序、快速排序、堆排序
归并排序 要将一个数组排序,可以先将它分成两半分别排序,然后再将结果合并(归并)起来。这里的分成的两半,每部分可以使用其他排序算法,也可以仍然使用归并排序(递归)。 我看《算法》…...
Redis 面试题——持久化
目录 1.概述1.1.Redis 的持久化功能是指什么?1.2.Redis 有哪些持久化机制? 2.RDB2.1.什么是 RDB 持久化?2.2.Redis 中使用什么命令来生成 RDB 快照文件?2.3.如何在 Redis 的配置文件中对 RDB 进行配置?2.4.✨RDB 持久化…...
Linux使用固定ip地址
设置静态ip,我们就需要修改 /etc/sysconfig/network-scripts/ifcfg-ens33 配置文件。 vim /etc/sysconfig/network-scripts/ifcfg-ens33 //进入网卡ens33的配置页面 (1) 将 BOOTPROTO dhcp 改成 BOOTPROTO static 也就是将动态ip,改成静态i…...
ESP Multi-Room Music 方案:支持音频实时同步播放 实现音乐互联共享
项目背景 随着无线通信技术的发展,针对不同音频应用领域的无线音频产品正不断涌现。近日,乐鑫科技推出了基于 Wi-Fi 的多扬声器互联共享音乐通信协议——ESP Multi-Room Music 方案。该方案使用乐鑫自研的基于 Wi-Fi 局域网的音频同步播放技术ÿ…...
java分布式锁分布式锁
java分布式&锁&分布式锁 锁 锁的作用:有限资源的情况下,控制同一时间段,只有某些线程(用户/服务器)能访问到资源。 锁在java中的实现: synchronized关键字并发包的类 缺点:只对单个的…...
2. 流程控制|方法|数组|二维数组|递归
文章目录 流程控制代码块选择结构循环结构跳转控制关键字 方法方法的概述方法的重载Junit单元测试初识全限定类名 Debug 小技巧数组数组的基本概念数组的基本使用数组的声明数组的初始化 JVM内存模型什么是引用数据类型基本数据类型和引用数据类型的区别堆和栈中内容的区别 数组…...
22. 自动装配有哪些限制(需要注意)?
自动装配有哪些限制(需要注意)? 一定要声明set方法覆盖: 你仍可以用 < constructor-arg >和 < property > 配置来定义依赖,这些配置将始终覆盖自动注入。基本数据类型:不能自动装配简单的属性,如基本数据…...
14 网关实战:网关聚合API文档
上节课介绍了网关层的认证鉴权,今天这节介绍一下网关层如何聚合API接口文文档。 为什么需要聚合API接口文档? 大型微服务系统模块众多,木谷博客系统就有9个,如果这些服务的接口地址没有一个统一,那么客户端将要保存每个服务的接口地址,这个肯定是不现实。 先来看一下A…...
css 固定按钮到页面顶部或者底部的实现方式
实现方式 要将按钮固定到顶部或底部,可以使用CSS的定位属性来实现。下面是一种常用的方法: 创建一个包含按钮的HTML元素,例如一个<div>元素。确保给它添加一个唯一的id,以便在CSS中进行定位。 <div id"myButton&qu…...
【Java Spring】SpringBoot常用插件
文章目录 1、Lombok1.1 IDEA社区版安装Lombok1.2 IDEA专业版安装Lombok1.3 Lombok的基本使用 2、EditStarters2.1 IDEA安装EditStarters2.2 EditStarters基本使用方法 1、Lombok 是简化Java开发的一个必要工具,lombok的原理是编译过程中将lombok的注解给去掉并翻译…...
GPT还远远不是真正的智能
GPT是一个基于深度学习的自然语言处理模型,它可以生成逼真的文本。虽然GPT在生成文本方面取得了显著的进展,但它并不具备真正的智能。GPT是通过训练模型来学习语言模式,它不具备理解、推理、判断和主动学习的能力。它只是根据已有的语料库生成…...
计算机网络:网络层
0 本节主要内容 问题描述 解决思路 1 问题描述 两大问题(重点,也是难点): 地址管理;路由选择。 1.1 子问题1:地址管理 网络上的这些主机和节点都需要使用一种规则来区分,就相当于是一种身…...
消息队列进阶-1.消息队列的应用场景与选型
👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理🔥如果感觉博主的文章还不错的话,请ὄ…...
浅谈堆和栈内存以及编程语言
浅谈堆和栈内存以及编程语言 栈和堆C 和 C# 的区别:C#总结 编程语言C汇编语言(Assembly Language):机器语言(Machine Language): 拓展C#依赖注入(Dependency Injection)模…...
SpringBootWeb案例_01
Web后端开发_04 SpringBootWeb案例_01 原型展示 成品展示 准备工作 需求&环境搭建 需求说明: 完成tlias智能学习辅助系统的部门管理,员工管理 环境搭建 准备数据库表(dept、emp)创建springboot工程,引入对应…...
C语言数据结构-----栈和队列练习题(分析+代码)
前言 前面的博客写了如何实现栈和队列,下来我们来看一下队列和栈的相关习题。 链接: 栈和队列的实现 文章目录 前言1.用栈实现括号匹配2.用队列实现栈3.用栈实现队列4.设计循环队列 1.用栈实现括号匹配 此题最重要的就是数量匹配和顺序匹配。 用栈可以完美的做到…...
uniapp基础-教程之HBuilderX配置篇-01
uniapp教程之HBuilderX配置篇-01 为什么要做这个教程的梳理,主要用于自己学习和总结,利于增加自己的积累和记忆。首先下载HBuilderX,并保证你的软件在C盘进行运行,最好使用英文或者拼音,这个操作是为了保证软件的稳定…...
【备忘录】快速回忆ElasticSearch的CRUD
导引——第一条ElasticSearch语句 测试分词器 POST /_analyze {"text":"黑马程序员学习java太棒了","analyzer": "ik_smart" }概念 语法规则 HTTP_METHOD /index/_action/IDHTTP_METHOD 是 HTTP 请求的方法,常见的包括…...
Youtu-Parsing本地化部署详解:OpenClaw工具链整合实践
Youtu-Parsing本地化部署详解:OpenClaw工具链整合实践 最近在折腾本地AI工具链,发现很多朋友对文档解析这个场景特别感兴趣。无论是处理合同、分析报告,还是批量整理PDF资料,如果能有个稳定、高效且完全离线的解析工具࿰…...
HunyuanVideo-Foley入门必看:音频质量客观指标(PESQ/STOI)实测报告
HunyuanVideo-Foley入门必看:音频质量客观指标(PESQ/STOI)实测报告 1. 引言 在音视频生成领域,音频质量评估一直是开发者关注的重点。HunyuanVideo-Foley作为一款集视频生成与音效生成于一体的AI工具,其音频输出质量…...
3步掌握APK Installer:如何在Windows上无缝运行安卓应用?
3步掌握APK Installer:如何在Windows上无缝运行安卓应用? 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否厌倦了臃肿的安卓模拟器&#x…...
如何通过3个关键步骤将HDRI全景图转换为立方体贴图:从概念到实践
如何通过3个关键步骤将HDRI全景图转换为立方体贴图:从概念到实践 【免费下载链接】HDRI-to-CubeMap Image converter from spherical map to cubemap 项目地址: https://gitcode.com/gh_mirrors/hd/HDRI-to-CubeMap HDRI-to-CubeMap是一个基于浏览器的专业工…...
NOKOV动捕软件数据处理实战:从MarkerSet构建到刚体应用
1. 动捕数据处理入门:从零认识NOKOV工作流 第一次接触NOKOV动捕软件时,我被它强大的数据处理能力震撼到了。这套系统不仅能捕捉演员的动作,还能把数据直接用在无人机、机械臂控制上。今天我就带大家走一遍完整的流程,从原始数据导…...
别再让PCB走线偷走你的电压!手把手教你用开尔文四线连接搞定FPGA核心电源设计
别再让PCB走线偷走你的电压!手把手教你用开尔文四线连接搞定FPGA核心电源设计 调试FPGA板卡时,你是否遇到过这样的场景:电源模块输出显示1.8V完美无缺,但用万用表测量FPGA核心供电引脚时,电压却只有1.72V?…...
OpenFace面部分析实战:多模态行为理解的完整解决方案
OpenFace面部分析实战:多模态行为理解的完整解决方案 【免费下载链接】OpenFace OpenFace – a state-of-the art tool intended for facial landmark detection, head pose estimation, facial action unit recognition, and eye-gaze estimation. 项目地址: htt…...
网络安全应急响应流程
网络安全应急响应流程:守护数字世界的防火墙 在数字化时代,网络安全事件频发,从数据泄露到勒索软件攻击,企业和组织面临的威胁日益复杂。网络安全应急响应流程(Incident Response, IR)是应对这些威胁的核心…...
Harness到底是什么?
一、大白话定义:理解Harness的底层隐喻 Harness本义为马具、缰绳,映射到AI领域,它不属于全新算法或大模型,而是包裹在原生大模型外层,用于管控智能体全链路运行的工程闭环体系。 可以用通俗逻辑对照: 原…...
辅助驾驶场景应用:如何用视觉定位模型理解道路目标
辅助驾驶场景应用:如何用视觉定位模型理解道路目标 1. 从“指哪打哪”到“看懂路况”:视觉定位在辅助驾驶中的价值 想象一下,你坐在副驾驶,用手指着前方说:“注意右边那辆白色轿车,它可能要变道。” 驾驶…...
