任务说明
将银行卡卡号打印输出
; 实现
一、思路
1、定位银行卡卡号数字区域
2、将银行卡每个卡号数字单独提取出来
3、处理模板图片,将每个模板数字单独提取出来
4、通过模板匹配来识别每个卡号
二、具体代码实现
1、处理模板
卡号数字模板
img_m = cv2.imread("ocr_a_reference.png",1)
img_m_g = cv2.cvtColor(img_m,cv2.COLOR_BGR2GRAY)
img_m_g = cv2.threshold(img_m_g,0,255,cv2.THRESH_OTSU|cv2.THRESH_BINARY_INV)[1]
img_m_g_con = cv2.findContours(img_m_g,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)[0]
img_m_g_dst = cv2.drawContours(img_m.copy(),img_m_g_con,-1,(0,0,255),2)
imshow(img_m_g_dst)
将每个模板数字分割开,并保存到字典中
l1 = []
for con in img_m_g_con:
(x,y,w,h) = cv2.boundingRect(con)
l1.append(x)
(img_m_g_con,l1) = zip(*sorted(zip(img_m_g_con,l1),key=lambda x :x[1],reverse=False))
digits = {}
for i,con in enumerate(img_m_g_con):
(x,y,w,h) = cv2.boundingRect(con)
roi = img_m_g[y:y+h,x:x+w]
digits[i] = cv2.resize(roi,(57,88))
2、处理银行卡图片
img_card = cv2.imread("credit_card_01.png",1)
img_card_gray = cv2.cvtColor(img_card,cv2.COLOR_BGR2GRAY)
kernel = np.ones((5,5))
tophat = cv2.morphologyEx(img_card_gray,cv2.MORPH_TOPHAT,kernel)
imshow(tophat)
求图像的梯度(边缘)的目的是方便之后的形态学操作,将目标区域连通在一起。
grady = cv2.Sobel(tophat,ddepth = cv2.CV_32F,dx=0,dy=1,ksize = 3)
grady = cv2.convertScaleAbs(grady)
gradx = cv2.Sobel(tophat,ddepth = cv2.CV_32F,dx=1,dy=0,ksize=3)
gradx = cv2.convertScaleAbs(gradx)
grad = cv2.addWeighted(gradx,0.5,grady,0.5,0)
imshow(grad)
形态学操作,将目标区域连通在一起
kernel = np.ones((3,3))
grad_close = cv2.morphologyEx(grad,cv2.MORPH_CLOSE,kernel,iterations = 1)
imshow(grad_close)
grad_dst = cv2.threshold(grad_close,0,255,cv2.THRESH_OTSU)[1]
grad_close = cv2.morphologyEx(grad_dst,cv2.MORPH_CLOSE,kernel,iterations=8)
imshow(grad_close)
闭操作执行的次数和银行卡的格式是严格相关的,不同格式的银行卡要设置不用的参数,参数值通过实验经验获得。
其主要目的是将目标区域联通在一起,并且要求连通后的区域不可以包含额外区域,比如参数设置过大会导致左侧目标区域与下方区域连通,设置过小会导致目标区域无法连通。
gradcon = cv2.findContours(grad_close,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)[0]
dst = cv2.drawContours(img_card.copy(),gradcon,-1,(0,0,255),2)
imshow(dst)
losc = []
for con in gradcon:
(x,y,w,h) = cv2.boundingRect(con)
ar = w/h
if ar >2.4 and ar <3.5:
if w>155 or w<85:
continue
losc.append((x,y,w,h))
sort_losc = sorted(losc,key = lambda x :x[0],reverse=False)
img_part = []
for i in sort_losc:
x,y,w,h = i[0],i[1],i[2],i[3]
con = np.array([[[x,y],[x+w,y],[x+w,y+h],[x,y+h]]])
img_part.append(img_card[y:y+h,x:x+w])
imshow(img_card[y:y+h,x:x+w])
再对每个小区域处理,获取每个卡号数字区域
digital = []
def f(img):
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_2 = cv2.threshold(img_gray,0,255,cv2.THRESH_OTSU)[1]
imgcon = cv2.findContours(img_2,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)[0]
new_con = []
for con in imgcon:
(x,y,w,h) = cv2.boundingRect(con)
if h>35 or w<15:
continue
new_con.append((x,y,w,h))
sort_con = sorted(new_con,key = lambda x:x[0])
for i in sort_con:
x,y,w,h = i[0],i[1],i[2],i[3]
con = np.array([[[x,y],[x+w,y],[x+w,y+h],[x,y+h]]])
roi = img_2[y-1:y+h+1,x-1:x+w+1]
digital.append(cv2.resize(roi,(57,88)))
for i in img_part:
f(i)
...
3、模板匹配
ans = []
for img_dig in digital:
now = []
for (dig,digroi) in digits.items():
res = cv2.matchTemplate(img_dig,digroi,cv2.TM_CCOEFF_NORMED)
now.append(res.item())
ans.append(now.index(max(now)))
now.clear()
print(ans)
cv2.matchTemplate是用于模板匹配的函数,第一个参数为待匹配图像,第二个参数为模板图像,模板图像和原图像的大小要保持一致,第三个参数为匹配方式。返回值越大,相似度越高。
存在的问题:
1、不同格式的银行卡图片需要对参数进行幅度较大的改动。
2、没有考虑银行卡图片倾斜的情况,如果输入的银行卡图片在输入的图片中只是倾斜的,可以使用透视变换进行校正,具体做法可以参考上一篇blog(答题卡识别)
Original: https://blog.csdn.net/qq_44805233/article/details/123192913
Author: 棒子胡豆
Title: opencv项目实践二(银行卡卡号识别)
相关阅读1
Title: 语音合成数据解决方案助您获取专属AI声音
在2020年小米开发者大会(MIDC)上,小米宣布小爱同学5.0正式上线。小爱同学在声音体验上做了很多创新,如奶萌泡芙童声、多情感语音、粤语合成、定制声音等。
在语音合成技术的支持下,小爱同学做了很多创新
小爱同学声音体验升级的背后,其实正是小米自研语音合成技术的迭代创新。
01
什么是语音合成?
语音合成(Text to Speech),简称TTS,是将人类语音用人工方式产生、将任意文字信息实时转化为标准流畅的语音朗读出来的技术。
TTS涉及声学、语言学、数字信号处理、计算机科学等多个学科技术,是信息处理领域的一项前沿技术,解决的主要问题就是如何将文字信息转化为可听的声音信息,即让机器像人一样开口说话。
语音合成是最近几年很火的一个词,知名AI企业如科大讯飞、思必驰、谷歌、华为等纷纷发力语音合成领域,研发的语音助手、智能音箱、语音翻译等应用渗入到生活的各种方面。
语音合成是信息处理的一项前沿技术
虽然TTS已经取得了可观的成就,但是仍存在很大的进步空间。
目前TTS的自然度和可懂度基本可以满足,但是到句子和篇章一级时,自然度还是一个较大的问题。其次,人类语音有不同的情感、语气语速和说话方式,丰富性是语音合成需要进一步努力的方向。
数据堂作为专业的人工智能数据服务提供商,致力于攻克技术瓶颈、推动TTS更广泛的落地应用。针对上述情况,数据堂推出了语音合成数据解决方案。
基于海量语音文本数据标注经验与领先的人工智能语音合成技术,针对客户提出的不同场景、音色、音质、类型等需求,数据堂支持快速合成定制化声音效果,让机器像人类一样能说会道。
02
数据堂的服务能力
数据堂具有丰富的数据资源、突出的技术优势和丰富的数据处理经验,支持按场景、语种、年龄、性别、发音人定制采集语音数据。
01
安全合规
为保障公司为客户提供安全合规的数据服务,同时保障数据堂自身的安全合规,数据堂根据世界范围内主要国家有关数据的法律政策,制定了本公司数据业务的安全合规体系。
数据堂规定数据采集必须以被采集人本人签署的授权书为准,取得数据采集的授权。
02
专业环境
数据堂拥有专业语音级录音棚,专业级人声电容麦克风和监听设备。数据堂录音棚符合NR15声学标准:混响时间小于0.1秒,背景噪声小于20dB,并获得了清华大学建筑物理实验室认证。
数据堂拥有专业录音设备
03
资源丰富
数据堂拥有全球上千名专业发音人资源和上百人专业团队。
数据堂支持中文普通话、英语等多种语言,支持主要方言区、中英混读等语音合成。同时,数据堂拥有男声、女声、童声等多种音色,每种音色均有不同类型发音人,全面满足多样化语音合成需求。
04
质量保障
在录制过程中,数据堂配置了专业监听确保录音质量。通过请教专家、调研论文,参考各种词典、谷歌翻译和百度翻译上的单词发音,数据堂整理出了一套完整的发音规则,制作了发音词典。
03
数据堂TTS数据解决方案应用场景
数据堂TTS数据解决方案支持大部分应用场景,如客服、有声读物、语音交互、歌声合成等。
· 智能客服
目前智能客服在业界已经能够提供整套的本地化服务,且能满足用户的许多客制化需求。
智能客服是语音合成的重要应用之一
数据堂拥有丰富的语音合成音库,能够模拟发音人真实工作状态,助力打造对话式客服,以便促进客户体验的提升,实现营销效果的转化。
· 有声读物
现代社会人们拥有的完整的阅读时间越来越少,识别文字并精准转化为语音并用最接近人声的效果朗读出来成了书友们最迫切的需求。
数据堂TTS数据解决方案支持新闻、书籍等读物场景
数据堂的语音合成数据解决方案支持小说、新闻、书籍等读物场景,提供媲美人声的听觉体验,帮助人们解放双眼,保障内容的流畅清晰,能够有效降低有声内容创作门槛。
· 车载场景
语音导航、语音控制、车载信息娱乐系统等车载交互系统,解放车主双手的同时,也为车主带来了便捷出行与娱乐享受的驾驶体验。
语音合成技术在车载场景得到了广泛的应用
把文字转语音应用于车载场景,可快速实现低成本为车主及乘客提供更多资讯的服务,提升用户在驾驶过程中的体验感,安全驾驶的同时还可以增加更多乐趣。
· 音乐合成
音乐合成系统从数据中学习,提供对音色和音乐力度变化的直观控制,可以创造出人工方法不可能实现的音乐。
数据堂以TTS标准录制音乐,包含乐谱制作、音字标注、音准校对等,二次元音色都可驾驭。
目前的语音合成技术已经应用于各种场景,满足了市场上绝大部分需求,是较成熟可落地的产品。当前主要的问题在于不同场景的具体需求,例如不同的数字读法,如何智能的判断当前场景应该是哪种播报方式,以及什么样的语气和情绪更适合当下的场景等。
数据堂深耕人工智能数据服务领域多年,时刻保持创新意识,积极探索新领域和新应用,不断完善自身TTS数据解决方案,致力于将更多研究成果转化为实际应用。
Original: https://blog.csdn.net/weixin_44532659/article/details/122620574
Author: 数据堂官方账号
Title: 语音合成数据解决方案助您获取专属AI声音
相关阅读2
Title: 2021/12/28组会
2012/12/28(第4章 类)
1 用var声明局部变量
p109
在java10中可以利用var 来声明变量类型 ide会自动推导类型 (类似c++中的auto类型)
例如
Employee harry = new Employee("Harry Hacker");
利用var
var harry = new Employee("Harry Hacker");
2 null值的应用
p109
对一个被复制为null的变量调用方法会引起NullPointException异常
LocalDate birthday = null;
String s = birthday.toString();
这个错误类似数组越界,是很严重的错误,对于这个错误有两种解决方法,"宽容型"和"严格型"
2.1 宽容型:
发现变量是null值时,使其变成一个其他的值,在java9中提供了一个方法
public Employee(String n, double s, int year, int month, int day)
{
name = Objects.requireNonNullElse(n,"unknow");//如果name值为null,则改为unknown
...
}
2.2 严格型:
发现变量是null值时,直接报错,在java9中提供了一个方法
public Employee(String n, double s, int year, int month, int day)
{
Objects.requireNonNull(n,"name can't be null");
name = n;
...
}
这个方法看起来没啥用,因为还是会出NullPointException的报错,但是这个报错会提供这个问题的描述和问题所处位置
3 隐式参数和显式参数
p110
举例对于一个对象的方法调用
employee007.raiseSalary(5);
前面的对象emploee007就是隐式参数(也称为方法的调用者),后面括号中的数值就是现式参数
4 封装的优点
p111
1,封装实现了getter和setter方法,防止类内的变量被随意修改,同时也可以设置getter和setter的权限等级来实现分级访问或者修改
2,同时,对于封装好的方法,如果在类内的某些参数发生了改变,我们只需要调整getter或setter函数便可保证整个代码继续可用,而不需要去找到每个可能使得代码异常的地方,如下
class Employee
{
private string name;
public string getName()
{
return name;
}
}
如果将name改成firstname和lastname的组合,也只需要更改getter方法,外界对方法怎么实现并不在意
class Employee
{
private string firstName;
private string lastName;
public string getName()
{
return firstName + " " + lastName;
}
}
3,同时,getter和setter也可用于错误检查,例如setSalary可检查在设置薪资时是否为小于0的异常值
public void setSalary(int s)
{
if(s
警告 不要写返回可变对象引用的getter(返回 可变对象引用 的getter) 如下
class Employee
{
private Date hireDay;
...
public Date getHireDay()
{
return hireDay;
}
...
}
public static void main(string[] arg)
{
Employee harry = ...;
Date d = harry.getHireDay();
double tenYearInMilliSeconds = 10*365.25*24*60*60*1000;
d.setTime(d.getTime() - (long) tenYearsInMilliseconds);
//let's get Harry ten years of added seniority
}
在上面的代码中并没有写Employee中hireday的setter,但是由于返回了类内的hireday的引用,可以声明一个Date d来接受这个引用,再利用Date中的setter更改这个引用指向的值,这就破坏了封装的意义也破坏了hireday的private权限
如果需要返回可变对象引用,应当使用克隆后的副本返回,防止上述问题发生
class Employee
{
private Date hireDay;
...
public Date getHireDay()
{
return (Date) hireDay.clone();
}
...
}
Original: https://www.cnblogs.com/luoyoucode/p/15709263.html
Author: 落悠
Title: 2021/12/28组会
相关阅读3
Title: 2个函数宏技巧
1.用宏调用对象函数
#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
do{ \
CObserverListBase<ObserverType>::Iterator it(observer_list); \
ObserverType* obs; \
while((obs=it.GetNext()) != NULL) \
obs->func; \
} while(0)
调用方式
// void NotifyBar(int x, int y) {
// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
// }
2.用宏定义函数指针来转发
定义:
class TestDelegate
{
public:
void Test(int i)
{
i=1;
}
void Test2(int i,int j)
{
i=1;
}
void (Test22)(int i,int j)
{
//((this)->*(&TestDelegate::Test))(i);
}
};
#define __IMPLEMENT_COMSINK_FUNCTION(func, params, values) \
typedef void (T::*F##func)params;\
void Hook_##func(F##func pf##func) \
{ \
m_pf##func = pf##func; \
} \
void (func)params \
{ \
((m_pT)->*(m_pf##func))values; \
} \
private:\
F##func m_pf##func;
template<typename T>
class DelegateHandler
{
public:
DelegateHandler(T* pT,void (T::*pFunc)(int))
:m_pT(pT),m_pFunc(pFunc)
{
}
__IMPLEMENT_COMSINK_FUNCTION(OnEvent,(int a,int b),(a,b))
private:
T* m_pT;
void (T::*m_pFunc)(int);
};
TestDelegate td;
DelegateHandler dh(&td,&TestDelegate::Test);
dh.Hook_OnEvent(&TestDelegate::Test2);
dh.OnEvent(4,3);
Original: https://www.cnblogs.com/Clingingboy/p/3435435.html
Author: Clingingboy
Title: 2个函数宏技巧

Visual studio 2019使用Microsoft Speech SDK 5.1语音识别

win11+RTX3060搭建tensorflow深度学习环境

《30天吃掉那只 TensorFlow2.0》 开篇辞(Tensorflow 学习之路)

【笔记】并行与分布式-进程组织与交互

计算机视觉(相机标定;内参;外参;畸变系数)

《商业模式新生代》笔记

Docker部署onnxruntime-gpu环境

【Tensorflow】Failed to load the native TensorFlow runtime及exit code -1073741819 (0xC0000005)问题解决
![[人脸算法]技术方向综述](https://www.itcode1024.com/wp-content/themes/begin/prune.php?src=https://www.itcode1024.com/wp-content/themes/begin/img/loading.png&w=280&h=210&a=&zc=1)
[人脸算法]技术方向综述

Yolov5 安装详细教程及目标检测和识别

LiJian-kaldi搭建在线语音识别系统 资料汇总

python+tensorflow2.0实现简单人脸识别—–第一天:训练集的采集

Windows 实时语音转文字|免费语音视频翻译转文字|语音会议记录方案

文字识别成语音_百度Ai语音识别文字转语音
