不知道公司是不是和我杠上了,进公司做的第一个项目是拍照,后面连续几个都有拍照功能,而且设计方案上还多加了签名的功能。
https://blog.csdn.net/weixin_37608784/article/details/82835865
上面网址介绍了我搜罗到的两种签名方法,可以用到项目中,方法一修改像素点,领导不满意,换了第二种方法,使用 LineRenderer 主相机照射 3D 场景和 UGUI 结合,达到签名效果。
本篇文章主要针对第二种方法进行优化。LineRenderer 这种方法本质是通过截图,并将截图叠加到照片上,再对照片进行二次截取进行保存。但是发现无论怎样截,都会把背景截进去,即主摄像机既能照到 LineRenderer 划出的线条(签名),也能找到线条后面的背景,签名那篇文章投机取巧将主相机上 Camera 组件上的 BackGround 修改为白色(这个也可以在线条后面加一个 Plane,只是确保大小在主相机的 Viewport Rect 在变成 (0,0,1,1)的时候能能把天空盒盖住(有点麻烦,直接修改天空盒就好)),还特意让美工在图片中间抠出一块透明的洞,让两个正好对上,造成假象。但效果是完成了。就是合成的时候把签名板背景图也给合成到照片上,像在照片上打了个补丁。
感觉一直是心里的一个梗,同时又因为接了个拍照项目,还有签名需求,而且甲方设计的相框在签名位置还有建筑线条,如果还是按照原来的方法就会把建筑线条盖住,索性找一找扣字效果的方法,即把背景图去掉。
不啰嗦了,文章参考了很多大神博客,都记不住了,在此感谢在博客上无私分享的前辈们。
先上效果图:
原理:
首先将图片灰度化处理,接着遍历所有像素,计算一下整张图的灰度的平均值(grayMean),图片中颜色较深部分,灰度值比较小,图片中颜色较浅部分,灰度值越大,加权平均值后总的平均值会比浅色部分的灰度值略低,比深色部分灰度值略高;然后再次遍历所有像素,并计算每个像素点的灰度,如果其灰度值比 grayMean 大,则将其 alpha 值设置为 0,即完全透明,否则不作处理。
代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class RemoveBorder : MonoBehaviour {
public Image img;//原始签名图片
Texture2D tex;
public RawImage showImg;//处理后图片
float grayMean;//整张图的平均灰度值
// Use this for initialization
void Start () {
tex = img.mainTexture as Texture2D;
showImg.texture=SpecialImgGray(tex) as Texture;
}
/// <summary>
/// 拍照人脸彩色图做成灰度图
/// </summary>
Texture2D SpecialImgGray(Texture2D texSrc)
{
int width = texSrc.width;
int height = texSrc.height;
Texture2D texRec = new Texture2D(texSrc.width, texSrc.height);
for (int i = 0; i < texSrc.width; i++)
{
for (int j = 0; j < texSrc.height; j++)
{
UnityEngine.Color c = texSrc.GetPixel(i, j);
float r, g, b = 0;
r = c.r;
g = c.g;
b = c.b;
//灰度值计算公式
grayMean += (r * 0.299f + g * 0.587f + b * 0.114f);
}
}
//计算平均灰度
grayMean = grayMean / (width * height);
for (int i = 0; i < texSrc.width; i++)
{
for (int j = 0; j < texSrc.height; j++)
{
UnityEngine.Color c = texSrc.GetPixel(i, j);
float r, g, b, Result = 0;
r = c.r;
g = c.g;
b = c.b;
//以加权平均值法 对图片进行灰度化处理
//下面的 switch 语句可以用这一句 Result = (r * 0.299f + g * 0.587f + b * 0.114f); 代替。写这么多是因为之前做图片灰度化处理,下面的三种方法都可以,包括 case 2 中注释掉的那一句,提供大家一个思路
int iType = 2;//1或者2都可以 3修改
switch (iType)
{
case 0://平均值法
Result = ((r + g + b) / 3);
break;
case 1://最大值法
Result = r > g ? r : g;
Result = Result > b ? Result : b;
break;
case 2://加权平均值法
//Result = ((float)(0.7 * r) + (float)(0.2 * g) + (float)(0.1 * b));
Result = (r * 0.299f + g * 0.587f + b * 0.114f);
break;
}
//如果灰度值大于当前的平均灰度值,则将 alpha 设为 0
if(Result>grayMean)
{
texRec.SetPixel(i, j, new UnityEngine.Color(Result, Result, Result,0));
}
}
}
texRec.Apply();
return texRec;
}
}
编辑器界面:
做两张图,一张 Image ,一张 RawImage,按照程序里的类型。你可以创建同一种类型。注意代码中类型的转换。Image上放你找到的签名图,注意:图片勾选 Read/Write Enabled ,图片可读写。
脚本挂到 Canvas 上,将两个物体拖拽到对应位置进行赋值。
运行即可。