边缘的检测

边缘检测效果,是一种用于突出图像中的边缘,使物体的轮廓更加明显的图像处理技术,边缘检测的主要目的是找到图像中亮度变化显著的区域,这些区域通常对应于物体的边界,边缘检测相当于利用 Shader 代码自动给屏幕图像进行描边处理

1、边缘检测基本原理

计算每个像素的灰度值,用灰度值结合卷积核进行卷积运算,得到该像素的梯度值,梯度值越大越靠近边界,越趋近于描边颜色;梯度值越小表明不是边界位置,越趋近于原始颜色
关键知识点:灰度值、卷积、卷积核、梯度值

灰度值

由于人眼对不同颜色的敏感度不同,所以在计算平均值时不会直接使用算数平均(R+G+B)/3
在图形学中我们一般使用加权平均法来计算灰度值
所谓加权平均法就是通过对不同数据分配不同权重,计算出更符合实际情况的平均值
下面是基于 Rec. 709标准 计算的灰度值(高清电视和许多数字图像格式中常用的标准)
灰度值 L = 0.2126*R + 0.7152*G + 0.0722*B

卷积、卷积核、梯度值

卷积是一种数学计算方式,首先通过一个比喻来理解卷积在边缘检测中的作用,它就像是要用一个放大镜(卷积核)在图片上移动,放大镜(卷积核)的作用是帮助我们看到图,片上的细微变化。当我们用这个放大镜(卷积核)扫描整张图片时,它能帮助我们发现图片上哪些地方颜色变化突然,这些突然变化的地方往往就是物体的边缘了

假设我们有一张 5x5 的图像,每一个格子代表一个像素,格子中的数据表示该像素的灰度值,假设我们有一个 3x3 的卷积核(放大镜)

如果你想要求出图中红色格子的梯度值(值越大表示越靠近边缘),如果你想要求出图中红色格子的梯度值(值越大表示越靠近边缘)进行如下计算:

最终算出来的结果就表示该像素的梯度值,我们便可以用该值决定边缘效果了

从卷积的计算方式我们可以得知,其中卷积核(也被称为边缘检测因子)是非常重要的一个元素,在图形学中,有三种常用的卷积核(边缘检测因子),他们分别是:

  • Roberts 算子:由拉里·罗伯茨(Larry Roberts)于1965年提出
  • Prewitt 算子:由约翰·普雷维特(John Prewitt)于1970年提出
  • Sobel 算子:由欧文·索贝尔(Irwin Sobel)于1968年提出

图形学中最常用的还是Sobel算子,因为它更适合高精度的边缘检测

可以看到三种算子都包含了两个方向的卷积核,他们分别用来检测水平和竖直方向上的边缘信息
边缘检测的卷积计算时,只需要对每个像素进行两次卷积计算即可,这样就可以得到两个方向的梯度值 Gx 和 Gy,而该像素的整体梯度值 G = abs(Gx) + abs(Gy)

已经知道了通过卷积获取梯度值的基本原理那么我们只需要定义一个描边颜色,利用Shader中的内置函数lerp,在原始颜色和描边颜色之间利用梯度值进行插值即可
最终颜色 = lerp(原始颜色,描边颜色,梯度值)
梯度值越大表明越接近边缘,则颜色越接近描边颜色;反之越接近原始颜色

2、如何得到当前像素周围8个像素位置

想要获取当前像素周围8个像素的位置,我们需要Unity 提供给我们用于访问纹理对应的每个纹素(像素)的大小 的变量——float4 纹理名_TexelSize
类似 纹理名_ST(用于获取纹理缩放偏移的变量)
其中的xyzw分别代表(假设纹理宽高为 1024 * 768)

  • x:1/纹理宽度 = 1/1024
  • y:1/纹理高度 = 1/768
  • z:纹理宽度 = 1024
  • w:纹理高度 = 768

可以利用 float4 纹理名_TexelSize 纹素 信息得到当前像素周围8个像素位置,可以进行uv坐标偏移计算,在 顶点着色器函数 或者 片元着色器函数 中计算都行,但是建议在顶点着色器函数中计算,可以节约计算量,片元着色器中直接使用插值的结果也不会影响纹理坐标的计算结果

3、边缘检测的实现

