{
private $appid
private $appKey
private $secretKey
public function __construct(){
$this->appid= config('api.baidu.appid')
$this->appKey = config('api.baidu.apikey')
$this->secretKey = config('api.baidu.secretkey')
}
//百度ai接口--文字识别--车牌号识别
public function getCarNumber($_imgurl,$_img=''){
$_token = $this->getToken()
$_url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate?access_token='.$_token
if($_img){
$_data = [
'image'=>$_img//图像数据,base64编码后进行urlencode,要求base64编码和urlencode后大小不超过4M,最短边至少15px,最长边最大4096px,支持jpg/jpeg/png/bmp格式
]
}else{
$_data = [
'url'=>request()->domain().'/'.$_imgurl
]
}
$_res = json_decode(httpGet($_url,$_data),true)
//TODO 此处只返回false没有终止,是因为程序执行流程需要,后期可能要改
if(isset($_res['error_msg'])) return false
return $_res['words_result']['number']
}
//获取token
private function getToken(){
if(cache('baidu_token')){
$_access_token = cache('baidu_token')
}else{
$_url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id='.$this->appKey.'&client_secret='.$this->secretKey
$res = json_decode(httpGet($_url),true)
if(isset($res['error']))TApiException($res['error_description'])//终止程序并抛出异常
$_access_token = $res['access_token']
$_expires_in = $res['expires_in']
cache('baidu_token',$_access_token,($_expires_in-1000))//我喜欢少存1000秒,没有为什么,问就是癖好
}
return $_access_token
}
}
这是ThinkPhp5.1后端封装的百度AI接口类,getToken()获取凭证,getCarNumber()请求$_url 返回识别结果,这个是车牌号码识别,车型识别等其他接口大部分都一样,就换个请求地址$_url就行
//接口:
public function getImgCarNum(){
$_number = (new BaiDuAiBaseController())->getCarNumber(false,request()->param('img'))
return self::myShow('申请成功',['carNum'=>$_number])
}
小程序端正常request请求上面的接口就行,下面是微信小程序拍照识别功能
//拍照
goImgSearch(){
uni.chooseImage({
count:1,
sizeType: ['compressed'],//original 原图,compressed 压缩图
sourceType: ['album','camera'],//camera 相机 album相册
success:(r)=>{
console.log(r)
//执行识别车牌号码
this.img = r.tempFilePaths[0]
this.urlTobase64(r.tempFilePaths[0])
}
})
},
//识别车牌号码
urlTobase64(url){
uni.showLoading({
title:'拼命识别车牌中..'
})
//#ifdef MP-WEIXIN
uni.getFileSystemManager().readFile({
filePath: url, //选择图片时返回的路径
encoding: "base64",//这个是很重要的
success: res =>{ //成功的回调
//返回base64格式
let base64 = 'data:image/jpegbase64,' + res.data
//发送请求,识别车牌号码
this.$H.post('/getImgCarNum',{
img:base64 //图片数据
},{
token:true //必须登录
}).then((res)=>{
console.log(res.carNum)
if(!res.carNum){
uni.hideLoading()
return uni.showModal({
title:'识别失败',
content:'没能识别到车牌号码,请拍张清晰的图片再试哦,谢谢',
showCancel:false
})
}
uni.showToast({
title:'识别车牌成功',
icon:'none'
})
this.searchUser = res.carNum
this.userCarNum = res.carNum
uni.hideLoading()
}).catch((e)=>{
uni.hideLoading()
return uni.showModal({
title:'识别失败',
content:'没能识别到车牌号码,请拍张清晰的图片再试哦,谢谢',
showCancel:false
})
})
},
fail:(e)=>{
console.log(e)
}
})
//#endif
},
虽然我未必能帮助你解决这个问题,但是还是想说几句来帮助你。(1)车牌照识别是属于图像处理里面的内容,MATLAB里面有图像处理工具箱可以帮助你,但是不能帮你彻底解决问题。
(2)能否无错识别肯定和图片的清晰度有关,没有任何一个软件或者代码可以保证完全识别出来,当然,在仅仅考虑图片清晰的前提下(即肉眼可以很轻松识别),还是可以保证比较高的识别率。
(3)这个问题涉及到图片的方位判断,边界提取,字符匹配 等算法,本质上不是一个代码问题,而是一个算法问题。也不局限于MATLAB来解决,GIS,C++,等软件都可以用来做。但是算法才是关键。
(4)给你一些参考文献,希望能对你有启发。
[1] 刘峡壁,贾云得. 一种字符图像线段提取及细化算法[J]. 中国图象图形学报. 2005(01): 48-53.
[2] 李文举,梁德群,崔连延,等. 一种新的面向字符分割的车牌图像预处理方法[J]. 计算机应用研究. 2004(07): 258-260.
[3] 曹建海,路长厚. 基于小波变换和DCT的字符图像特征抽取新方法[J]. 光电子•激光. 2004(04): 477-482.
[4] 付仲良,陈江平,黄书强,等. 货车图像车牌区快速定位及字符切割算法[J]. 计算机工程与设计. 2003(01): 77-79.
[5] 王建平,盛军,朱程辉. 基于小波分析的视频图像字符特征提取方法研究[J]. 微电子学与计算机. 2002(05): 51-53.
[6] 吴大勇,魏平,侯朝桢,等. 一种车牌图像中的字符快速分割与识别方法[J]. 计算机工程与应用. 2002(03): 232-233.
[7] 陈锻生,谢志鹏,刘政凯. 复杂背景下彩色图像车牌提取与字符分割技术[J]. 小型微型计算机系统. 2002(09): 1144-1148.
[8] 顾晖,程晨,梁惺彦. 利用模糊边界提取算法实现医学图像边界提取[J]. 现代计算机(专业版). 2008(01): 38-40.
[9] 罗诗途,王艳玲,罗飞路,等. 基于分形几何边界提取的图像跟踪方法[J]. 应用光学. 2006(01): 19-22.
[10] 王少霞,颜钢峰. 基于张弛法的图像边界提取算法[J]. 江南大学学报. 2005(05): 53-55.
[11] 王艳玲,张玘,罗诗途. 基于分形几何边界提取的图像跟踪方法[J]. 光电子技术与信息. 2005(06): 49-52.
[12] 付青青,冯桂. 噪声图像中边界提取方法的研究[J]. 电脑与信息技术. 2003(01): 22-25.
[13] 王晖,张基宏. 多尺度图像边界提取的小波算法与最优准则[J]. 深圳大学学报. 1997(Z1): 21-25.
#pragma hdrstop#include <stdio.h>
#include <iostream.h>
const A=30.0
const B=10.0
const MAX=500 //最大训练次数
const COEF=0.0035 //网络的学习效率
const BCOEF=0.001//网络的阀值调整效率
const ERROR=0.002 // 网络训练中的允许误差
const ACCURACY=0.0005//网络要求精度
double sample[41][4]={{0,0,0,0},{5,1,4,19.020},{5,3,3,14.150},
{5,5,2,14.360},{5,3,3,14.150},{5,3,2,15.390},
{5,3,2,15.390},{5,5,1,19.680},{5,1,2,21.060},
{5,3,3,14.150},{5,5,4,12.680},{5,5,2,14.360},
{5,1,3,19.610},{5,3,4,13.650},{5,5,5,12.430},
{5,1,4,19.020},{5,1,4,19.020},{5,3,5,13.390},
{5,5,4,12.680},{5,1,3,19.610},{5,3,2,15.390},
{1,3,1,11.110},{1,5,2,6.521},{1,1,3,10.190},
{1,3,4,6.043},{1,5,5,5.242},{1,5,3,5.724},
{1,1,4,9.766},{1,3,5,5.870},{1,5,4,5.406},
{1,1,3,10.190},{1,1,5,9.545},{1,3,4,6.043},
{1,5,3,5.724},{1,1,2,11.250},{1,3,1,11.110},
{1,3,3,6.380},{1,5,2,6.521},{1,1,1,16.000},
{1,3,2,7.219},{1,5,3,5.724}}
double w[4][10][10],wc[4][10][10],b[4][10],bc[4][10]
double o[4][10],netin[4][10],d[4][10],differ//单个样本的误差
double is //全体样本均方差
int count,a
void netout(int m, int n)//计算网络隐含层和输出层的输出
void calculd(int m,int n) //计算网络的反向传播误差
void calcalwc(int m,int n)//计算网络权值的调整量
void calcaulbc(int m,int n) //计算网络阀值的调整量
void changew(int m,int n) //调整网络权值
void changeb(int m,int n)//调整网络阀值
void clearwc(int m,int n)//清除网络权值变化量wc
void clearbc(int m,int n)//清除网络阀值变化量bc
void initialw(void)//初始化NN网络权值W
void initialb(void) //初始化NN网络阀值
void calculdiffer(void)//计算NN网络单个样本误差
void calculis(void)//计算NN网络全体样本误差
void trainNN(void)//训练NN网络
/*计算NN网络隐含层和输出层的输出 */
void netout(int m,int n)
{
int i,j,k
//隐含层各节点的的输出
for (j=1,i=2j<=mj++) //m为隐含层节点个数
{
netin[i][j]=0.0
for(k=1k<=3k++)//隐含层的每个节点均有三个输入变量
netin[i][j]=netin[i][j]+o[i-1][k]*w[i][k][j]
netin[i][j]=netin[i][j]-b[i][j]
o[i][j]=A/(1+exp(-netin[i][j]/B))
}
//输出层各节点的输出
for (j=1,i=3j<=nj++)
{
netin[i][j]=0.0
for (k=1k<=mk++)
netin[i][j]=netin[i][j]+o[i-1][k]*w[i][k][j]
netin[i][j]=netin[i][j]-b[i][j]
o[i][j]=A/(1+exp(-netin[i][j]/B))
}
}
/*计算NN网络的反向传播误差*/
void calculd(int m,int n)
{
int i,j,k
double t
a=count-1
d[3][1]=(o[3][1]-sample[a][3])*(A/B)*exp(-netin[3][1]/B)/pow(1+exp(-netin[3][1]/B),2)
//隐含层的误差
for (j=1,i=2j<=mj++)
{
t=0.00
for (k=1k<=nk++)
t=t+w[i+1][j][k]*d[i+1][k]
d[i][j]=t*(A/B)*exp(-netin[i][j]/B)/pow(1+exp(-netin[i][j]/B),2)
}
}
/*计算网络权值W的调整量*/
void calculwc(int m,int n)
{
int i,j,k
// 输出层(第三层)与隐含层(第二层)之间的连接权值的调整
for (i=1,k=3i<=mi++)
{
for (j=1j<=nj++)
{
wc[k][i][j]=-COEF*d[k][j]*o[k-1][i]+0.5*wc[k][i][j]
}
// printf("\n")
}
//隐含层与输入层之间的连接权值的调整
for (i=1,k=2i<=mi++)
{
for (j=1j<=mj++)
{
wc[k][i][j]=-COEF*d[k][j]*o[k-1][i]+0.5*wc[k][i][j]
}
// printf("\n")
}
}
/*计算网络阀值的调整量*/
void calculbc(int m,int n)
{
int j
for (j=1j<=mj++)
{
bc[2][j]=BCOEF*d[2][j]
}
for (j=1j<=nj++)
{
bc[3][j]=BCOEF*d[3][j]
}
}
/*调整网络权值*/
void changw(int m,int n)
{
int i,j
for (i=1i<=3i++)
for (j=1j<=mj++)
{
w[2][i][j]=0.9*w[2][i][j]+wc[2][i][j]
//为了保证系统有较好的鲁棒性,计算权值时乘惯性系数0.9
printf("w[2][%d][%d]=%f\n",i,j,w[2][i][j])
}
for (i=1i<=mi++)
for (j=1j<=nj++)
{
w[3][i][j]=0.9*w[3][i][j]+wc[3][i][j]
printf("w[3][%d][%d]=%f\n",i,j,w[3][i][j])
}
}
/*调整网络阀值*/
void changb(int m,int n)
{
int j
for (j=1j<=mj++)
b[2][j]=b[2][j]+bc[2][j]
for (j=1j<=nj++)
b[3][j]=b[3][j]+bc[3][j]
}
/*清除网络权值变化量wc*/
void clearwc(void)
{
for (int i=0i<4i++)
for (int j=0j<10j++)
for (int k=0k<10k++)
wc[i][j][k]=0.00
}
/*清除网络阀值变化量*/
void clearbc(void)
{
for (int i=0i<4i++)
for (int j=0j<10j++)
bc[i][j]=0.00
}
/*初始化网络权值W*/
void initialw(void)
{
int i,j,k,x
double weight
for (i=0i<4i++)
for (j=0j<10j++)
for (k=0k<10k++)
{
randomize()
x=100+random(400)
weight=(double)x/5000.00
w[i][j][k]=weight
}
}
/*初始化网络阀值*/
void initialb(void)
{
int i,j,x
double fazhi
for (i=0i<4i++)
for (j=0j<10j++)
{
randomize()
for (int k=0k<12k++)
{
x=100+random(400)
}
fazhi=(double)x/50000.00
b[i][j]=fazhi
}
}
/*计算网络单个样本误差*/
void calculdiffer(void)
{
a=count-1
differ=0.5*(o[3][1]-sample[a][3])*(o[3][1]-sample[a][3])
}
void calculis(void)
{
int i
is=0.0
for (i=0i<=19i++)
{
o[1][1]=sample[i][0]
o[1][2]=sample[i][1]
o[1][3]=sample[i][2]
netout(8,1)
is=is+(o[3][1]-sample[i][3])*(o[3][1]-sample[i][3])
}
is=is/20
}
/*训练网络*/
void trainNN(void)
{
long int time
int i,x[4]
initialw()
initialb()
for (time=1time<=MAXtime++)
{
count=0
while(count<=40)
{
o[1][1]=sample[count][0]
o[1][2]=sample[count][1]
o[1][3]=sample[count][2]
count=count+1
clearwc()
clearbc()
netout(8,1)
calculdiffer()
while(differ>ERROR)
{
calculd(8,1)
calculwc(8,1)
calculbc(8,1)
changw(8,1)
changb(8,1)
netout(8,1)
calculdiffer()
}
}
printf("This is %d times training NN...\n",time)
calculis()
printf("is==%f\n",is)
if (is<ACCURACY) break
}
}
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double result
int m,test[4]
char ch='y'
cout<<"Please wait for the train of NN:"<<endl
trainNN()
cout<<"Now,this modular network can work for you."<<endl
while(ch=='y' || ch=='Y')
{
cout<<"Please input data to be tested."<<endl
for (m=1m<=3m++)
cin>>test[m]
ch=getchar()
o[1][1]=test[1]
o[1][2]=test[2]
o[1][3]=test[3]
netout(8,1)
result=o[3][1]
printf("Final result is %f.\n",result)
printf("Still test?[Yes] or [No]\n")
ch=getchar()
}
return 0
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)