-
c++图形中如何判断鼠标点击在一条直线上_PS教程:十种抠图方法【上】
2020-12-07 00:42:53今天的关键字是“抠图”日常工作生活中大家可能经常会用到抠图的技能方法很多包括使用美图秀秀等我之前也分享过比如利用ppt如何抠图那么今天就来给大家介绍十种用ps抠图的方法:1、橡皮擦:例如我要把第一张图片的云...今天的关键字是“抠图”
日常工作生活中大家可能经常会用到抠图的技能
方法很多
包括使用美图秀秀等
我之前也分享过比如利用ppt如何抠图
那么今天就来给大家介绍十种用ps抠图的方法:
1、橡皮擦:
例如
我要把第一张图片的云
替换到第二张图的大海上面去:
直接将两张图片拖进ps
摆放好图层顺序
然后选择橡皮擦工具进行擦除就可以了:
小技巧:
你可以调整图片的透明度,以免擦除过度
擦完之后再调整回来就可以了!
同时注意涂抹的时候
可以分别点击“【】”方括号键进行画笔大小的调整哦:
用这个方法进行抠图
优点:快
缺点:细节不容易被控制,对于两张图片合成的边缘部分处理,需要特别小心
2、魔术橡皮擦
又称魔棒工具
用这个方法也能快速的将背景进行去掉:
注意看一下左上角红色方框处的容差
这里做下解释容差值简单理解就是容许选择颜色的差别度
数值越大,容许的范围越广
所以当你选择魔棒工具来消除背景的时候
单击鼠标左键,发现消除的范围比较下的时候
不妨可以把容差值调大一些:
这样就可以轻松擦除掉背景了:
优点:比橡皮擦更快,适用于删除大范围的纯色背景
缺点:同样细节不易处理
3、快速选择工具:
同样还是这两张图
我们只需要点击快速选择工具
然后鼠标左键按住拖拽
进行框选要选择的区域就可以了:
框选过程中
如果遇到如红色方框处被多选的部分
可以按alt+鼠标拖拽去进行删减:
最后点击删除键
被选择的部分就会删除掉
选择过程中
同样可以分别点击“【】”方括号键
进行画笔大小的调整
让选区做到更加精细
以上三种方法
对于替换背景、风景等相当适用
但是都不太适合做特别细节的处理
4、多边形套索工具
如果抠取对象是边缘明显的多边形图形
那么用它就再适合不过了
例如下图
我要抠出麦克风
选择多边形套索工具:
操作方法是直接鼠标单击
然后拖动,这样它会形成一条直线
然后不断的重复将对象套住:
如果希望边缘部分不要太生硬
可以选择鼠标右键点击羽化几个像素:
这样图片就被抠出来了
当然,你也可以尝试用磁性套索工具
这里就不复述了:
这个应该是最常用的抠图方法之一了
边缘有弧度的图像不太适用
5、钢笔工具
钢笔工具的用途非常多
抠图也是其中的常用用途之一
它不同于多边形套索工具的是
可以抠除边缘有弧形的图像
如图
我们要把这个书本抠出来
点击钢笔工具:
单击鼠标建立一个描点
然后再点另外一个描点的时候
鼠标左键不放进行拖动
然后就可以画出弧形了
将整个图形勾勒一遍:
鼠标右键建立选区:
这样图像就会被抠出来了:
操作上来说
需要一定的练习
但是如果能熟练运用钢笔工具的画
无论是抠图,还是作图都会有相当大的帮助!
希望对小白们有所帮助,想学习更多关注我不迷路!
-
阿里云图像识别Java调用示例参考
2020-07-20 00:25:30图像识别服务(Image Recognition)基于大数据和深度学习实现,可精准识别图像中的视觉内容,包括上千种物体标签、数十种常见场景等,包含场景分类、图像打标、鉴黄等在线API服务模块,应用于智能相册管理、图片分类...阿里云图像识别Java调用示例参考
简介: 本文给出使用Java语言分别使用网络图片和本地图片调用场景识别API的示例。
概述
图像识别服务(Image Recognition)基于大数据和深度学习实现,可精准识别图像中的视觉内容,包括上千种物体标签、数十种常见场景等,包含场景分类、图像打标、鉴黄等在线API服务模块,应用于智能相册管理、图片分类和检索、图片安全监控等场景。下面给出使用Java语言分别使用网络图片和本地图片调用场景识别API的示例。
控制台测试
与人脸识别类似,可以参考:阿里云人脸识别使用流程简介 。
Java Code Sample
使用网络图片测试
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
//@SuppressWarnings(“restriction”)
public class ComputerDemo1 {/*
- 计算MD5+BASE64
/
public static String MD5Base64(String s) {
if (s == null)
return null;
String encodeStr = “”;
byte[] utfBytes = s.getBytes();
MessageDigest mdTemp;
try {
mdTemp = MessageDigest.getInstance(“MD5”);
mdTemp.update(utfBytes);
byte[] md5Bytes = mdTemp.digest();
BASE64Encoder b64Encoder = new BASE64Encoder();
encodeStr = b64Encoder.encode(md5Bytes);
} catch (Exception e) {
throw new Error("Failed to generate MD5 : " + e.getMessage());
}
return encodeStr;
}
/ - 计算 HMAC-SHA1
/
public static String HMACSha1(String data, String key) {
String result;
try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), “HmacSHA1”);
Mac mac = Mac.getInstance(“HmacSHA1”);
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
result = (new BASE64Encoder()).encode(rawHmac);
} catch (Exception e) {
throw new Error("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
/ - 等同于javaScript中的 new Date().toUTCString();
/
public static String toGMTString(Date date) {
SimpleDateFormat df = new SimpleDateFormat(“E, dd MMM yyyy HH:mm:ss z”, Locale.UK);
df.setTimeZone(new java.util.SimpleTimeZone(0, “GMT”));
return df.format(date);
}
/ - 发送POST请求
/
public static String sendPost(String url, String body, String ak_id, String ak_secret) throws Exception {
PrintWriter out = null;
BufferedReader in = null;
String result = “”;
int statusCode = 200;
try {
URL realUrl = new URL(url);
/
* http header 参数
/
String method = “POST”;
String accept = “application/json”;
String content_type = “application/json”;
String path = realUrl.getFile();
String date = toGMTString(new Date());
// 1.对body做MD5+BASE64加密
String bodyMd5 = MD5Base64(body);
String stringToSign = method + “\n” + accept + “\n” + bodyMd5 + “\n” + content_type + “\n” + date + “\n”
+ path;
// 2.计算 HMAC-SHA1
String signature = HMACSha1(stringToSign, ak_secret);
// 3.得到 authorization header
String authHeader = “Dataplus " + ak_id + “:” + signature;
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty(“accept”, accept);
conn.setRequestProperty(“content-type”, content_type);
conn.setRequestProperty(“date”, date);
conn.setRequestProperty(“Authorization”, authHeader);
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(body);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
statusCode = ((HttpURLConnection)conn).getResponseCode();
if(statusCode != 200) {
in = new BufferedReader(new InputStreamReader(((HttpURLConnection)conn).getErrorStream()));
} else {
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
}
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (statusCode != 200) {
throw new IOException(”\nHttp StatusCode: "+ statusCode + "\nErrorMessage: " + result);
}
return result;
}
/ - GET请求
/
public static String sendGet(String url, String ak_id, String ak_secret) throws Exception {
String result = “”;
BufferedReader in = null;
int statusCode = 200;
try {
URL realUrl = new URL(url);
/
* http header 参数
*/
String method = “GET”;
String accept = “application/json”;
String content_type = “application/json”;
String path = realUrl.getFile();
String date = toGMTString(new Date());
// 1.对body做MD5+BASE64加密
// String bodyMd5 = MD5Base64(body);
String stringToSign = method + “\n” + accept + “\n” + “” + “\n” + content_type + “\n” + date + “\n” + path;
// 2.计算 HMAC-SHA1
String signature = HMACSha1(stringToSign, ak_secret);
// 3.得到 authorization header
String authHeader = “Dataplus " + ak_id + “:” + signature;
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty(“accept”, accept);
connection.setRequestProperty(“content-type”, content_type);
connection.setRequestProperty(“date”, date);
connection.setRequestProperty(“Authorization”, authHeader);
connection.setRequestProperty(“Connection”, “keep-alive”);
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
statusCode = ((HttpURLConnection)connection).getResponseCode();
if(statusCode != 200) {
in = new BufferedReader(new InputStreamReader(((HttpURLConnection)connection).getErrorStream()));
} else {
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (statusCode != 200) {
throw new IOException(”\nHttp StatusCode: "+ statusCode + "\nErrorMessage: " + result);
}
return result;
}
public static void main(String[] args) throws Exception {
// 发送POST请求示例
String ak_id = “"; //用户ak
String ak_secret = "”; // 用户ak_secret
String url = “https://dtplus-cn-shanghai.data.aliyuncs.com/image/scene”;
String body = “{“type”: “0”, “image_url”:“https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1544608444&di=54513735567736d0eaeba7a13aa0421c&src=http://img5q.duitang.com/uploads/item/201411/23/20141123205812_Bircn.jpeg”}”;
System.out.println(“response body:” + sendPost(url, body, ak_id, ak_secret));
}
}使用本地图片测试
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
public class ComputerDemo2 {/*
-
计算MD5+BASE64
/
public static String MD5Base64(String s) {
if (s == null)
return null;
String encodeStr = “”;
byte[] utfBytes = s.getBytes();
MessageDigest mdTemp;
try {
mdTemp = MessageDigest.getInstance(“MD5”);
mdTemp.update(utfBytes);
byte[] md5Bytes = mdTemp.digest();
BASE64Encoder b64Encoder = new BASE64Encoder();
encodeStr = b64Encoder.encode(md5Bytes);
} catch (Exception e) {
throw new Error("Failed to generate MD5 : " + e.getMessage());
}
return encodeStr;
}
/ -
计算 HMAC-SHA1
/
public static String HMACSha1(String data, String key) {
String result;
try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), “HmacSHA1”);
Mac mac = Mac.getInstance(“HmacSHA1”);
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
result = (new BASE64Encoder()).encode(rawHmac);
} catch (Exception e) {
throw new Error("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
/ -
等同于javaScript中的 new Date().toUTCString();
/
public static String toGMTString(Date date) {
SimpleDateFormat df = new SimpleDateFormat(“E, dd MMM yyyy HH:mm:ss z”, Locale.UK);
df.setTimeZone(new java.util.SimpleTimeZone(0, “GMT”));
return df.format(date);
}
/ -
发送POST请求
/
public static String sendPost(String url, String body, String ak_id, String ak_secret) throws Exception {
PrintWriter out = null;
BufferedReader in = null;
String result = “”;
int statusCode = 200;
try {
URL realUrl = new URL(url);
/
* http header 参数
/
String method = “POST”;
String accept = “application/json”;
String content_type = “application/json”;
String path = realUrl.getFile();
String date = toGMTString(new Date());
// 1.对body做MD5+BASE64加密
String bodyMd5 = MD5Base64(body);
String stringToSign = method + “\n” + accept + “\n” + bodyMd5 + “\n” + content_type + “\n” + date + “\n”
+ path;
// 2.计算 HMAC-SHA1
String signature = HMACSha1(stringToSign, ak_secret);
// 3.得到 authorization header
String authHeader = “Dataplus " + ak_id + “:” + signature;
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty(“accept”, accept);
conn.setRequestProperty(“content-type”, content_type);
conn.setRequestProperty(“date”, date);
conn.setRequestProperty(“Authorization”, authHeader);
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(body);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
statusCode = ((HttpURLConnection)conn).getResponseCode();
if(statusCode != 200) {
in = new BufferedReader(new InputStreamReader(((HttpURLConnection)conn).getErrorStream()));
} else {
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
}
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
if (statusCode != 200) {
throw new IOException(”\nHttp StatusCode: "+ statusCode + "\nErrorMessage: " + result);
}
return result;
}
/ -
GET请求
/
public static String sendGet(String url, String ak_id, String ak_secret) throws Exception {
String result = “”;
BufferedReader in = null;
int statusCode = 200;
try {
URL realUrl = new URL(url);
/
* http header 参数
*/
String method = “GET”;
String accept = “application/json”;
String content_type = “application/json”;
String path = realUrl.getFile();
String date = toGMTString(new Date());
// 1.对body做MD5+BASE64加密
// String bodyMd5 = MD5Base64(body);
String stringToSign = method + “\n” + accept + “\n” + “” + “\n” + content_type + “\n” + date + “\n” + path;
// 2.计算 HMAC-SHA1
String signature = HMACSha1(stringToSign, ak_secret);
// 3.得到 authorization header
String authHeader = “Dataplus " + ak_id + “:” + signature;
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty(“accept”, accept);
connection.setRequestProperty(“content-type”, content_type);
connection.setRequestProperty(“date”, date);
connection.setRequestProperty(“Authorization”, authHeader);
connection.setRequestProperty(“Connection”, “keep-alive”);
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
statusCode = ((HttpURLConnection)connection).getResponseCode();
if(statusCode != 200) {
in = new BufferedReader(new InputStreamReader(((HttpURLConnection)connection).getErrorStream()));
} else {
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (statusCode != 200) {
throw new IOException(”\nHttp StatusCode: "+ statusCode + "\nErrorMessage: " + result);
}
return result;
}
public static void main(String[] args) throws Exception {
// 发送POST请求示例
String ak_id = “"; //用户ak
String ak_secret = "”; // 用户ak_secret
String url = “https://dtplus-cn-shanghai.data.aliyuncs.com/image/scene”;
//上传本地图片
// Request body
String pic_path = “C:\Users\taro.yt\Desktop\timg.jpg”;File picBase64 = new File(pic_path);
String pic = encodeImageToBase64(picBase64);//提出base64编码的换行符问题
String data = pic.replaceAll("[\s*\t\n\r]", “”);
data = “’” + data + “’”;String body = “{“type”: “1”, “content”:”+data+"}";
System.out.println(“response body:” + sendPost(url, body, ak_id, ak_secret));
}
/** -
将本地图片编码为base64
-
@param file
-
@return
-
@throws Exception
*/
public static String encodeImageToBase64(File file) throws Exception {
//将图片文件转化为字节数组字符串,并对其进行Base64编码处理
// loggerger.info(“图片的路径为:” + file.getAbsolutePath());InputStream in = null;
byte[] data = null;
//读取图片字节数组
try {
in = new FileInputStream(file);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
throw new Exception(“图片上传失败,请联系客服!”);
}
//对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
String base64 = encoder.encode(data);
return base64;//返回Base64编码过的字节数组字符串
}
}
测试结果
response body:{“tags”:[{“value”:“人物”,“confidence”:97.0},{“value”:“演出”,“confidence”:12.0},{“value”:“其他”,“confidence”:12.0},{“value”:“室内”,“confidence”:11.0}],“errno”:0,“request_id”:“b31aebed-305a-4377-a843-ac4e9d3d30c1”}
参考链接
场景识别API调用说明
- 计算MD5+BASE64
-
【华为云技术分享】人脸识别算法的训练之路(下)
2020-06-08 11:41:55我们知道深度卷积网络虽然作为一种黑盒模型,但是能够通过数据训练的方式去表征图片或者物体的特征。因此人脸识别算法可以通过卷积网络提取出大量的人脸特征向量,然后根据相似度判断与底库比较人脸识别
人脸识别问题本质是一个分类问题,即每一个人作为一类进行分类检测,但实际应用过程中会出现很多问题。第一,人脸类别很多,如果要识别一个城镇的所有人,那么分类类别就将近十万以上的类别,另外每一个人之间可获得的标注样本很少,会出现很多长尾数据。根据上述问题,要对传统的CNN分类网络进行修改。
我们知道深度卷积网络虽然作为一种黑盒模型,但是能够通过数据训练的方式去表征图片或者物体的特征。因此人脸识别算法可以通过卷积网络提取出大量的人脸特征向量,然后根据相似度判断与底库比较完成人脸的识别过程,因此算法网络能不能对不同的人脸生成不同的特征,对同一人脸生成相似的特征,将是这类embedding任务的重点,也就是怎么样能够最大化类间距离以及最小化类内距离。
在人脸识别中,主干网络可以利用各种卷积神经网络完成特征提取的工作,例如resnet,inception等等经典的卷积神经网络作为backbone,关键在于最后一层loss function的设计和实现。现在从两个思路分析一下基于深度学习的人脸识别算法中各种损失函数。
思路1:metric learning,包括contrastive loss, triplet loss以及sampling method
思路2:margin based classification,包括softmax with center loss, sphereface, normface, AM-sofrmax(cosface) 和arcface。
Metric Larning
1. Contrastive loss
深度学习中最先应用metric learning思想之一的便是DeepID2了。其中DeepID2最主要的改进是同一个网络同时训练verification和classification(有两个监督信号)。其中在verification loss的特征层中引入了contrastive loss。
Contrastive loss不仅考虑了相同类别的距离最小化,也同时考虑了不同类别的距离最大化,通过充分运用训练样本的label信息提升人脸识别的准确性。因此,该loss函数本质上使得同一个人的照片在特征空间距离足够近,不同人在特征空间里相距足够远直到超过某个阈值。(听起来和triplet loss有点像)。
Contrastive loss引入了两个信号,并通过两个信号对网络进行训练。其中识别信号的表达式如下:
验证信号的表达式如下:
基于这样的信号,DeepID2在训练的时候就不是以一张图片为单位了,而是以Image Pair为单位,每次输入两张图片,为同一人则
为1,如果不是同一人则
为-1.
1. Triplet loss from FaceNet
这篇15年来自Google的FaceNet同样是人脸识别领域分水岭性质的工作。它提出了一个绝大部分人脸问题的统一解决框架,即:识别、验证、搜索等问题都可以放到特征空间里做,需要专注解决的仅仅是如何将人脸更好的映射到特征空间。
Google在DeepID2的基础上,抛弃了分类层即Classification Loss,将Contrastive Loss改进为Triplet loss,只为了一个目的:学习到更好的feature。
直接贴出Triplet loss的损失函数,其输入的不再是Image Pair,而是三张图片(Triplet),分别为Anchor Face, Negative Face和Positive Face。Anchor与Positive Face为同一人,与Negative Face为不同的人。那么Triplet loss的损失函数即可表示为:
该式子的直观解释为:在特征空间里Anchor与Positive的距离要小于Anchor与Negative的距离并超过一个Margin Alpha。他与Contrastive loss的直观区别由下图所示。
1. Metric learning的问题
上述的两个loss function效果很不错,而且也符合人的客观认知,在实际项目中也有大量的应用,但该方法仍有一些不足之处。
· 模型训练依赖大量的数据,拟合过程很慢。由于contrastive loss和triplet loss都是基于pair或者triplet的,需要准备大量的正负样本,,训练很长时间都不可能完全遍历所有可能的样本间组合。网上有博客说10000人、500000张左右的亚洲数据集上花一个月才能完成拟合。
· Sample方式影响模型的训练。比如对于triplet loss来说,在训练过程中要随机的采样anchor face, negative face以及positive face,好的样本采样能够加快训练速度和模型收敛,但是在随机抽取的过程中很难做到非常好。
· 缺少对hard triplets的挖掘,这也是大多数模型训练的问题。比如说在人脸识别领域中,hard negatives表示相似但不同的人,而hard positive表示同一个人但完全不同的姿态、表情等等。而对hard example进行学习和特殊处理对于提高识别模型的精度至关重要。
2. 对于Metric Learning不足进行修正的各种trick
a. Finetune
参考论文:Deep Face Recognition
在论文《Deep Face Recognition》中,为了加快triplet loss的训练,坐着先用softmax训练人脸识别模型,然后移除顶层的classification layer,然后用triplet loss对模型进行特征层finetune,在加速训练的同时也取得了很不错的效果。该方法也是现在训练triplet loss时最常用的方法。
b. 对Triplet loss的修改
参考论文:In Defense of the Triplet Loss for Person Re-Identification
该作者说出了Triplet loss的缺点。对于Triplet loss训练所需要的一个三元组,anchor(a)、positive(p)、negative(n)来说,需要从训练集中随机挑选。由于loss function的驱动,很有可能挑选出来的是很简单的样本组合,即很像的正样本以及很不像的负样本,而让网络一直在简单样本上进行学习,会限制网络的范化能力。因此坐着修改了triplet loss并添加了新的trick,大量实验证明,这种改进版的方法效果非常好。
在Google提供的facenet triplet loss训练时,一旦选定B triplets集合,数据就会按照顺序排好的3个一组,那么总共的组合就有3B种,但是这些3B个图像实际上有多达
种有效的triplets组合,仅仅使用3B种就很浪费。
在该片论文中,作者提出了一个TriHard loss,其核心思想是在triplet loss的基础上加入对hard example的处理:对于每一个训练的batch, 随机挑选P个ID的行人,每个行人随机挑选K张不同的图片,即一个batch含有P×K张图片。之后对于batch中的每一张图片a,我们可以挑选一个最难的正样本和一个最难的负样本和a组成一个三元组。首先我们定义和a为相同ID的图片集为A,剩下不同ID的图片图片集为B,则TriHard损失表示为:
其中
是人为设定的阈值参数。TriHard loss会计算a和batch中的每一张图片在特征空间的欧氏距离,然后选出与a距离最远(最不像)的正样本p和距离最近(最像)的负样本n来计算三元组损失。其中d表示欧式距离。损失函数的另一种写法如下:
另外,作者在轮中也提出了几个实验得到的观点:
Ø 平方后的欧式距离不如开方后的真实欧氏距离(后续会简单提一下原因)
Ø 提出了Soft-Margin损失函数替代原始的Triplet loss表达式,soft-margin能够使得损失函数更加平滑,避免函数收敛在bad local处,能够一定程度上加速算法收敛。
Ø 引进了Batch Hard Sampling
该方法考虑了hard example后效果比传统的triplet loss好。
a. 对loss以及sample方法的修改
参考论文:Deep Metric Learning via Lifted Structured Feature Embedding
该论文首先提出了现有的三元组方法无法充分利用minibatch SGD training的training batches的优势,创造性的将the vector of pairwise distances转换成the matrix of pairwise distance,然后设计了一个新的结构化损失函数,取得了非常好的效果。如下图所示,是contrastice embedding,triplet embedding以及lifted structured embedding三种方式的采样示意图。
直观上看,lifted structured embedding涉及的分类模式更多,作者为了避免大量数据造成的训练困难,作者在此基础上给出了一个结构化的损失函数。如下图所示。
其中P是正样本集合,N是负样本集合。可以看到对比上述的损失函数,该损失函数开始考虑一个样本集合的问题。但是,并不是所有样本对之间的negative edges都携带了有用的信息,也就是说随机采样的样本对之间的negative edges携带了非常有限的信息,因此我们需要设计一种非随机的采样方法。
通过上述的结构化损失函数我们可以看到,在最终计算损失函数时,考虑了最像和最不像的hard pairs(也就是损失函数中max的用处),也就相当于在训练过程中添加了difficult neighbors的信息了训练mini-batch,通过这种方式训练数据能够大概率的搜寻到hard negatives和hard positives的样本,而随着训练的不断进行,对hard样本的训练也将实现最大化类间距离和最小化类内距离的目的。
如上图所示,该文章在进行metric learning的时候并没有随机的选择sample pairs,而是综合了多类样本之间较难区分者进行训练。此外,文中还提到了以为的寻求max的过程或者寻求single hardest negative的过程会导致网络收敛到一个bad local optimum,我猜想可能是因为max的截断效应,使得梯度比较陡峭或者梯度间断点过多。作者进一步改进了loss function,采用了smooth upper bound,即下式所示。
a. 对sample方式和对triplet loss的进一步修改
参考论文:Sampling Matters in Deep Embedding Learning
1) 对采样方式的修改
文章指出hard negative样本由于anchor的距离较小,这是如果有噪声,那么这种采样方式就很容易受到噪声的影响,从而造成训练时的模型坍塌。FaceNet曾经提出一种semi-hard negative mining的方法,它提出的方法是让采样的样本不是太hard。但是根据作者的分析认为,sample应该在样本中进行均匀的采样,因此最佳的采样状态应该是在分散均匀的负样本中,既有hard,又有semi-hard,又有easy的样本,因此作者提出了一种新的采样方法Distance weighted sampling。
在现实状态下,我们队所有的样本进行两两采样,计算其距离,最终得到点对距离的分布有着如下的关系:
那么根据给定的距离,通过上述函数的反函数就可以得到其采样概率,根据该概率决定每个距离需要采样的比例。给定一个anchor,采样负例的概率为下式:
由于训练样本与训练梯度强相关,因此作者也绘制出了采样距离、采样方法与数据梯度方差的关系,如下图所示。从图中可以看出,hard negative mining方法采样的样本都处于高方差的区域,如果数据集中有噪声的话,采样很容易受到噪声的影响,从而导致模型坍塌。随机采样的样本容易集中在低方差的区域,从而使得loss很小,但此时模型实际上并没有训练好。Semi-hard negative mining采样的范围很小,这很可能导致模型在很早的时候就收敛,loss下降很慢,但实际上此时模型也还没训练好;而本文提出的方法,能够实现在整个数据集上均匀采样。
1) 对loss function的修改
作者在观察constractive loss和triplet loss的时候发现一个问题,就是负样本在非常hard的时候loss函数非常的平滑,那么也就意味着梯度会很小,梯度小对于训练来说就意味着非常hard的样本不能充分训练,网络得不到hard样本的有效信息,因此hard样本的效果就会变差。所以如果在hard样本周围loss不是那么平滑,也就是深度学习中经常用的导数为1(像relu一样),那么hard模式会不会就解决了梯度消失的问题。另外loss function还要实现triplet loss对正负样本的兼顾,以及具备margin设计的功能,也就是自适应不同的数据分布。损失函数如下:
我们称anchor样本与正例样本之间的距离为正例对距离;称anchor样本与负例样本之间的距离为负例对距离。公式中的参数beta定义了正例对距离与负例对距离之间的界限,如果正例对距离Dij大于beta,则损失加大;或者负例对距离Dij小于beta,损失加大。A控制样本的分离间隔;当样本为正例对时,yij为1,样本为负例对时,yij为-1。下图为损失函数曲线。
从上图可以看出为什么在非常hard的时候会出现梯度消失的情况,因为离0点近的时候蓝色的线越来越平滑,梯度也就越来越小了。另外作者对
的设置也进行了调优,加入了样本偏置、类别偏置以及超参,对损失函数进一步优化,能够根据训练过程自动修改
的值。
Margin Based Classification
Margin based classification不像在feature层直接计算损失的metric learning那样对feature加直观的强限制,是依然把人脸识别当 classification 任务进行训练,通过对 softmax 公式的改造,间接实现了对 feature 层施加 margin 的限制,使网络最后得到的 feature 更 discriminative。
1. Center loss
参考论文:A Discriminative Feature Learning Approach for Deep Face Recognition
ECCV 2016的这篇文章主要是提出了一个新的Loss:Center Loss,用以辅助Softmax Loss进行人脸的训练,为了让同一个类别压缩在一起,最终获取更加discriminative的features。center loss意思即为:为每一个类别提供一个类别中心,最小化min-batch中每个样本与对应类别中心的距离,这样就可以达到缩小类内距离的目的。下图为最小化样本和类别中心距离的损失函数。
为每个batch中每个样本对应的类别中心,和特征的维度一样,用欧式距离作为高维流形体距离表达。因此,在softmax的基础上,center loss的损失函数为:
个人理解Center loss就如同在损失函数中加入了聚类的功能,随着训练的进行,样本自觉地聚类在每一个batch的中心,进一步实现类间差异最大化。但是我觉得,对于高维特征,欧氏距离并不能反映聚类的距离,因此这样简单的聚类并不能在高维上取得更好的效果。
1. L-Softmax
原始的Softmax的目的是使得
,将向量相乘的方式变换为向量的模与角度的关系,即
,在这个基础上,L-Softmax希望可以通过增加一个正整数变量m,可以看到:
使得产生的决策边界可以更加严格地约束上述不等式,让类内的间距更加的紧凑,让类间的间距更加有区分性。所以基于上式和softmax的公式,可以得到L-softmax的公式为:
由于cos是减函数,所以乘以m会使得内积变小,最终随着训练,类本身之间的距离会增大。通过控制m的大小,可以看到类内和类间距离的变化,二维图显示如下:
作者为了保障在反向传播和推理过程中能够满足类别向量之间的角度都能够满足margin的过程,并保证单调递减,因此构建了一种新的函数形式
:
有人反馈L-Softmax调参难度较大,对m的调参需要反复进行,才能达到更好的效果。
1. Normface
参考论文:NormFace: L2 Hypersphere Embedding for Face Verification
这篇论文是一篇很有意思的文章,文章对于权重与特征归一化做了很多有意思的探讨。文章提出,sphereface虽然好,但是它不优美。在测试阶段,sphereface通过特征间的余弦值来衡量相似性,即以角度为相似性度量。但在训练过程中也有一个问题,权重没有归一化,loss function在训练过程中减小的同时,会使得权重的模越来越大,所以sphereface损失函数的优化方向并不是很严谨,其实优化的方向还有一部分去增大特征的长度了。有博主做实验发现,随着m的增大,坐标的尺度也在不断增大,如下图所示。
因此作者在优化的过程中,对特征做了归一化处理。相应的损失函数也如下所示:
其中W和f都为归一化的特征,两个点积就是角度余弦值。参数s的引入是因为数学上的性质,保证了梯度大小的合理性,原文中有比较直观的解释,可以阅读原论文,并不是重点。s既可以变成可学习的参数,也可以变成超参,论文作者给了很多推荐值,可以在论文中找到。其实,FaceNet中归一化的欧氏距离,和余弦距离是统一的。
1. AM-softmax/CosFace
参考论文:Additive Margin Softmax for Face Verification
CosFace: Large Margin Cosine Loss for Deep Face Recognition
看上面的论文,会发现少了一个东西,那就是margin,或者说是margin的意味少了一些,所以AM-softmax在归一化的基础上有引入了margin。损失函数如下:
直观上来看,
-m比
更小,所以损失函数值比Normface里的更大,因此有了margin的感觉。m是一个超参数,控制惩罚,当m越大,惩罚越强。该方法好的一点是容易复现,而且没有很多调参的tricks,效果也很好。
1. ArcFace
与 AM-softmax 相比,区别在于 Arcface 引入 margin 的方式不同,损失函数:
乍一看是不是和 AM-softmax一样?注意 m 是在余弦里面。文章指出基于上式优化得到的特征间的 boundary 更为优越,具有更强的几何解释。
然而这样引入 margin 是否会有问题?仔细想 cos(θ+m) 是否一定比 cos(θ) 小?
最后我们用文章中的图来解释这个问题,并且也由此做一个本章 Margin-based Classification 部分的总结。
这幅图出自于 Arcface,横坐标为 θ 为特征与类中心的角度,纵坐标为损失函数分子指数部分的值(不考虑 s),其值越小损失函数越大。
看了这么多基于分类的人脸识别论文,相信你也有种感觉,大家似乎都在损失函数上做文章,或者更具体一点,大家都是在讨论如何设计上图的 Target logit-θ 曲线。
这个曲线意味着你要如何优化偏离目标的样本,或者说,根据偏离目标的程度,要给予多大的惩罚。两点总结:
1. 太强的约束不容易泛化。例如 Sphereface 的损失函数在 m=3 或 4 的时候能满足类内最大距离小于类间最小距离的要求。此时损失函数值很大,即 target logits 很小。但并不意味着能泛化到训练集以外的样本。施加太强的约束反而会降低模型性能,且训练不易收敛。
2. 选择优化什么样的样本很重要。Arcface 文章中指出,给予 θ∈[60° , 90°] 的样本过多惩罚可能会导致训练不收敛。优化 θ ∈ [30° , 60°] 的样本可能会提高模型准确率,而过分优化 θ∈[0° , 30°] 的样本则不会带来明显提升。至于更大角度的样本,偏离目标太远,强行优化很有可能会降低模型性能。
这也回答了上一节留下的疑问,上图曲线 Arcface 后面是上升的,这无关紧要甚至还有好处。因为优化大角度的 hard sample 可能没有好处。这和 FaceNet 中对于样本选择的 semi-hard 策略是一个道理。
Margin based classification 延伸阅读
1. A discriminative feature learning approach for deep face recognition [14]
提出了 center loss,加权整合进原始的 softmax loss。通过维护一个欧式空间类中心,缩小类内距离,增强特征的 discriminative power。
2. Large-margin softmax loss for convolutional neural networks [10]
Sphereface 作者的前一篇文章,未归一化权重,在 softmax loss 中引入了 margin。里面也涉及到 Sphereface 的训练细节。
点击这里,了解更多精彩内容
-
-
只用十行 Python 代码就提取了韦小宝的身份证信息
2020-12-17 14:41:43本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 记得以前有个广告词叫:“学好数理化,走遍天下都不怕”,感觉应该再加一句:“带上身份证”,本文我们看一下...本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理
记得以前有个广告词叫:“学好数理化,走遍天下都不怕”,感觉应该再加一句:“带上身份证”,本文我们看一下如何使用 Python 提取身份证信息。
实现方式
实现方式大致可以分为两种:
-
自己造轮子,如:使用 OpenCV 等自己编码实现,该方式所有功能都需自己来实现,比较耗时耗力,优点是更灵活一些
-
使用现成的轮子,如:百度云,平台已经实现好了核心功能,并对外提供了 API 接口,我们直接调用接口即可,该方式省时省力,但灵活性可能差一些
实现过程
因为我们要实现的功能也比较简单,这里就用第二种方式来演示一下,下面简单看一下实现过程。
SDK 安装
百度云 SDK 对多种语言提供了支持,这里我们安装 Python 版的 SDK,使用
pip install baidu-aip
命令即可,SDK 目录结构如下:├── README.md ├── aip // SDK 目录 │ ├── __init__.py // 导出类 │ ├── base.py // aip 基类 │ ├── http.py // http 请求 │ └── ocr.py //OCR └── setup.py // setuptools 安装
创建应用
SDK 安装好后,我们接着需要创建应用了,这里需要一个百度账号或百度云账号,如果没有的话自己注册一个即可,登录及注册地址为:
https://login.bce.baidu.com/?redirect=http%3A%2F%2Fcloud.baidu.com%2Fcampaign%2Fcampus-2018%2Findex.html
.我们先找一张身份证图片,如图所示:
接着看一下代码实现,首先创建 AipOcr,AipOcr 是 OCR 的 Python SDK 客户端,代码实现如下:
# 自己的 APPID AK SK APP_ID = '自己的 App ID' API_KEY = '自己的 Api Key' SECRET_KEY = '自己的 Secret Key' client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
信息的提取有普通和高精度两种模式,普通模式代码实现如下:
# 打开并读取文件内容 fp = open("card.jpg", "rb").read() res = client.basicGeneral(fp) # 普通 # 遍历结果 for tex in res["words_result"]: row = tex["words"] print(row)
输出结果如下:
姓名韦小宝 性别男民族汉 出生1654年12月20日 住址北京市东城区景山前街4号 紫禁城敬事房 公民身份证号码112441654122日2438
再来试一下高精度模式,代码实现如下:
# 打开并读取文件内容 fp = open("card.jpg", "rb").read() res = client.basicAccurate(fp) # 高精度 # 遍历结果 for tex in res["words_result"]: row = tex["words"] print(row)
输出结果如下:
姓名韦小宝 性别男民族汉 出生1654年12月20日 住址北京市东城区景山前街4号 紫禁城敬事房 公民身份证号码11204416541220243X
通过输入结果我们可以看到:高精度模式提取了正确的身份证号码,普通模式提取的身份证号码是有一些误差的。
总结
本文我们使用 Python 结合百度云接口几行代码就提取了身份证信息,其实除了身份证信息也可以提取其他卡片信息,比如银行卡信息等,有兴趣的可以试一下。
示例代码: py-discern
想要获取更多Python学习资料可以加
QQ:2955637827私聊
或加Q群630390733
大家一起来学习讨论吧! -
-
使用 Github 空间搭建 Hexo 技术博客——分享使用HexoEditor写博客(十五)
2019-03-11 22:21:26如果说hexo-myadmin是简约之美,HexoEditor就是很...比如一键上传博客图片,让我省的打开腾讯云客户端手动上传和建立文件夹了。现在我要记录以下日常使用中一些经常用到的操作。 1.介绍 HexoEditor是 Github 上一... -
外贸怎么打造自己的品牌,搭建自己的独立站?B2B转B2C未来怎么样呢?
2020-07-20 18:27:38一、网站建立 1>购买域名。这个没啥好说的,就是网址。...费用是几十块钱,阿里云就可以注册。...这个叫法有很多种,又叫服务器、云服务器、虚拟主机、VPS主机、云...例如网站的源文件、网站的数据库、网站里面上传的图片 -
微信的迭代之路
2021-04-11 08:16:10我们回顾一下微信的发展之路,十年的时间,它从一个IM工具蜕变为一种生活方式。它没有创造内容,但是为所有的创作者提供了平台。它变成了一种基础设施,就像一个操作系统。 从IM工具 摇一摇 漂流瓶 附近的人 可能的... -
智能录音笔的工作原理
2020-08-25 15:03:55广告内容神乎其神,AI录音笔可以将语言直接转化成文字,能识别10种语言加上十种方言!不了解的人大概以为是什么骗子广告吧。 人工智能的发展下,总是能与我们的生活完美结合衍生出这样那样的黑科技产品没有做不到... -
iRASPA-COCOA:适用于macOS的iRASPA-源码
2021-03-30 23:15:05伊拉帕可可 iRASPA是针对材料科学的可视化程序包(具有编辑功能)。 材料的示例是金属,金属氧化物,陶瓷,生物材料,... 制作高质量的图片和电影, 环境光遮挡和高动态范围渲染, 结构的拼贴, (透明)吸附面, -
阿里视觉AI训练营-day05-创意日-你的图像识别项目
2020-11-03 22:01:47图像识别技术是基于阿里云深度学习技术,可实现精准识别图像中的视觉内容,包括上千种物体标签、数十种常见场景等,为您提供图像打标、场景分类、颜色识别、风格识别以及元素识别等能力。图像识别技术可广泛应用于... -
-
-
-
-
-
-
-
python文字识别前端_Python文字识别OCR案例:百度AI实现OCR识别(源代码)
2020-12-15 20:53:55最近研究OCR技术实现较多,各种OCR实现方式做...从根本上来说,OCR的技术实现有两种方式:第一种较为简单,就是调用各个云平台提供的OCR服务来识别图片上的文字。这种实现方式的优点是简单易用,识别率较高,灵活性... -
星空便签 v1.0.4.zip
2019-07-14 11:50:39六、粘贴图片与超链接:可以粘贴截图,PNG、JPG、BMP 类型的图片文件;能够粘贴超链接。 七、全局坐标系:背景白板可以拖拽移动,通过全局坐标获得更灵活的操作方式。 八、绿色、无依赖:星空云便签可以在新装的... -
oauth2.0 学习案例demo_Python文字识别OCR案例:百度AI实现OCR识别(源代码) !
2020-11-27 02:08:16最近研究OCR技术实现较多,各种OCR实现方式做...从根本上来说,OCR的技术实现有两种方式:第一种较为简单,就是调用各个云平台提供的OCR服务来识别图片上的文字。这种实现方式的优点是简单易用,识别率较高,灵活性... -
java+mysql实现的代码分享网(所有源码已开源,效果可看网址:www.admintwo.com)
2017-05-31 15:03:1911、其他功能包括:图片压缩处理功能(即使是几M的图片,压缩后也只有几十kb)。通用json处理功能(向方法中传递任何参数,int、string等,都会返回json数据,而且速度很快)。分词功能(点击某一个分享,进入详情页... -
文档管理系统|多可网站媒体管理系统 v3.6.5.0.zip
2019-07-13 03:41:53多可网站媒体管理系统众多大型企业和设计类企事业单位的各类文档数量越来越多,需要的存储容量达到数十TB。多可网站媒体管理系统,借助创新的云技术,多可文档管理系统实现了文档存储云部署功能,它可以把海量的... -
DotNetNuke新闻模块免费版
2013-09-22 19:38:57七、对于从网络复制的内容可以自动下载图片存储到本地,并产生缩略图,如果删除有图片的文档,包含的图片可以自动删除,不会产生垃圾文件。 八、提供了回收站功能,删除的分类和文档将首先入回收站,以便日后... -
poco相机 android v1.5.0
2012-03-26 15:21:287、网络备份云相册:内置网络备份功能,可将图片直接导入POCO图片社区提供的免费网络云相册,空间大小不受限制,与爱生活、爱摄影的人群在POCO.CN上分享创作灵感、学习拍摄技巧、探讨摄影后期; 我们会不断优化... -
CAXA CAD电子图板 CAXA CAD 2020 SP0 v20.0.0.6460 中文多语版.zip
2021-03-09 09:00:52提供符合最新国标的参数化图库,包含50多个大类,4600余种,几十万规格的标准图符,并提供完全开放式的图库管理和定制手段;针对机械设计中频繁出现的构件图形提供完整的构件库。 开放而快捷的图幅功能 提供开放的... -
优淘开源淘客程序 v5.7
2019-10-22 19:52:54自动生成标签 2、自带积分兑换模块 3、自带免费的wap模板,手机与PC 访客自动识别展示不同的模板 4、自带一键报名功能 5、自带百川短信发送,邮件发送功能 6、自带伪静态缓存 7、集成QQ,微博,微信,淘宝四种第三... -
✅ 21云盒子:最容易使用的云 - 自动化你的工作流程。代码构建,静态网页,Web应用发布,云数据库托管,SSL证书生成和维护,极速CDN,私有网络的一站式服务平台 ✅ BlinkMath:iOS app,累了眨眨眼,动动脑! 2020...
-
wordpress人文古风主题 v2.5.zip
2019-07-07 02:09:01一十三:视频、图片、框架都支持自适应,但必须按照模板使用文档的css格式来写,不然无效,具体看模板使用文档。 一十四:分享、版权信息、二维码地址都集成在模板中了,你无需安装插件,更省心。 一十五:自定义... -