Shader "Unlit/EdgeDetection"
{Properties{_MainTex ("Texture", 2D) = "white" {}_EdgeColor ("EdgeColor", Color) = (0, 0, 0, 0)_EdgeFactor ("EdgeFactor", Float) = 1}SubShader{Tags { "RenderType"="Opaque" }Pass{ZTest AlwaysCull OffZWrite OffCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{half2 uv[9] : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;half4 _MainTex_TexelSize;fixed4 _EdgeColor;fixed _EdgeFactor;v2f vert (appdata_base v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);half2 uv = v.texcoord;o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1, -1);o.uv[1] = uv + _MainTex_TexelSize.xy * half2(-1, 0);o.uv[2] = uv + _MainTex_TexelSize.xy * half2(-1, 1);o.uv[3] = uv + _MainTex_TexelSize.xy * half2(0, -1);o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0, 0);o.uv[5] = uv + _MainTex_TexelSize.xy * half2(0, 1);o.uv[6] = uv + _MainTex_TexelSize.xy * half2(1, -1);o.uv[7] = uv + _MainTex_TexelSize.xy * half2(1, 0);o.uv[8] = uv + _MainTex_TexelSize.xy * half2(1, 1);return o;}// 计算灰度值fixed4 calcuminance(fixed4 color){return 0.2126 * color.r + 0.71522 * color.g + 0.0722 * color.b;}half Sobel(v2f o){half Gx[9] = {-1, -2, -1,0,   0,  0,1,   2,  1};half Gy[9] = {-1,  0,  1,-2,  0,  2,-1,  0,  1};half L;half edgeX = 0;half edgeY = 0;for (int i = 0; i < 9; i++){// 采样后获取灰度值L = calcuminance(tex2D(_MainTex, o.uv[i]));edgeX += L * Gx[i];edgeY += L * Gy[i];}return abs(edgeX) + abs(edgeY);}fixed4 frag (v2f i) : SV_Target{half edge = Sobel(i);return lerp(tex2D(_MainTex, i.uv[4]), _EdgeColor, edge * _EdgeFactor);}ENDCG}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class EdgeDetection : PostEffectBase
{public Color EdgeColor;[Range(0, 1)]public float EdgeFactor;protected override void UpdateProperty() {if (material != null) {material.SetFloat("_EdgeFactor", EdgeFactor);material.SetColor("_EdgeColor", EdgeColor);}}
}

 4、边缘检测的纯色背景功能

边缘描边时,有时只想保留描边的边缘线,不想要显示原图的背景颜色,比如把整个背景变为白色、黑色、等等自定义颜色,而抛弃掉原本图片的颜色信息,效果就像是一张描边图片

需要做以下:

(1)新属性声明

  • 添加 背景颜色程度变量 _BackgroundExtent 0表示保留图片原始颜色,1表示完全抛弃图片原始颜色,0~1之间可以自己控制保留程度
  • 添加自定义背景颜色 _BackgroundColor,定义用于替换图片原始颜色的颜色

(2)修改片元着色器

  • 利用插值运算,记录纯色背景中像素描边颜色
  • 利用插值运算,在 原始图片描边 和 纯色图片描边 之间用程度变量进行控制
Shader "Unlit/EdgeDetection"
{Properties{_MainTex ("Texture", 2D) = "white" {}_EdgeColor ("EdgeColor", Color) = (0, 0, 0, 0)_EdgeFactor ("EdgeFactor", Float) = 1_BackgroundExtent ("BackgroundExtent", Range(0, 1)) = 0_BackgroundColor ("BackgroundColor", Color) = (1, 1, 1, 1)}SubShader{Tags { "RenderType"="Opaque" }Pass{ZTest AlwaysCull OffZWrite OffCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct v2f{half2 uv[9] : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;half4 _MainTex_TexelSize;fixed4 _EdgeColor;fixed _EdgeFactor;fixed _BackgroundExtent;fixed4 _BackgroundColor;v2f vert (appdata_base v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);half2 uv = v.texcoord;o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1, -1);o.uv[1] = uv + _MainTex_TexelSize.xy * half2(-1, 0);o.uv[2] = uv + _MainTex_TexelSize.xy * half2(-1, 1);o.uv[3] = uv + _MainTex_TexelSize.xy * half2(0, -1);o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0, 0);o.uv[5] = uv + _MainTex_TexelSize.xy * half2(0, 1);o.uv[6] = uv + _MainTex_TexelSize.xy * half2(1, -1);o.uv[7] = uv + _MainTex_TexelSize.xy * half2(1, 0);o.uv[8] = uv + _MainTex_TexelSize.xy * half2(1, 1);return o;}// 计算灰度值fixed4 calcuminance(fixed4 color){return 0.2126 * color.r + 0.71522 * color.g + 0.0722 * color.b;}half Sobel(v2f o){half Gx[9] = {-1, -2, -1,0,   0,  0,1,   2,  1};half Gy[9] = {-1,  0,  1,-2,  0,  2,-1,  0,  1};half L;half edgeX = 0;half edgeY = 0;for (int i = 0; i < 9; i++){// 采样后获取灰度值L = calcuminance(tex2D(_MainTex, o.uv[i]));edgeX += L * Gx[i];edgeY += L * Gy[i];}return abs(edgeX) + abs(edgeY);}fixed4 frag (v2f i) : SV_Target{half edge = Sobel(i);fixed4 withEdgeColor = lerp(tex2D(_MainTex, i.uv[4]), _EdgeColor, edge * _EdgeFactor);fixed4 onlyEdgeColor = lerp(_BackgroundColor, _EdgeColor, edge * _EdgeFactor);return lerp(withEdgeColor, onlyEdgeColor, _BackgroundExtent);}ENDCG}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class EdgeDetection : PostEffectBase
{public Color EdgeColor;public Color BackgroundColor;[Range(0, 1)]public float EdgeFactor;[Range(0, 1)]public float BackgroundExtent;protected override void UpdateProperty() {if (material != null) {material.SetFloat("_EdgeFactor", EdgeFactor);material.SetFloat("_BackgroundExtent", BackgroundExtent);material.SetColor("_EdgeColor", EdgeColor);material.SetColor("_BackgroundColor", BackgroundColor);}}
}

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

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

相关文章

HP G10服务器ESXI6.7告警提示ramdisk tmp已满

物理服务器是HP G10 VCENTER内两台服务器报错提示ramdisk"tmp"已满&#xff0c;无法写入文件 登录ESXI命令行后发现两台主机的/tmp目录都没有空间了 定位到是ams-bbUsg.txt文件占用了大量的空间 1、关闭集群的DRS功能 2、迁移当前主机上面运行的所有虚拟机至其他主…

深度学习中的感受野:从基础概念到多层次特征提取

在深度学习&#xff0c;特别是计算机视觉任务中&#xff0c;感受野&#xff08;Receptive Field&#xff09;是一个至关重要的概念。它指的是在神经网络中某一层的神经元在输入图像上“看到”的区域大小。感受野的大小影响了网络能捕捉的特征层级&#xff0c;从而决定了它的特征…

Diffusion Policy——斯坦福机器人UMI所用的扩散策略:从原理到其编码实现(含Diff-Control、ControlNet详解)

前言 本文一开始是属于此文《UMI——斯坦福刷盘机器人&#xff1a;从手持夹持器到动作预测Diffusion Policy(含代码解读)》的第三部分&#xff0c;考虑后Diffusion Policy的重要性很高&#xff0c;加之后续还有一系列基于其的改进工作 故独立成本文&#xff0c;且写的过程中 …

【数据结构与算法】第12课—数据结构之归并排序

文章目录 1. 归并排序2. 计数排序3. 排序算法复杂度及稳定性分析在这里插入图片描述 1. 归并排序 分治法&#xff08;Divide and Conquer&#xff09;是一种重要的算法设计策略&#xff0c;其核心思想是将一个复杂的大问题分解为若干个小规模的子问题&#xff0c;递归地解决这些…

2024 年 Apifox 和 Postman 对比介绍详细版

Apifox VS Postman &#xff0c;当下流行的的两款 API 开发工具&#xff0c;2024 版对比&#xff01;

vue请求数据报错,设置支持跨域请求,以及2种请求方法axios或者async与await

设置跨域 通过vite创建的项目&#xff0c;一般会在你项目文件中自动生成一个名为vite.config文件&#xff0c;点击添加支持跨域的代码 import { defineConfig } from vite import vue from vitejs/plugin-vue// https://vitejs.dev/config/ export default defineConfig({plu…

【ACM出版】第四届信号处理与通信技术国际学术会议(SPCT 2024)

& 第四届信号处理与通信技术国际学术会议&#xff08;SPCT 2024&#xff09; 2024 4th International Conference on Signal Processing and Communication Technology 2024年12月27-29日 中国深圳 www.icspct.com 第四届信号处理与通信技术国际学术会议&#x…

【大数据学习 | HBASE高级】rowkey的设计,hbase的预分区和压缩

1. rowkey的设计 ​ RowKey可以是任意字符串&#xff0c;最大长度64KB&#xff0c;实际应用中一般为10~100bytes&#xff0c;字典顺序排序&#xff0c;rowkey的设计至关重要&#xff0c;会影响region分布&#xff0c;如果rowkey设计不合理还会出现region写热点等一系列问题。 …

基于微信小程序的农场管理系统的设计与实现,LW+源码+讲解

1.2 课题意义 现如今&#xff0c;信息种类变得越来越多&#xff0c;信息的容量也变得越来越大&#xff0c;这就是信息时代的标志。近些年&#xff0c;计算机科学发展得也越来越快&#xff0c;而且软件开发技术也越来越成熟&#xff0c;因此&#xff0c;在生活中的各个领域&…

学习记录:js算法(九十二):克隆图

文章目录 克隆图思路一 克隆图 给你无向 连通 图中一个节点的引用&#xff0c;请你返回该图的 深拷贝&#xff08;克隆&#xff09;。 图中的每个节点都包含它的值 val&#xff08;int&#xff09; 和其邻居的列表&#xff08;list[Node]&#xff09;。 class Node {public int…

大数据新视界 -- 大数据大厂之 Impala 性能飞跃:动态分区调整的策略与方法(上)(21 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

win11 新建一个批处理,双击查看本机的IP地址

1、先上个图&#xff1a; 2、bat的代码&#xff1a; :: 获取本机 IP 地址 &#xff1a; 只显示ip echo off for /f "tokens2 delims:" %%a in (ipconfig ^| findstr /i "IP 地址") do set IP%%a echo %IP%pause 3、新建一个文件比如叫ip.bat&#xff0c;…

Spring高手之路26——全方位掌握事务监听器

文章目录 1. 什么是Spring事务监听器&#xff1f;2. 通过TransactionSynchronization 接口实现事务监听器3. 时序图&#xff1a;通过TransactionSynchronization 接口实现事务监听器4. TransactionalEventListener注解实现事务监听器5. 时序图&#xff1a;TransactionalEventLi…

QQ 小程序已发布,但无法被搜索的解决方案

前言 我的 QQ 小程序在 2024 年 8 月就已经审核通过&#xff0c;上架后却一直无法被搜索到。打开后&#xff0c;再在 QQ 上下拉查看 “最近使用”&#xff0c;发现他出现一下又马上消失。 上线是按正常流程走的&#xff0c;开发、备案、审核&#xff0c;没有任何违规&#xf…

MFC工控项目实例二十九主对话框调用子对话框设定参数值

在主对话框调用子对话框设定参数值&#xff0c;使用theApp变量实现。 子对话框各参数变量 CString m_strTypeName; CString m_strBrand; CString m_strRemark; double m_edit_min; double m_edit_max; double m_edit_time2; double …

C语言 | Leetcode C语言题解之第556题下一个更大元素III

题目&#xff1a; 题解&#xff1a; int nextGreaterElement(int n){int x n, cnt 1;for (; x > 10 && x / 10 % 10 > x % 10; x / 10) {cnt;}x / 10;if (x 0) {return -1;}int targetDigit x % 10;int x2 n, cnt2 0;for (; x2 % 10 < targetDigit; x2…

elementui el-table中给表头 el-table-column 加一个鼠标移入提示说明

前言 在使用el-table 表格中有些表格的表头需要加入一些提示&#xff0c;鼠标移入则出现提示&#xff0c;非常实用&#xff0c;我是通过el-table中的el-tooltip实现的&#xff0c;以下的效果预览 代码实现 <el-table ref"multipleTable" :data"data"…

阿里云通义大模型团队开源Qwen2.5-Coder:AI编程新纪元

&#x1f680; 11月12日&#xff0c;阿里云通义大模型团队宣布开源通义千问代码模型全系列&#xff0c;共6款Qwen2.5-Coder模型。这些模型在同等尺寸下均取得了业界最佳效果&#xff0c;其中32B尺寸的旗舰代码模型在十余项基准评测中均取得开源最佳成绩&#xff0c;成为全球最强…

python 同时控制多部手机

在这个智能时代,我们的手机早已成为生活和工作中不可或缺的工具。无论是管理多个社交媒体账号,还是处理多台设备上的事务,如何更高效地控制多个手机成为了每个人的痛点。 今天带来的这个的软件为你提供了一键控制多部手机的强大功能。无论是办公、娱乐,还是社交,你都能通过…

软件测试:测试用例详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、通用测试用例八要素   1、用例编号&#xff1b;    2、测试项目&#xff1b;   3、测试标题&#xff1b; 4、重要级别&#xff1b;    5、预置…