摘要:
关键词:: 机器人语音控制;语音人机交互;Speech SDK
一、Speech SDK语音识别过程详解:
目前,语音识别技术因为其实用性、趣味性成为国内外关注的热点。微软、IBM等公司都相继推出了它们基于PC的语音识别产品。其中,微软Speech SDK完全支持简体中文语音系统的开发,是开发语音软件的一个理想工具。它是基于COM标准开发的,底层协议以COM组件的形式完全独立于应用程序层,为应用程序设计人员屏蔽了复杂的语音技术,充分体现了COM的技术优点。语音识别由识别引擎(Recognition Engine)管理,能实现从语音中识别出汉字;语音合成由语音合成引擎(也即文本到语音引擎TTS Engine)负责,实现语音朗读。程序员只需专注于自己的应用,调用相关的语音应用程序接口(SAPI)来实现语音功能。
该语音框架主要靠SAPI运行来实现应用程序与语音引擎之间的协作,而SAPI提供各种接口来实现不同的语音功能,如识别、朗读、训练等。
下面只介绍与控制命令识别有关的接口:
(1) 语音识别引擎(ISpRecognizer)接口:用于创建语音识别引擎的实例。语音识别引擎对象有两种:独占(InProcRecognizer)的引擎和共享(SharedRecognizer)的引擎。独占的引擎对象只能由创建的应用程序使用,而共享的引擎可以
供多个应用程序共同使用。
(2) 语音识别上下文(ISpRecoContext)接口:主要用于发送和接收与语音识别相关的消息通知,创建语法规则对象。
(3) 语法规则(ISpRecoGrammar)接口:定义引擎需要识别的具体内容,用于创建、载入和激活识别用的语法规则。而语法规则定义了期望识别的单词、短语和句子,通常有两种语法规则:听写语法(DictationGrammer)和命令控制语法(Command and Control Grammer)。命令控制语法主要用于识别用户在语法文件里自定义的一些特定的命令词汇和句子,这些语法规则以XML文件的格式编写,通过(ISpRecoGrammar)接口载入,并激活。
(4) 识别结果(ISpPhr ase)接口:用于获取识别的结果,包括识别的文字,识别的语法规则等。
(5) 语音合成(ISpVoice)接口:主要功能是通过访问TTS引擎实现文本到语音的转换,从而使电脑会说话。
二、机器人语音控制软件系统设计:
语音识别的功能由ISpRecognizer、ISpRecoContext、ISpRecoGrammar、ISpPhrase四个接口实现,而且遵循COM组件的工作原理和Windows应用程序的工作原理(消息驱动机制),软件系统实现分以下几步:
(1) 首先,初始化COM平台;
(2) 定义各个语音接口对象(以特定的顺序),设置识别语法、识别消息,使识别引擎处于工作状态;
(3) 当有语法规则被识别后, ISpRecoContext对象向应用程序发出语音识别消息,从而调用识别消息响应函数;在改消息函数中,通过ISpPhrase接口获取识别的结果。此步可以循环,直到停止语法规则为止。
(4) 应用程序退出时,卸载COM平台。语音识别软件系统流程如图4所示,硬件只需在原来的机器人系统上配置麦克风。
三、程序实例
(1) 编写语法规则文件(Cmd.xml),以定义需要识别的命令。
<GRAMMARLANGID="804">
<DEFINE>
<ID NAME="CMD"VAL="10"/>
</DEFINE>
<RULE NAME="COMMAND"ID="CMD" TOPLEVEL="ACTIVE">
<L>
<p>前进</P>
<p>后退</P>
<p>左转</p>
<p>右转</p>
<P>停止</P>
</L>
</RULE>
</GRAMMAR>
(2)系统的初始化
1. 在Visual c++ 6. 0中建立一个基于MFC的对话框工程;
2. 在该工程的入口函数处初始化COM平台:
HRESULT hr=CoInitialize(NULL);
3. 在对话框类的头文件中定义建立语音识别需要的接口对象
CComPtr<ISpRecognizer>m_pRecognizer;
CComPtr<ISpRecoContext>m_pRecoCtxt;
CComPtr<ISpRecoGrammar>m_pCmdGram;
CComPtr<ISpAudio>m_pAudio;
4. 在对话框类的初始化函数OnInitDialog()中建立的各个对象进行初始化:
5. 创建一个独占型语音识别引擎
m_pRecognizer.CoCreateInstance(CLSID_SpInprocRecognizer);
6. 创建命令识别上下文
m _ p R e c o g n i z e r->CreateRecoContext(&m_pRecoCtxt);
7. 设置语音事件通知自定义消息WM_RECORD_INFO;在程序中将此消息与OnRecord函数绑定,这样才能识别后激活OnRecord函数。
M_pRecoCtxt->SetNotifyWindowMessage(mhWnd,WM_RECORD_INFO,0,0);
8. 告诉识别引擎,我们只感兴趣命令识别事
m-pRecoCtxt->SetInterest(SPFEI(SPEI_RECOGNITION)
SPFEI(SPEI_RECOGNITION));
9. 创建默认的音频输入对象SpCreateDefaultObjectFromCategoryId ( SPCAT_AUDIOIN,&m_pAudio);
10. 将上面的音频输入对象作为识别引擎对象的音频输入源
m_pRecognizer->SetInput(m_pAudio,TRUE;
11. 创建语法规则,并从Cmd.xml文件装载语法规则
m_pRecoCtxt->CreateGrammar(GID_SRCMD_CN ,&m_pCmdGram);
m_pCmdGram->LoadCmdFromFile(L″test.xml″,SPLO_DYNAMIC);
12. 激活语法规则
g_cpCmdGrammar->SetRuleState(NULL,NULL,SPRS_ACTIVE);
(3)消息函数的实现
经过上述初始化工作后,识别引擎就可以工作,按如图4所示的流程。如果有正确的命令输入,则按照语法规则被识别,语音接口向应用程序发出语音识别通知消息WM_RECORD_INFO,从而调用消息函数OnReord(),其实现表示为
(4)主要实现代码:
//点击按钮打开语音识别
voidCFstarTestDlg::OnVoice()
{
// TODO: Add your control notificationhandler code here
CString cs;
CButton *pBtn=(CButton*)GetDlgItem(IDC_VOICE); //"语音开启"按钮指针
pBtn->GetWindowText(cs);
if (cs=="语音开启")
//根据按钮文本进行不同的操作,可以实现开始和停止两种功能
{
m_Reco.Start(CMD_MODE);
//设置语音识别为指令模式——按照语法文件列举的选项进行识别
pBtn->SetWindowText("语音关闭");
}
else
{
m_staVoice.SetWindowText("");
m_Reco.SetState(STOPRECO); //停止语音识别
pBtn->SetWindowText("语音开启");
}
}
语音识别响应函数:
voidCReco::AfterCmd(CString inStr)
{
if (inStr == "前进" && m_pCmd != NULL){
m_pCmd->SetBothMotorsSpeed(2000,-2000);}
if (inStr == "后退" && m_pCmd != NULL){
m_pCmd->SetBothMotorsSpeed(-2000,2000);}
if (inStr == "左转" && m_pCmd != NULL){
m_pCmd->SetBothMotorsSpeed(-1800,-1800);}
if (inStr == "右转" && m_pCmd != NULL){
m_pCmd->SetBothMotorsSpeed(1800,1800);}
if (inStr == "停止" && m_pCmd != NULL){
m_pCmd->SetBothMotorsSpeed(0,0);}
if (inStr == "开灯" && m_pCmd != NULL){
m_pCmd->TurnOnLgt(3);}
if (inStr == "关灯" && m_pCmd != NULL){
m_pCmd->TurnOffLgt(3);}
m_pTxtOut->SetWindowText(inStr);
}
while(event.GetFrom(m_cpRecoCtxt) == S_OK)
{
switch (event.eEventId)
{
case SPEI_SOUND_START:
break;
case SPEI_SOUND_END:
break;
case SPEI_RECOGNITION:
// There may be multiplerecognition results, so get all of them
{
//识别出了语音输入
static const WCHARwszUnrecognized[] = L"<Unrecognized>";
CSpDynamicStringdstrText;
//取得识别结果
if (FAILED(event.RecoResult()->GetText(SP_GETWHOLEPHRASE,SP_GETWHOLEPHRASE, TRUE
,&dstrText,NULL)))
{
dstrText =wszUnrecognized;
}
BSTR SRout;
dstrText.CopyToBSTR(&SRout);
m_RecStr.Empty();
m_RecStr = SRout;
switch(m_nState)
{
case CMD_MODE:
AfterCmd(m_RecStr);
break;
case TXT_MODE:
AfterTxt(m_RecStr);
break;
}
}
break;
}
}
四、实验结果分析与总结:
实验软件运行在博创科技的机器人平台未来之星上,通过麦克风机器车基本能够响应语音命令,前进,后退,左转,右转,开关,关灯;识别率90%以上,但是对于嘈杂环境识别率明显降低,需要后续的语音信号处理。
五、扩展操作视频处理处理
(1)Directshow介绍:
DirectShow是微软公司在ActiveMovie和Video for Windows的基础上推出的新一代基于COM(ComponentObject Model)的流媒体处理的开发包,与DirectX开发包一起发布。DirectShow使用一种叫Filter Graph的模型来管理整个数据流的处理过程,运用DirectShow,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。这样使在多媒体数据库管理系统(MDBMS)中多媒体数据的存取变得更加方便。它广泛地支持各种媒体格式,包括Asf、Mpeg、Avi、Dv、Mp3、Wave等,为多媒体流的捕捉和回放提供了强有力的支持。
DirectShow还集成了DirectX其它部分(比如DirectDraw、DirectSound)的技术,直接支持DVD的播放,视频的非线性编辑,以及与数字摄像机的数据交换。
DirectShow使用一种叫FilterGraph的模型来管理整个数据流的处理过程;参与数据处理的各个功能模块叫做Filter;各个Filter在Filter Graph中按一定的顺序连接成一条“流水线”协同工作。大家可以看到,按照功能来分,Filter大致分为三类:Source Filters、Transform Filters和RenderingFilters。Source Filters主要负责取得数据,数据源可以是文件、因特网、或者计算机里的采集卡、数字摄像机等,然后将数据往下传输;Transform Fitlers主要负责数据的格式转换、传输;Rendering Filtes主要负责数据的最终去向,我们可以将数据送给声卡、显卡进行多媒体的演示,也可以输出到文件进行存储。值得注意的是,三个部分并不是都只有一个Filter去完成功能。恰恰相反,每个部分往往是有几个Fitler协同工作的。比如,Transform Filters可能包含了一个Mpeg的解码Filter、以及视频色彩空间的转换Filter、音频采样频率转换Filter等等。除了系统提供的大量Filter外,我们可以定制自己的Filter,以完成我们需要的功能。
(2)实现功能:
1、FstarVideo完成有RGB转化为亮度空间,可以用于检测黑线,完成巡线,寻光等操作.
主要操作代码1:
for (int x =0;x< m_nWidth;x++) //m_nWidth为视频的宽度
{
for(int y =0;y<m_nHeight;y++) //m_nHeight为视频的宽度
{
// Median(x,y,prgb); // 中值滤波
// prewitt(x,y,prgb,2.0); //prewitt算子
GetColor(x,y,prgb); //获得xy坐标处的颜色值
//亮度空间转换
tY =0.299*prgb->rgbtRed + 0.587*prgb->rgbtGreen + 0.114*prgb->rgbtBlue;
//将RGB颜色空间转换为亮度空间
if(tY>230) //追踪亮度 //tY为亮度阈值
{
//SetColor(x,y,black); //二值化,将坐标xy处像素值设为黑色
m_pParam->Yx+= x;
m_pParam->Yy+= y;
m_pParam->Ysum++;
//计算被标记的点数量(不绘制总标记重心则可以去掉)
m_nCX = m_pParam->Yx/m_pParam->Ysum;
m_nCY=m_pParam->Yy/m_pParam->Ysum;
prgb->rgbtBlue=0;
prgb->rgbtGreen= 0xff;
prgb->rgbtRed= 0;
DrawFocus(x,y,prgb); //以绿色绘制满足tY的像素值
}else
SetColor(x,y,white); //使这个区域的像素为白色。
}
主要操作代码2:
//为该区域像素变红色
for (int m =400;m<426;m++)
{
for (int n=75;n<86;n++)
{
SetColor(m,n,red);
}
}
//对每个像素进行操作
for (int p=400;p<409;p++) //查询像素值
{
for (int q=400;q<409;q++)
{
prgb->rgbtBlue =m_pImageBuf[q*m_nWidth*3 + p*3];
prgb->rgbtGreen = m_pImageBuf[q*m_nWidth*3 + p*3 + 1];
prgb->rgbtRed = m_pImageBuf[q*m_nWidth*3 + p*3 + 2];
//操作像素值
if(prgb->rgbtBlue==0&& prgb->rgbtGreen==0xff && prgb->rgbtRed==0)
//绿色像素进行操作 {
SetColor(p,q,black); //使p,q之间的区域为黑色 }
}
}
处理实例分析与总结:
该实验中数据量很大,不能完成基本的中值滤波,或者prewitt算子滤波。
2、实现颜色追踪,本次实验主要针对红色追踪:
主要程序一:
m_vDemo.m_para.ReSet(); //设置复位颜色值,RGB各分量全为零
m_vDemo.m_para.Ven= TRUE;
m_vDemo.m_para.Vmin= 55; //设置颜色阈值范围
m_vDemo.m_para.Vmax= 120;
m_pCap->SetCmd(&m_cmd);
m_cmd.SetBehavior(&m_vDemo);
主要程序一:
for (int x =0;x< m_nWidth;x++)
{
for (int y =0;y<m_nHeight;y++)
{
GetColor(x,y,prgb);
flag= FALSE; //判断结果标记
//根据使能变量决定是否进行颜色空间转换
if(m_pParam->Ven == TRUE)
{
tV= 0.5*prgb->rgbtRed - 0.45*prgb->rgbtGreen - 0.05*prgb->rgbtBlue;
if(m_pParam->Vmin<tV && tV<m_pParam->Vmax)
{
m_pParam->Vx+= x;
m_pParam->Vy+= y;
m_pParam->Vsum++;
flag= TRUE;
}
}
if (flag == TRUE)
SetColor(x,y,red); //检测到红色后将其标记为红色
}
}
}
else
{ //只进行统计
for (int x=0;x< m_nWidth-1;x++)
{
for (int y =0;y<m_nHeight-1;y++)
{
GetColor(x,y,prgb);
//根据使能标记进行颜色空间变换
if(m_pParam->Ven == TRUE)
{
tV= 0.5*prgb->rgbtRed- 0.45*prgb->rgbtGreen - 0.05*prgb->rgbtBlue;;
if(m_pParam->Vmin<tV && tV<m_pParam->Vmax)
{
m_pParam->Vx+= x;
m_pParam->Vy+= y;
m_pParam->Vsum++;
}
}
if (m_pParam->Yen == TRUE)
{
tY= 0;
if(m_pParam->Ymin<tY && tY<m_pParam->Ymax)
{
m_pParam->Yx += x;
m_pParam->Yy+= y;
m_pParam->Ysum++;
}
}}}}
//开始绘制颜色重心点
//如果没有找到任何点则返回
if(m_pParam->Ysum< 1 && m_pParam->Usum < 1 && m_pParam->Vsum < 1)
{
delete prgb;
m_pParam->bBusy = FALSE;
return FALSE;
}
//计算被标记的点数量(不绘制总标记重心则可以去掉)
m_nCX =(m_pParam->Ux +m_pParam->Vx + m_pParam->Yx)/(m_pParam->Usum + m_pParam->Vsum +m_pParam->Ysum);
m_nCY=(m_pParam->Uy +m_pParam->Vy + m_pParam->Yy)/(m_pParam->Usum + m_pParam->Vsum +m_pParam->Ysum);
prgb->rgbtBlue=0;
prgb->rgbtGreen= 0xff;
prgb->rgbtRed= 0;
DrawFocus(m_nCX,m_nCY,prgb); //对中心部分作为绘制绿色点
//计算各重心坐标
if(m_pParam->Ven == TRUE)
{
m_pParam->Vx =m_pParam->Vx/m_pParam->Vsum;
m_pParam->Vy =m_pParam->Vy/m_pParam->Vsum;
}
实验结果分析:
3、实现运动追踪:
3.1、理论研究:
视频图像中的运动追踪的首要工作是确定场景中存在的运动目标,即运动目标的检测。并且检测要达到以下要求:
(1)对环境的缓慢变化(如光照变化等)不敏感;
(2)对于复杂背景和复杂目标有效;
(3)能适应场景中个别物体运动的干扰(如树木的摇晃,水面的波动等);
(4)能够去除目标阴影的影响;
(5)检测和分割的结果应满足后续处理(如跟踪等)的精度要求。
3.2、运动目标检测常用的方法有:
(1)帧间差分法
帧间差分法是检测相邻图像之间变化的最简单方法,主要利用视频序列中连续的两帧或几帧图像的差异来进行目标检测和提取。
帧间差分法的特点:
用帧间差分法进行目标检测和分割,算法复杂度低,便于实时使用。由于相邻帧的时间间隔一般较短,因此该方法对场景光线的变化一般不太敏感,稳定性较好。但是检测中依赖于选择的帧时间间隔,对快速运动的物体,需要选择较小的时间间隔。如果选择不合适,当物体在前后两帧中没有重叠时会被检测为两个分开的物体;而对慢速运动的物体应该选择较大的时间差,如果此时选择不适当,物体在前后两帧中几乎完全重叠,则检测不到物体。且一般都不能完全提取出所有的特征像素点,这样在运动实体内部容易产生空洞现象,即使进行了必要的数字图像的形态学处理和连通性分析,也不能得到运动目标的完整轮廓,给以后的运动目标识别和检测带来了困难。
(2)背景相减法
这种方法能够较完整的提取目标点,但对场景的动态变化如光照或外部条件引起的场景变化较为敏感。如果参考图像选取适当,这种方法的优点是可以准确地分割出运动物体。但是,该方法成功与否依赖于所采用的背景图像。如何获取一个相对准确的背景图像是背景相减法的一个重点内容,通常利用背景更新的方法以弥补动态场景中的光线变化等因素带来的不利影响。
引起背景变化的原因
①光照变化:包括连续的光照变化,通常是室外环境;突然的光照变化,通常是室内环境中关灯或者室外晴天出现乌云等情况;投影到背景中的阴影,这既可能是背景自己产生的阴影,如大楼、树,也可能是前景目标自身的阴影。
②背景扰动:背景中存在的如风中树叶的摇动、水面波光的闪动、车窗玻璃的反光以及天气变化等许多细微活动,都会影响到运动目标的检测。再如室外摄像机受风吹而抖动同样会影响运动目标的检测。
③背景变化:运动目标引起的背景变化包括人将某个东西带入或带出背景,汽车驶入或驶出,或者人或物在场景中停留一阵后又运动的情况。
④遮挡问题:遮挡也是运动目标检测过程中一个难以解决的问题,在运动目标前方的遮挡物能会作为目标的一部分被提取出来,从而造成检测目标变形严重,甚至还会检测目标的失败。这些因素都会大大提高背景建模及背景更新的难度,影响到检测的效果。
3.3、运动目标检测前需要对视频数据进行处理,常用的处理方法有:
(1)统计平均法:
该方法通过对连续的图像序列进行统计平均来获得背景图像,即连续采集N帧图像累加求平均,式中N为图像帧数。
这种更新方法在每次更新时考虑利用当前帧信息而废弃过时信息,从而有利于背景自适应地跟随新环境的变化而变化。算法简单易实现,由于采用递归算法,故时间开销小。
该算法的不足之处是需要保存帧图像的数据,增加了空间的开销。这种方法通常用于场景内目标滞留时间较小、目标出现不频繁的情况。但是统计平均法无法满足实时性要求。
(2)中值滤波器法
通常在背景模型提取阶段,运动目标可以在监视区域运动,但不会长时间停留在某一个位置上。对视频画面中某一像素进行一段时间的观测,可以发现,只有在前景目标通过该点时,它的亮度值才发生大的变化。中值滤波法的思想是先建
立一个视频流滑窗用来缓存L张视频帧,然后把缓存中所有视频帧同位置像素的中值作为背景中该处像素的值。
L值的大小由运动目标通过的速度和摄像机拍摄时的采样速率等因素决定。
(3)GMM方法
在一段较长时间内,对图像中同一位置的像素点进行采集,该像素点作为背景图像上的一点,在理想状态下,采样值应该是某一个固定值,但是由于光照等自然因素的影响存在偏差。在统计意义下,这些采样值是服从单高斯分布模型的,它们主要集中在概率大的高斯模型的中心位置上,而在该点上出现的运动目标则是属于发生概率小的远离高斯模型中心的部分。因此我们可以计算这个像素点的平均亮度μ0,以及它的方差σ02,用各点像素的亮度均值组成的具有高斯分布的图像作为背景图像B0,其中
但是,用单高斯模型来描述背景是不够的。例如,在某帧中一个像素可能表示天空,但在另一帧中则可能表示树叶,而在第3帧中则又可能表示树枝。显然,每一种状态下的像素亮度(颜色)值是不同的,因此可以对这些多模态情形使用多个高斯模型来混合建模。设用来描述每个点像素值的高斯分布共有k个,分别记为η(x,u,μit,σit),i =1,2,...,k,则有
如果没有任何高斯模型与当前亮度值匹配,则将权重最小的高斯分量以一个新的高斯模型替代。新高斯模型的内核密度均值为It ,偏差为最大初始偏差,权重为最小初始权重。其他高斯分布模型不变,只降低它们的权重,即
混合高斯法在背景建模过程中由于允许运动目标存在,因此尤其适合室外有光线和天气变化的小而速度快的运动目标的检测。它的缺点首先是计算复杂,不仅对背景建模,实际上也对前景建模,其计算复杂度与高斯模型的个数成正比,而且模型参数难调。其次,它对大而慢的目标检测效果也不好,特别是会将纹理少或对比度低的目标当作背景。第三就是它对全局亮度的突然变化非常敏感,如果场景很长时间没变,则背景分量的变化就非常小,但是全局亮度的突然变化会将
整个视频帧认为是前景。
3.4、工程实践:
本文主要用帧间差分法做运动追踪。
六、 结论
采用语音识别技术将人类之间的交流方式应用于人类与机器之间,是机器人智能水平的重要标志。
本文阐明了语音接口的工作原理和开发程序,对于开发设计具有语音识别的智能机器人,具有很高的参考价值。
七、参考文献
[1] Microsoft Speech 5.1 SDK Help [Z].
[2] 博创科技未来之星实验指导书(第二版)
[3] 骆家伟,基于MicrosoftSpeech SDK的语音程序的设计与实现,2009
[4] 宋坤, 刘锐宁, 马文强,Visual C++视频技术方案宝典
[5] 陈兵旗, 孙明,Visual C++实用图像处理专业教程
[6] 左飞, 万晋森, 刘航,Visual C++数字图像处理开发入门与编程实践
[7] 刘瑞祯, 于仕琪,OpenCV教程.基础篇
[8] 冯伟兴,唐墨,贺波,,冯伟兴,唐墨,贺波
八、附录:
(1)中值滤波法,中值滤波法是一种非线性平滑技术,它将每一象素点的灰度值设置为该点某邻域窗口内的所有象素点灰度值的中值.
实现方法:
1:通过从图像中的某个采样窗口取出奇数个数据进行排序
2:用排序后的中值取代要处理的数据即可
中值滤波法对消除椒盐噪音非常有效,在光学测量条纹图象的相位分析处理方法中有特殊作用,但在条纹中心分析方法中作用不大.
中值滤波在图像处理中,常用于用来保护边缘信息,是经典的平滑噪声的方法
中值滤波原理
中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。方法是去某种结构的二维滑动模板,将板内像素按照像素值的大小进行排序,生成单调上升(或下降)的为二维数据序列。二维中值滤波输出为g(x,y)=med{f(x-k,y-l),(k,l∈W)} ,其中,f(x,y),g(x,y)分别为原始图像和处理后图像。W为二维模板,通常为2*2,3*3区域,也可以是不同的的形状,如线状,圆形,十字形,圆环形等。
(2)Prewitt算子:
Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。
对数字图像f(x,y),Prewitt算子的定义如下:
G(i)=|[f(i-1,j-1)+f(i-1,j)+f(i-1,j+1)]-[f(i+1,j-1)+f(i+1,j)+f(i+1,j+1)]|
G(j)=|[f(i-1,j+1)+f(i,j+1)+f(i+1,j+1)]-[f(i-1,j-1)+f(i,j-1)+f(i+1,j-1)]|
则 P(i,j)=max[G(i),G(j)]或P(i,j)=G(i)+G(j)
经典Prewitt算子认为:凡灰度新值大于或等于阈值的像素点都是边缘点。即选择适当的阈值T,若P(i,j)≥T,则(i,j)为边缘点,P(i,j)为边缘图像。这种判定是欠合理的,会造成边缘点的误判,因为许多噪声点的灰度值也很大,而且对于幅值较小的边缘点,其边缘反而丢失了。
//prewitt