2009年2月6日星期五

车牌识别及验证码识别的一般思路(转帖)

转自http://www.cnblogs.com/xiaotie/archive/2009/01/15/1376677.html

本文源自我之前花了2天时间做的一个简单的车牌识别系统。那个项目,时间太紧,样本也有限,达不到对方要求的95%识别率(主要对于车牌来说,D,0OI1等等太相似了。然后,汉字的识别难度也不小),因此未被对方接受。在此放出,同时描述一下思路及算法。

全文分两部分,第一部分讲车牌识别及普通验证码这一类识别的普通方法,第二部分讲对类似QQ验证码,Gmail验证码这一类变态验证码的识别方法和思路。

一、车牌/验证码识别的普通方法

车牌、验证码识别的普通方法为:

(1) 将图片灰度化与二值化

(2) 去噪,然后切割成一个一个的字符

(3) 提取每一个字符的特征,生成特征矢量或特征矩阵

(4) 分类与学习。将特征矢量或特征矩阵与样本库进行比对,挑选出相似的那类样本,将这类样本的值作为输出结果。

下面借着代码,描述一下上述过程。因为更新SVN Server,我以前以bdb储存的代码访问不了,因此部分代码是用Reflector反编译过来的,望见谅。

(1) 图片的灰度化与二值化

这样做的目的是将图片的每一个象素变成0或者255,以便以计算。同时,也可以去除部分噪音。

图片的灰度化与二值化的前提是bmp图片,如果不是,则需要首先转换为bmp图片。

用代码说话,我的将图片灰度化的代码(算法是在网上搜到的):


1 protected static Color Gray(Color c)
2 {
3 int rgb = Convert.ToInt32((double) (((0.3 * c.R) + (0.59 * c.G)) + (0.11 * c.B)));
4 return Color.FromArgb(rgb, rgb, rgb);
5 }
6

通过将图片灰度化,每一个象素就变成了一个0-255的灰度值。

然后是将灰度值二值化为 0 255。一般的处理方法是设定一个区间,比如,[a,b],将[a,b]之间的灰度全部变成255,其它的变成0。这里我采用的是网上广为流行的自适应二值化算法。


1 public static void Binarizate(Bitmap map)
2 {
3 int tv = ComputeThresholdValue(map);
4 int x = map.Width;
5 int y = map.Height;
6 for (int i = 0; i < x; i++)
7 {
8 for (int j = 0; j < y; j++)
9 {
10 if (map.GetPixel(i, j).R >= tv)
11 {
12 map.SetPixel(i, j, Color.FromArgb(0xff, 0xff, 0xff));
13 }
14 else
15 {
16 map.SetPixel(i, j, Color.FromArgb(0, 0, 0));
17 }
18 }
19 }
20 }
21
22 private static int ComputeThresholdValue(Bitmap img)
23 {
24 int i;
25 int k;
26 double csum;
27 int thresholdValue = 1;
28 int[] ihist = new int[0x100];
29 for (i = 0; i < 0x100; i++)
30 {
31 ihist[i] = 0;
32 }
33 int gmin = 0xff;
34 int gmax = 0;
35 for (i = 1; i < (img.Width - 1); i++)
36 {
37 for (int j = 1; j < (img.Height - 1); j++)
38 {
39 int cn = img.GetPixel(i, j).R;
40 ihist[cn]++;
41 if (cn > gmax)
42 {
43 gmax = cn;
44 }
45 if (cn < gmin)
46 {
47 gmin = cn;
48 }
49 }
50 }
51 double sum = csum = 0.0;
52 int n = 0;
53 for (k = 0; k <= 0xff; k++)
54 {
55 sum += k * ihist[k];
56 n += ihist[k];
57 }
58 if (n == 0)
59 {
60 return 60;
61 }
62 double fmax = -1.0;
63 int n1 = 0;
64 for (k = 0; k < 0xff; k++)
65 {
66 n1 += ihist[k];
67 if (n1 != 0)
68 {
69 int n2 = n - n1;
70 if (n2 == 0)
71 {
72 return thresholdValue;
73 }
74 csum += k * ihist[k];
75 double m1 = csum / ((double) n1);
76 double m2 = (sum - csum) / ((double) n2);
77 double sb = ((n1 * n2) * (m1 - m2)) * (m1 - m2);
78 if (sb > fmax)
79 {
80 fmax = sb;
81 thresholdValue = k;
82 }
83 }
84 }
85 return thresholdValue;
86 }
87
88

灰度化与二值化之前的图片:

灰度化与二值化之后的图片:

注:对于车牌识别来说,这个算法还不错。对于验证码识别,可能需要针对特定的网站设计特殊的二值化算法,以过滤杂色。

(2) 去噪,然后切割成一个一个的字符

上面这张车牌切割是比较简单的,从左到右扫描一下,碰见空大的,咔嚓一刀,就解决了。但有一些车牌,比如这张:

简单的扫描就解决不了。因此需要一个比较通用的去噪和切割算法。这里我采用的是比较朴素的方法:

将上面的图片看成是一个平面。将图片向水平方向投影,这样有字的地方的投影值就高,没字的地方投影得到的值就低。这样会得到一根曲线,像一个又一个山头。下面是我手画示意图:

然后,用一根扫描线(上图中的S)从下向上扫描。这个扫描线会与图中曲线存在交点,这些交点会将山头分割成一个又一个区域。车牌图片一般是7个字符,因此,当扫描线将山头分割成七个区域时停止。然后根据这七个区域向水平线的投影的坐标就可以将图片中的七个字符分割出来。

但是,现实是复杂的。比如,“川”字,它的水平投影是三个山头。按上面 这种扫描方法会将它切开。因此,对于上面的切割,需要加上约束条件:每个山头有一个中心线,山头与山头的中心线的距离必需在某一个值之上,否则,则需要将 这两个山头进行合并。加上这个约束之后,便可以有效的切割了。

以上是水平投影。然后还需要做垂直投影与切割。这里的垂直投影与切割就一个山头,因此好处理一些。

切割结果如下:

水平投影及切割代码:


1 public static IList<Bitmap> Split(Bitmap map, int count)
2 {
3 if (count <= 0)
4 {
5 throw new ArgumentOutOfRangeException("Count 必须大于0.");
6 }
7 IList<Bitmap> resultList = new List<Bitmap>();
8 int x = map.Width;
9 int y = map.Height;
10 int splitBitmapMinWidth = 4;
11 int[] xNormal = new int[x];
12 for (int i = 0; i < x; i++)
13 {
14 for (int j = 0; j < y; j++)
15 {
16 if (map.GetPixel(i, j).R == CharGrayValue)
17 {
18 xNormal[i]++;
19 }
20 }
21 }
22 Pair pair = new Pair();
23 for (int i = 0; i < y; i++)
24 {
25 IList<Pair> pairList = new List<Pair>(count + 1);
26 for (int j = 0; j < x; j++)
27 {
28 if (xNormal[j] >= i)
29 {
30 if ((j == (x - 1)) && (pair.Status == PairStatus.Start))
31 {
32 pair.End = j;
33 pair.Status = PairStatus.End;
34 if ((pair.End - pair.Start) >= splitBitmapMinWidth)
35 {
36 pairList.Add(pair);
37 }
38 pair = new Pair();
39 }
40 else if (pair.Status == PairStatus.JustCreated)
41 {
42 pair.Start = j;
43 pair.Status = PairStatus.Start;
44 }
45 }
46 else if (pair.Status == PairStatus.Start)
47 {
48 pair.End = j;
49 pair.Status = PairStatus.End;
50 if ((pair.End - pair.Start) >= splitBitmapMinWidth)
51 {
52 pairList.Add(pair);
53 }
54 pair = new Pair();
55 }
56 if (pairList.Count > count)
57 {
58 break;
59 }
60 }
61 if (pairList.Count == count)
62 {
63 foreach (Pair p in pairList)
64 {
65 if (p.Width < (map.Width / 10))
66 {
67 int width = (map.Width / 10) - p.Width;
68 p.Start = Math.Max(0, p.Start - (width / 2));
69 p.End = Math.Min((int) (p.End + (width / 2)), (int) (map.Width - 1));
70 }
71 }
72 foreach (Pair p in pairList)
73 {
74 int newMapWidth = (p.End - p.Start) + 1;
75 Bitmap newMap = new Bitmap(newMapWidth, y);
76 for (int ni = p.Start; ni <= p.End; ni++)
77 {
78 for (int nj = 0; nj < y; nj++)
79 {
80 newMap.SetPixel(ni - p.Start, nj, map.GetPixel(ni, nj));
81 }
82 }
83 resultList.Add(newMap);
84 }
85 return resultList;
86 }
87 }
88 return resultList;
89 }
90

代码中的 Pair,代表扫描线与曲线的一对交点:


1 private class Pair
2 {
3 public Pair();
4 public int CharPixelCount { get; set; }
5 public int CharPixelXDensity { get; }
6 public int End { get; set; }
7 public int Start { get; set; }
8 public BitmapConverter.PairStatus Status { get; set; }
9 public int Width { get; }
10 }
11

PairStatus代表Pair的状态。具体哪个状态是什么意义,我已经忘了。


1 private enum PairStatus
2 {
3 JustCreated,
4 Start,
5 End
6 }
7

以上这一段代码写的很辛苦,因为要处理很多特殊情况。那个PairStatus 也是为处理特殊情况引进的。

垂直投影与切割的代码简单一些,不贴了,见附后的dllBitmapConverter.TrimHeight方法。

以上用到的是朴素的去噪与切割方法。有些图片,尤其是验证码图片,需要特别的去噪处理。具体操作方法就是,打开CxImagehttp://www.codeproject.com/KB/graphics/cximage.aspx),或者Paint.Net,用上面的那些图片处理方法,看看能否有效去噪。记住自己的操作步骤,然后翻他们的源代码,将其中的算法提取出来。还有什么细化啊,滤波啊,这些处理可以提高图片的质量。具体可参考ITK的代码或图像处理书籍。

(3) 提取每一个字符的特征,生成特征矢量或特征矩阵

将切割出来的字符,分割成一个一个的小块,比如3×35×5,或3×5,或10×8,然后统计一下每小块的值为255的像素数量,这样得到一个矩阵M,或者将这个矩阵简化为矢量V

通过以上3步,就可以将一个车牌中的字符数值化为矢量了。

1-3)步具体的代码流程如下:


1
2 BitmapConverter.ToGrayBmp(bitmap); // 图片灰度化
3 BitmapConverter.Binarizate(bitmap); // 图片二值化
4 IList<Bitmap> mapList = BitmapConverter.Split(bitmap, DefaultCharsCount); // 水平投影然后切割
5 Bitmap map0 = BitmapConverter.TrimHeight(mapList[0], DefaultHeightTrimThresholdValue); // 垂直投影然后切割
6 ImageSpliter spliter = new ImageSpliter(map0);
7 spliter.WidthSplitCount = DefaultWidthSplitCount;
8 spliter.HeightSplitCount = DefaultHeightSplitCount;
9 spliter.Init();
10

然后,通过spliter.ValueList就可以获得 Bitmap map0 的矢量表示。

(4) 分类

分类的原理很简单。用(Vij,Ci)表示一个样本。其中,Vij是样本图片经过上面过程数值化后的矢量。Ci是人肉眼识别这张图片,给出的结果。Vij表明,有多个样本,它们的数值化后的矢量不同,但是它们的结果都是Ci。假设待识别的图片矢量化后,得到的矢量是V’

直观上,我们会有这样一个思路,就是这张待识别的图片,最像样本库中的某张图片,那么我们就将它当作那张图片,将它识别为样本库中那张图片事先指定的字符。

在我们眼睛里,判断一张图片和另一张图片是否相似很简单,但对于电脑来说,就很难判断了。我们前面已经将图片数值化为一个个维度一样的矢量,电脑是怎样判断一个矢量与另一个矢量相似的呢?

这里需要计算一个矢量与另一个矢量间的距离。这个距离越短,则认为这两个矢量越相似。

我用 SampleVector 来代表矢量:


1 public class SampleVector<T>
2 {
3 protected T[] Vector { get; set; }
4 public Int32 Dimension { get { return Vector.Length; } }
5 ……
6 }
7

T代表数据类型,可以为Int32,也可以为Double等更精确的类型。

测量距离的公共接口为:IMetric


1 public interface IMetric<TElement,TReturn>
2 {
3 TReturn Compute(SampleVector<TElement> v1, SampleVector<TElement> v2);
4 }
5

常用的是MinkowskiMetric


1 ///
2 /// Minkowski 测度。
3 ///
4 public class MinkowskiMetric<TElement> : IMetric<TElement, Double>
5 {
6 public Int32 Scale { get; private set; }
7 public MinkowskiMetric(Int32 scale)
8 { Scale = scale; }
9
10 public Double Compute(SampleVector<TElement> v1, SampleVector<TElement> v2)
11 {
12 if (v1 == null || v2 == null) throw new ArgumentNullException();
13 if (v1.Dimension != v2.Dimension) throw new ArgumentException("v1 和 v2 的维度不等.");
14 Double result = 0;
15 for (int i = 0; i < v1.Dimension; i++)
16 {
17 result += Math.Pow(Math.Abs(Convert.ToDouble(v1[i]) - Convert.ToDouble(v2[i])), Scale);
18 }
19 return Math.Pow(result, 1.0 / Scale);
20 }
21 }
22
23 MetricFactory 负责生产各种维度的MinkowskiMetric:
24
25 public class MetricFactory
26 {
27 public static IMetric<TElement, Double> CreateMinkowskiMetric<TElement>(Int32 scale)
28 {
29 return new MinkowskiMetric<TElement>(scale);
30 }
31
32 public static IMetric<TElement, Double> CreateEuclideanMetric<TElement>()
33 {
34 return CreateMinkowskiMetric<TElement>(2);
35 }
36 }
37

MinkowskiMetric是普遍使用的测度。但不一定是最有效的量。因为它对于矢量V中的每一个点都一视同仁。而在图像识别中,每一个点的重要性却并不一样,例如,QO的识别,特征在下半部分,下半部分的权重应该大于上半部分。对于这些易混淆的字符,需要设计特殊的测量方法。在车牌识别中,其它易混淆的有D00OI1Minkowski Metric识别这些字符,效果很差。因此,当碰到这些字符时,需要进行特别的处理。由于当时时间紧,我就只用了Minkowski Metric

我的代码中,只实现了哪个最近,就选哪个。更好的方案是用K近邻分类器或神经网络分类器。K近邻的原理是,找出和待识别的图片(矢量)距离最近的K个样本,然后让这K个样本使用某种规则计算(投票),这个新图片属于哪个类别(C);神经网络则将测量的过程和投票判决的过程参数化,使它可以随着样本的增加而改变,是这样的一种学习机。有兴趣的可以去看《模式分类》一书的第三章和第四章。

二、 变态字符的识别

有些字符变形很严重,有的字符连在一起互相交叉,有的字符被掩盖在一堆噪音海之中。对这类字符的识别需要用上特殊的手段。

下面介绍几种几个经典的处理方法,这些方法都是被证实对某些问题很有效的方法:

(1) 切线距离 Tangent Distance):可用于处理字符的各种变形,OCR的核心技术之一。

(2) 霍夫变换(Hough Transform):对噪音极其不敏感,常用于从图片中提取各种形状。图像识别中最基本的方法之一。

(3) 形状上下文(Shape Context):将特征高维化,对形变不很敏感,对噪音也不很敏感。新世纪出现的新方法。

因为这几种方法我均未编码实现过,因此只简单介绍下原理及主要应用场景。

(1) 切线距离

前面介绍了MinkowskiMetric。这里我们看看下面这张图:一个正写的1与一个歪着的1.

MinkowskiMetric计算的话,两者的MinkowskiMetric很大。

然而,在图像识别中,形状形变是常事。理论上,为了更好地识别,我们需要对每一种形变都采足够的样,这样一来,会发现样本数几乎无穷无尽,计算量越来越大。

怎么办呢?那就是通过计算切线距离,来代替直接距离。切线距离比较抽象,我们将问题简化为二维空间,以便以理解。

上图有两条曲线。分别是两个字符经过某一形变后所产生的轨迹。V1V22个样本。V’是待识别图片。如果用样本之间的直接距离,比较哪个样本离V’最近,就将V’当作哪一类,这样的话,就要把V’分给V1了。理论上,如果我们无限取样的话,下面那一条曲线上的某个样本离V’最近,V’应该归类为V2。不过,无限取样不现实,于是就引出了切线距离:在样本V1V2处做切线,然后计算V’离这两条切线的距离,哪个最近就算哪一类。这样一来,每一个样本,就可以代表它附近的一个样本区域,不需要海量的样本,也能有效的计算不同形状间的相似性。

深入了解切线距离,可参考这篇文章。Transformation invariance in pattern recognition – tangent distance and tangent propagation (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.32.9482)这篇文章。

(2) 霍夫变换

霍夫变换出自1962年的一篇专利。它的原理非常简单:就是坐标变换的问题。

如,上图中左图中的直线,对应着有图中k-b坐标系中的一个点。通过坐标变换,可以将直线的识别转换为点的识别。点的识别就比直线识别简单的多。为了避免无限大无限小问题,常用的是如下变换公式:

下面这张图是wikipedia上一张霍夫变换的示意图。左图中的两条直线变换后正对应着右图中的两个亮点。

通过霍夫变换原理可以看出,它的抗干扰性极强极强:如果直线不是连续的,是断断续续的,变换之后仍然是一个点,只是这个点的强度要低一些。如果一个直线被一个矩形遮盖住了,同样不影响识别。因为这个特征,它的应用性非常广泛。

对于直线,圆这样容易被参数化的图像,霍夫变换是最擅长处理的。对于一般的曲线,可通过广义霍夫变换进行处理。感兴趣的可以google之,全是数学公式,看的人头疼。

(3) 形状上下文

图像中的像素点不是孤立的,每个像素点,处于一个形状背景之下,因此,在提取特征时,需要将像素点的背景也作为该像素点的特征提取出来,数值化。

形状上下文(Shape Context,形状背景)就是这样一种方法:假定要提取像素点O的特征,采用上图(c)中的坐标系,以O点作为坐标系的圆心。这个坐标系将O点的上下左右切割成了12×5=60小块,然后统计这60小块之内的像素的特征,将其数值化为12×5的矩阵,上图中的(d),(e),(f)便分别是三个像素点的Shape Context数值化后的结果。如此一来,提取的每一个点的特征便包括了形状特征,加以计算,威力甚大。来看看Shape Context的威力:

上图中的验证码,对Shape Context来说只是小Case

看看这几张图。嘿嘿,硬是给识别出来了。

Shape Context是新出现的方法,其威力到底有多大目前还未见底。这篇文章是Shape context的必读文章:Shape Matching and Object Recognitiom using shape contextshttp://www.cs.berkeley.edu/~malik/papers/BMP-shape.pdf)。最后那两张验证码识别图出自Greg Mori,Jitendra Malik的《Recognizing Objects in Adversarial Clutter:Breaking a Visual CAPTCHA》一文。

===========================================================

附件:第一部分的代码(vcr.zip). 3个dll文件,反编译看的很清晰。源代码反而没dll好看,我就不放了。其中,Orc.Generics.dll是几个泛型 类,Orc.ImageProcess.Common.dll 对图像进行处理和分割,Orc.PatternRecognition.dll 是识别部分。

这三个dll可以直接用在车牌识别上。用于车牌识别,对易混淆的那几个字符识别率较差,需要补充几个分类器,现有分类器识别结果为D ,O,0,I,1等时,用新分类器识别。用于识别验证码需要改一改。

有个asp.net的调用例子可实现在线上传图片识别,因为其中包含多张车牌信息,不方便放出来。我贴部分代码出来:

Global.asax:

void Application_Start(object sender, EventArgs e)
{
log4net.Config.XmlConfigurator.Configure();
Orc.Spider.Vcr.DaoConfig.Init();
Classifier.Update(Server);
}

DaoConfig:

using System;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord.Framework.Config;

namespace Orc.Spider.Vcr
{
public static class DaoConfig
{
private static Boolean Inited = false;

public static void Init()
{
if (!Inited)
{

Inited
= true;
XmlConfigurationSource con
= new XmlConfigurationSource(AppDomain.CurrentDomain.BaseDirectory + @"\ActiveRecord.config");

ActiveRecordStarter.Initialize
(con,
typeof(TrainPattern)
);
}
}
}
}

TrainPattern:
// TrainPattern存在数据库里

[ActiveRecord(
"TrainPattern")]
public class TrainPattern : ActiveRecordBase<TrainPattern>
{
[PrimaryKey(PrimaryKeyType.Native,
"Id")]
public Int32 Id { get; set; }

[Property(
"FileName")]
public String FileName { get; set; }

[Property(
"Category")]
public String Category { get; set; }

public static TrainPattern[] FindAll()
{
String hql
= "from TrainPattern ORDER BY Category DESC";
SimpleQuery
<TrainPattern> query = new SimpleQuery<TrainPattern>(hql);
return query.Execute();
}
}

Classifier:
//主要调用封装在这里

public class Classifier
{
protected static Orc.PatternRecognition.KnnClassifier<Int32> DefaultChineseCharClassifier;
protected static Orc.PatternRecognition.KnnClassifier<Int32> DefaultEnglishAndNumberCharClassifier;
protected static Orc.PatternRecognition.KnnClassifier<Int32> DefaultNumberCharClassifier;

public static Int32 DefaultWidthSplitCount = 3;
public static Int32 DefaultHeightSplitCount = 3;
public static Int32 DefaultCharsCount = 7; // 一张图片中包含的字符个数
public static Int32 DefaultHeightTrimThresholdValue = 4;

public static ILog Log = LogManager.GetLogger("Vcr");

public static void Update(HttpServerUtility server)
{
TrainPattern[] TPList
= TrainPattern.FindAll();

if (TPList == null) return;

DefaultChineseCharClassifier
= new KnnClassifier<Int32>(DefaultWidthSplitCount * DefaultHeightSplitCount);
DefaultEnglishAndNumberCharClassifier
= new KnnClassifier<Int32>(DefaultWidthSplitCount * DefaultHeightSplitCount);
DefaultNumberCharClassifier
= new KnnClassifier<Int32>(DefaultWidthSplitCount * DefaultHeightSplitCount);

foreach (TrainPattern tp in TPList)
{
String path
= server.MapPath(".") + "/VcrImage/" + tp.FileName;
using (Bitmap bitmap = new Bitmap(path))
{
TrainPattern
<Int32> tpv = CreateTainPatternVector(bitmap, tp.Category.Substring(0, 1));
Char c
= tpv.Category[0];
if (c >= '0' && c <= '9')
{
DefaultEnglishAndNumberCharClassifier.AddTrainPattern(tpv);
DefaultNumberCharClassifier.AddTrainPattern(tpv);
}
else if (c >= 'a' && c <= 'z')
DefaultEnglishAndNumberCharClassifier.AddTrainPattern(tpv);
else if (c >= 'A' && c <= 'Z')
DefaultEnglishAndNumberCharClassifier.AddTrainPattern(tpv);
else
DefaultChineseCharClassifier.AddTrainPattern(tpv);
}
}
}

protected static TrainPattern<Int32> CreateTainPatternVector(Bitmap bitmap, String categoryChars)
{
TrainPattern
<int> tpv = new TrainPattern<int>( CreateSampleVector(bitmap), categoryChars);
tpv.XNormalSample
= CreateXNormalSampleVector(bitmap);
tpv.YNormalSample
= CreateYNormalSampleVector(bitmap);
return tpv;
}

protected static SampleVector<Int32> CreateSampleVector(Bitmap bitmap)
{
ImageSpliter spliter
= new ImageSpliter(bitmap);
spliter.WidthSplitCount
= DefaultWidthSplitCount;
spliter.HeightSplitCount
= DefaultHeightSplitCount;
spliter.Init();
return new SampleVector<Int32>(spliter.ValueList);
}

protected static SampleVector<Int32> CreateYNormalSampleVector(Bitmap bitmap)
{
ImageSpliter spliter
= new ImageSpliter(bitmap);
spliter.WidthSplitCount
= 1;
spliter.HeightSplitCount
= DefaultHeightSplitCount;
spliter.Init();
return new SampleVector<Int32>(spliter.ValueList);
}

protected static SampleVector<Int32> CreateXNormalSampleVector(Bitmap bitmap)
{
ImageSpliter spliter
= new ImageSpliter(bitmap);
spliter.WidthSplitCount
= DefaultWidthSplitCount;
spliter.HeightSplitCount
= 1;
spliter.Init();
return new SampleVector<Int32>(spliter.ValueList);
}

public static String Classify(String imageFileName)
{
Log.Debug(
"识别文件:" + imageFileName);

String result
= String.Empty;
if (DefaultChineseCharClassifier == null || DefaultEnglishAndNumberCharClassifier == null) throw new Exception("识别器未初始化.");
using (Bitmap bitmap = new Bitmap(imageFileName))
{
BitmapConverter.ToGrayBmp(bitmap);
BitmapConverter.Binarizate(bitmap);
IList
<Bitmap> mapList = BitmapConverter.Split(bitmap, DefaultCharsCount);

if (mapList.Count == DefaultCharsCount)
{
Bitmap map0
= BitmapConverter.TrimHeight(mapList[0], DefaultHeightTrimThresholdValue);
TrainPattern
<Int32> tp0 = CreateTainPatternVector(map0, " ");
String sv0Result
= DefaultChineseCharClassifier.Classify(tp0);
Console.WriteLine(
"识别样本: " + tp0.Sample.ToString());
result
+= sv0Result;
for (int i = 1; i < mapList.Count; i++)
{
Bitmap mapi
= BitmapConverter.TrimHeight(mapList[i], DefaultHeightTrimThresholdValue);
TrainPattern
<Int32> tpi = CreateTainPatternVector(mapi, " ");
Console.WriteLine(
"识别样本: " + tpi.Sample.ToString());

if (i < mapList.Count - 3)
result
+= DefaultEnglishAndNumberCharClassifier.Classify(tpi);
else
result
+= DefaultNumberCharClassifier.Classify(tpi);
}
}

return result;
}
}

/*
public static IList> ComputeDistance(String imageFileName)
{
if (DefaultChineseCharClassifier == null) throw new Exception("识别器未初始化.");
using (Bitmap bitmap = new Bitmap(imageFileName))
{
ImageSpliter spliter = new ImageSpliter(bitmap);
spliter.WidthSplitCount = DefaultWidthSplitCount;
spliter.HeightSplitCount = DefaultHeightSplitCount;
spliter.Init();

SampleVector sv = new SampleVector(spliter.ValueList);
return DefaultChineseCharClassifier.ComputeDistance(sv);
}
}
*/
}

2009年2月4日星期三

OpenCV 关于adaboost的一些说明 [转贴]

上学期拿出一部分时间来做adaboost,做的时候做了一些笔记。论坛上也有一些正在读程序研究算法的人。我就把这份粗糙的笔记拿出来与大家分享一下吧。肯定有错误的地方,也有不妥当的地方,大家不要太相信我

还有这个地方不能贴公式,不能贴图片,还有我很懒,就挑了几幅重要的贴了,其他的大家去看文章吧

排版不好看,也许写得也不明白,大家多包涵,希望大家可以完善这个文档。让后来者少走些弯路。

不用发论坛消息问我,发在这里让更多人看见,更多人解答,然后也可以让更多的人知道,更好些

第一部分:算法的产生

1996 年Yoav Freund在Experiments with a New Boosting Algorithm中提出了AdaBoost.M1和AdaBoost.M2两种算法.其中,AdaBoost.M1是我们通常所说的Discrete AdaBoost;而AdaBoost.M2是M1的泛化形式.该文的一个结论是:当弱分类器算法使用简单的分类方法时,boosting的效果明显地统 一地比bagging要好.当弱分类器算法使用C4.5时,boosting比bagging较好,但是没有前者的比较来得明显.

文献中记录的.M1算法
初始
1.获得一组样本(X)和它的分类(Y)和一个分类器(weaklearn).
2.赋予平均的权值分布D(i)
进入循环:T次
1. 赋予弱分类器权值D(i),使用弱分类器获得样本(X)到分类(Y)上的一个映射.(就是把某个X归到某个Y类中去)
2. 计算这个映射的误差e.e=各个归类错误的样本权值之和.如果e>1/2那么弱分类器训练失败,挑出循环,训练结束(这在二值检测中是不会发生的,而多值的情况就要看分类器够不够强健了)
3. 设B = e / ( 1 - e ).用于调整权值.因为e<1/2.因此0<1 src="http://www.shineblog.com/UploadFiles/2008-10/1015342616.jpg" alt="图片">

树节点结构:
typedef struct CvTreeCascadeNode
{
CvStageHaarClassifier* stage; // 指向该节点stage强分类器的指针

struct CvTreeCascadeNode* next; // 指向同层下一个节点的指针
struct CvTreeCascadeNode* child; // 指向子节点的指针
struct CvTreeCascadeNode* parent; // 指向父节点的指针

struct CvTreeCascadeNode* next_same_level;//最后一层叶节点之间的连接
struct CvTreeCascadeNode* child_eval; //用于连接最终分类的叶节点和根节点
int idx; //表示该节点是第几个节点
int leaf; //从来没有用到过的参数
} CvTreeCascadeNode;

这 里需要说明的是child_eval这个指针,虽说人脸检测是一个单分类问题,程序中的maxtreesplits的设置值为0,没有分叉,但是树本身是 解决多分类问题的,它有多个叶节点,也就有多个最终的分类结果。但是我们使用的时候,虽然是一个多分类的树,也可能我们只需要判断是或者不是某一类。于是 我们就用root_eval和child_eval把这个分类上的节点索引出来,更方便地使用树结构。当然,这一点在本程序中是没有体现的。

分类器结构:
每 个树节点中都包含了一个CvStageHaarClassifier强分类器,而每个CvStageHaarClassifier包含了多个 CvIntHaarClassifier弱分类器。当CvIntHaarClassifier被使用的时候,被转化为 CvCARTHaarClassifier,也就是分类树与衰减数分类器作为一个弱分类器。

typedef struct CvCARTHaarClassifier
{
CV_INT_HAAR_CLASSIFIER_FIELDS()

int count; /* 在决策树中的节点数 number of nodes in the decision tree */
int* compidx; //特征序号
CvTHaarFeature* feature; //选出的特征。数组
CvFastHaarFeature* fastfeature;

float* threshold; /* array of decision thresholds */
int* left; /* array of left-branch indices */
int* right; /* array of right-branch indices */
float* val; /* array of output values */
} CvCARTHaarClassifier;

CvCARTHaarClassifier结构中包含了弱分类器的左值右值阈值等数组,在我们的程序中CART只选用了一个特征进行分类,即退化成了stump。这里的数组里面就只存有一个元了

那么这里为什么要使用一个如此复杂的结构呢。大体来说有两个好处:
1、 方便弱分类器之间的切换,当我们不选用CART而是其他的弱分类器结构的时候,就可以调用CvIntHaarClassifier时转换成其他的指针
2、 这样方便了Haar训练的过程和Boost过程的衔接。

特征的结构:
图片

2.OpenCV的HaarTraining程序中一种常用的编程方法:
在这个程序中,函数指针是一种很常用的手法。函数指针的转换使读程序的人更难把握程序的脉络,在这里举一个最极端的例子,来说明程序中这种手法的应用。

我们在cvBoost.cpp文件中的cvCreateMTStumpClassifier函数(这是一个生成多阈值(Multi-threshold)stump分类器的函数)下看到了一个这样的调用:
findStumpThreshold_16s[stumperror](……….)
这里对应的stumperror值是2

在cvboost.cpp中我们找到了一个这样的数组
CvFindThresholdFunc findStumpThreshold_16s[4] = {
icvFindStumpThreshold_misc_16s,
icvFindStumpThreshold_gini_16s,
icvFindStumpThreshold_entropy_16s,
icvFindStumpThreshold_sq_16s
};
这个数组的类型是一个类型定义过的函数指针typedef int (*CvFindThresholdFunc)(…..)

因此这个数组中的四项就是四个指针,我们在cvCreateMTStumpClassifier中调用的也就是其中的第三项icvFindStumpThreshold_entropy_16s。

然后我们发现这个函数指针没有直接的显性的实现。那么问题出在哪里呢?
它是通过宏实现的:
程序中定义了一个这样的宏:
#define ICV_DEF_FIND_STUMP_THRESHOLD_SQ( suffix, type )
ICV_DEF_FIND_STUMP_THRESHOLD( sq_##suffix, type,
/* calculate error (sum of squares) */
/* err = sum( w * (y - left(rigt)Val)^2 ) */
curlerror = wyyl + curleft * curleft * wl - 2.0F * curleft * wyl;
currerror = (*sumwyy) - wyyl + curright * curright * wr - 2.0F * curright * wyr;
)

和一个这样的宏:
#define ICV_DEF_FIND_STUMP_THRESHOLD( suffix, type, error )
CV_BOOST_IMPL int icvFindStumpThreshold_##suffix(…..)
{
……..
}

这两个宏中,后者是函数的主体部分,而函数的定义通过前者完成。即:
ICV_DEF_FIND_STUMP_THRESHOLD_ENTROPY( 16s, short ),这样的形式完成。这相当于给前者的宏传递了两个参数,前者的宏将第一个参数转换成sq_16s后和第二个参数一起传到后者的宏。(##是把前后两个 string连接到一起,string是可变的两,在这里suffix就放入了16s和sq_结合成了sq_16s)
后者的宏接收到参数以后就进行了函数的定义:
CV_BOOST_IMPL int icvFindStumpThreshold_sq_16s

这样icvFindStumpThreshold_sq_16s就被定义了。这样做的好处是,12个非常相似的函数可以通过两个宏和12个宏的调用来实现,而不需要直接定义12个函数。

3.训练结果中数据的含义:
-
-
<_>6 4 12 9 -1.
//矩阵。前四个数值是矩阵四个点的位置,最后一个数值是矩阵像素和的权值
<_>6 7 12 3 3.
//矩阵。前四个数值是矩阵四个点的位置,最后一个是像素和的权值,这样两个矩阵就形成了一个Haar特征

0 //是否是倾斜的Haar特征

-0.0315119996666908 //阈值
2.0875380039215088 //小于阈值时取左值
-2.2172100543975830 //大于阈值时取右值



4. 训练过程中使用的算法
这里主要讲弱分类器算法

•矩形特征值:Value[i][j], 1≤i≤n代表所有的Haar特征,1≤j≤m代表所有的样本
•FAULT = (curlerror + currerror)表示当前分类器的错误率的最小值,初始设置:curlerror currerror= 1000000000000000000000000000000000000000000000000(反正给个暴力大的数值就对了)

图片

2009年1月9日星期五

中国智能交通系统发展框架构想

摘 要:八十年代以来,世界一些发达国家纷纷投入智能交通系统(ITS)的研究与开发,并已形成二十一世纪交通运输系统的发展方向。我国是一个发展中国家,随 着经济的高速发展,城市化、汽车化急速发展,导致交通拥挤、事故增多、环境污染等问题日益恶化。本文针对我国的实际情况,对发展ITS的必要性、紧迫性进 行分析,并对

发展我国ITS的框架提出了设想。

一、中国发展ITS的必要性与紧迫性

1.ITS的概念及其意义

ITS(Intelligent Transportation System)是以信息通信技术将人、车、路三者紧密协调、和谐统一,而建立起的大范围内、全方位发挥作用的实时、准确、高效的运输管理系统。

ITS将有效地利用现有交通设施、减少交通负荷和环境污染、保证交通安全、提高运输效率、促进社会经济发展、提高人民生活质量,并以推动社会信息化及形成新产业受到各国的重视。目前已形成世界二十一世纪的发展方向。

2.发展中国ITS的必要性 1)中国是一个经济持续发展的发展中国家,改革开放以来,城市化与汽车化发展十分迅猛。改革开放前,城市化水平不足19%,目前已经发展到超过30%,预 测2010年将接近50%;机动车拥有量目前已达6000万辆,并以每年10%以上的速度增长,预计2010年达到1.3亿多辆;

2)中国城市交通的特点是混合交通,目前自行车拥有量超过1.8亿辆,如果公共交通服务水平不提高,城市交通结构不改善,自行车拥有量将会有增无减;

3)改革开放以来,中国道路交通设施及管理设施虽然有较大改观,但跟不上机动车增长速度。总体水平与发达国家有较大差距,特别是大多数城市路网结构不合理,道路功能不完善,道路系统不健全。

交通管理设施缺乏,管理水平不高。即使各地都建立了交通控制中心,大多只是实现了监视功能,而远没有发挥控制功能的效应;

4)中国城市的大气质量恶化,已逐步由无烟煤污染转变为机动车尾气污染。其主要原因是交通拥堵、车速下降以及车况差、车辆技术性能低等,致使在世界 十大空气污染最严重的城市中,我国就据之有七。同时,车辆状况差也直接影响到城市交通,并已成为制约我国城市交通的重要因素。以车况较好的北京市为例,平 均日故障次数达500次以上,给城市交通带来巨大压力。

二、中国发展ITS的主导思想

从上述必要性与紧迫性分析得到如下结论:

1.中国是一个发展中国家,与发达国家相比,我国在发展ITS的必要基础条件上还有较大差距,加上我国特有的混合交通特点,以及城市结构、路网结构、交通结构的不完善,因此要结合中国的国情来研究制定我国发展ITS的战略及发展框架;

2.中国交通运输正面临经济发展与资源制约的双重压力,因此也不能重复发达国家走过的老路,一定要立足本国实际,走中国ITS发展之路,以推动我国信息化进程及培育自己的ITS产业;

3.二十一世纪交通管理的发展趋势必将是管理体制的集约化;管理设施现代化;管理手段网络化、信息化、智能化;管理效率高效化;管理方式社会化。因此中国ITS的发展将带来一场交通管理体制与模式的变革,而这种变革将直接影响着ITS的发展。

三、中国发展ITS的目标及基本框架

综上所述,中国ITS的发展框架应逐步实现以下三个阶段目标:
(一)前期阶段(5年)
1.目标
缓解交通需求矛盾,提高交通通行能力,减少中心区交通负荷。

2.措施

1)完善道路网系统功能,实施主干道(含快速路)的交通监控;
2)加强交通需求管理(TDM),实施中心主要道路的收费管理,缓解中心区交通压力;
3)减少路口非机动车干扰,实施机动车—非机动车时空分离及对自行车实行IC卡管理;
4)路口渠化。实施信号灯优化配时及多相位信号控制;
5)提高公交服务水平。吸引一部分交通量,实施公交优先道路及优先信号;
6)公交线路网智能调度系统及信息服务系统。该系统运用GPS和计算机技术、信息网络技术实施运行起讫点的调度,运行期间的控制、突发事件的处理,并向乘客提供实时的车辆运营情况,车辆间隔时间等服务信息;
7)建立城市机动车紧急救援系统。机动车突发故障是目前造成我国城市交通拥堵的重要原因,及时、有效地处理故障将大幅度减轻交通堵塞的发生。依靠成熟的GPS定位技术、通信技术、计算机网络技术,并利用城市现有厂、站、救援车辆资源,再加以适当扩充,可以很快形成生产力;
8)严格执法,加强违章处理,实施电子抓拍和电视监视等科技手段;
9)开展动态交通分配理论方法研究,实施集中式交通控制系统软件的开发。

3.目的
该阶段的目的是充分利用现有条件,主要解决中心区交通拥堵,有目的地改进交通控制中心监控系统,改善交通结构,减少交通需求,为ITS创造必要的技术条件和交通环境。

4.阶段任务
该阶段同时要完成以下任务:
1)ITS标准化的制定;
2)ITS相关部门完成本行业ITS发展规划及信息化建设目标;
3)加强宣传、教育,发动有关企业开展ITS开发;
4)加强国际交流,了解国际ITS的动态,消化、吸收国际先进技术,研发我国ITS技术及产品;
5)进行ITS示范工程建设,推广应用ITS技术;

(二)发展阶段(10年)
1.目标
在综合信息网络平台下,形成信息管理、信息通信、信息服务子系统,实现交通信息双向交互;实施交通指挥、控制,达到减少堵塞时间、降低交通事故、出行便捷及保护环境的目的。

2.措施
初步建设以下各系统:
1)城市信息管理系统
该系统按城市GIS数据库、信息网络、车辆管理信息等分步建设,不仅为ITS系统提供直接相关的动、静态信息,同时也为未来城市发展提供各项信息服务。
2)道路交通信息通信系统
该系统由信息采集、信息处理及信息发布三部分组成。
信息采集:实时采集交通拥挤、事故发生、道路施工、气候变化及停车泊位等信息。
信息处理、分析:采集的各项信息经交通信息中心进行处理和分析。
信息发布:将经过整理的实时信息及分析后的预测信息通过无线通信、有线广播、电子显示屏、net网,车载器向出行者及驾驶员发布。
3)微波接入网系统
该系统与交通管理监控系统及交通管理信息系统联网,提供开放式联网支持,通过车载单元(微波标识卡)和路边单元(微波天线及其控制器)有效地采集交通数据,提供信息及交通控制。
4)网络下的电子收费系统
该系统是车路间信息通信系统,通过微波通信技术实行不停车收费。该系统将在全区域内实现收费路网“一卡通”。
5)多式联运管理服务系统
该系统采取计算机网络技术将各交通方式的运费、管理、服务系统联网,为客、货运输提供联运服务,提高效率和管理水平。

3.目的
该阶段的目的是信息通信网络化,建立信息通信平台,实行人、车、路之间相互传递实时、准确信息。

4.阶段任务
该阶段需要同时完成以下任务:
1)ITS相关部门在信息平台建设中,要统一规划,联合攻关;
2)形成产、学、研一体化,推进信息产业的开发和产品研制;
3)加快智能车辆的研制生产,以适应ITS发展对汽车技术提出的要求;
4)有指导性地抓好示范工程;
5)国际间的交流与合作。


(三)成熟阶段(10年)
1.目标
以ITS的发展推动信息化社会的进程,创立新产业,开拓新市场。

2.措施
1)完善交通基础设施,并达到世界发达国家现有水平;
2)在城市综合交通实现规划、管理、运营智能化的基础上,逐步实现全国各交通方式的综合运输规划、管理运营智能化;
3)城市交通结构趋于合理,公交运量占较大比重;
4)完成车间通信系统;
5)成批生产电动汽车、环保车辆及智能车辆;
6)建立社会化信息服务系统;
7)形成ITS新产业。


3.目的
1)建立一种大范围内、全方位发挥作用的实时、准确、高效的智能化运输综合管理系统;
2)实现科教兴国和社会可持续发展的战略目标;
3)推动人类迈进信息化社会。

四、结 语

本文从我国的实际情况出发,提出了我国ITS发展的框架设想,计划用5个5年计划的时间实现ITS的发展目标。设想必定会存在主观臆想或脱离实际, 仅作为抛砖引玉,引起大家讨论。设想虽然对其中的技术关键没有过多涉及,但技术问题也非常重要,是一只到达设想彼岸的船。因此,也望相关专业的同行一起讨 论,共谋大计。

我们一直认为在技术上,我们国家绝不比其他国家落后,虽然在发展ITS的基础条件上远不如发达国家,但只要坚持“两弹一星”的创业精神,一定会实现工业化的宏伟蓝图。

参考文献

1. 陆化普,史其信. 智能交通系统研究发展动向与启示. 科技导报,1996,第10期
2. 史其信. 中国道路交通的现状与ITS研究展望. 第一届亚太地区ITS会议(东京), 1996.10
3. Shi Qixin. The Present Situation of Road Transportation and Expectation of ITS Researches in China. 3rd World Congress on ITS,Orlando,Sep.1996
4. 陆化普,史其信. 智能交通发展趋势与我国的发展战略. 97’北京智能交通发展趋势国际学术研讨会论文集,人民交通出版社,1997.4
5. 陆化普,史其信. ITS-新一代道路交通系统. 公路交通科技,1997年,第14期
6. 史其信,陆化普. 中国的ITS的研究现状与发展趋势. 第二届亚太地区ITS会议(澳大利亚),1997.7
7. 史其信,陆化普. 智能交通系统的关键技术及研究发展策略. 中国土木工程学会第八届年会论文集,清华大学出版社,1998.3
8. Shi Qixin,Lu Huapu. The Conceivability of the ITS Development Strategy in China. 5th World Congress on ITS,Seoul,Oct.1998

原作者: 史其信

2009年1月7日星期三

车牌字符的识别常用的一些算法

第五章车牌字符的识别
§5.1常用的一些算法
1.
国内外车牌自动识别应用技术
应用图像处理技术对各类机动车和车牌号进行识别是目前现代交通管理中的一
个非常重要的研究课题,车辆监控和管理的自动化、智能化在交通系统中具有十分重
要的意义,车辆自动识别系统能广泛应用于公路和桥梁收费站、公路流量观测站、城
市监控系统、港口和机场等车牌认证的实际交通系统中,以提高交通系统的车辆监控
和管理的自动化程度。发达国家车牌自动识别系统在实际交通系统中已取得了成功的
应用,而我国在车牌自动识别系统方面的开发和应用还处于起步阶段,主要原因在于
识别速度这一瓶颈限制了其应用和推广。
2.
神经网络
“人工神经网络”(枷FIcL址NEuRAL
NETwORK,简称A.N.N.)是在对人脑
组织结构和运行机制的认识理解基础之上模拟其结构和智能行为的一种工程系统。上
世纪40年代初期,心理学家Mcculloch、数学家Pitts提出了人工神经网络的第一个
数学模型,开创了神经科学理论的研究时代。神经网络具有并行计算,分布式信息存
贮容错能力强以及具备自适应学习功能等优点。
3.
遗传算法
遗传算法是基于自然选择和基因遗传学原理的搜索算法,它将“适者生存”这一
基本进化理论引入串结构,并且在串之间进行有组织但又随机的信息交换。它是优化
理论中的一种算法,模仿生物进化的过程来逐步达到最好的结果,是一种全局随机寻
优算法。标准的遗传算法通常包括以下三个基本操作:复制、交叉和变异。遗传算法
的中心问题是鲁棒性。所谓鲁棒性是指能在许多不同的环境中通过效率及功能之间的
协调平衡以求生存的能力。人工系统很难达到如生物系统那样的鲁棒性。遗传算法正
是吸取了自然生物系统“适者生存”的进化原理,使它能够提供一个在复杂空间中基
本上不需要什么限制性的假设,如连续导数存在及单峰等。车辆牌照的分离是一个寻
找最符合牌照特征的区域的过程,从本质上讲就是一个在参量空间里寻找最优定位参
量的问题。而寻找参量空间的全局最优解用遗传算法可以较好的实现。
4.
模板匹配
使用模版匹配的方法,首先就是要确定模版大小,确定大小以后,要建立模板确
定完模板要设定一个相似度函数,对于每个要进行识别的字符,使用相似度函数分别
计算和每个模版字符之间的距离。距离最小的即为该字符的所对应的字符。这种方法
识别速度快,但误识率高。

智能识别市场现状及未来几年发展趋势

来源:中国安全防范行业网 作者:语馨 收编 发布时间:2007-7-30 11:02:55 字体[]
关键词:智能识别 生物识别 识别技术 智能化
摘 要:智能识别领域的热点产品和技术发展的现状 及未来几年发展趋势
目前,国内已建有100多万个各类风险等级的安防系统,每年新建和改建的各类安防系统超过了20万个,其中金融营业场所就有5万多个,住宅小区 有1万多个;此外,全国现拥有2000多家报警运营服务企业,入网总用户已达100多万户。随着我国“平安城市”建设的深入,我国安防市场的需求将进一步 提高,成为继美国之后全球第二大安防市场。

技术方面的突飞猛进也为安防产业的发展提供了强大的动力,60年代视频图像技术、70年代计算机数字技术、80年代生物识别技术以及90年代国际互联网技术的应用使安防行业得到快速发展。

2008年的北京奥运会和2010年的上海世博会为中国安防市场提供了巨大的商机,而中国持续不断的建设高潮也为安防市场的稳定发展提供了最坚实的基础。

智能识别领域的热点产品和技术发展的现状

近 年来,全程数字化、网络化的视频监控系统优势愈发明显,其高度的开放性、集成性和灵活性,为整个安防产业的发展提供了更加广阔的发展空间,而智能视频监控 则是网络化视频监控领域最前沿的应用模式之一。智能视频监控以数字化、网络化视频监控为基础,但又有别于一般的网络化视频监控,它是一种更高端的视频监控 应用。视频监控中所提到的智能视频技术主要是指:“自动的分析和抽取视频源中的关键信息。”如果把摄像机看作人的眼睛,而智能视频系统或设备则可以看作人 的大脑。智能视频技术借助计算机强大的数据处理功能,对视频画面中的海量数据进行高速分析,过滤掉用户不关心的信息,仅仅为监控者提供有用的关键信息。智 能视频监控系统能够识别不同的物体,发现监控画面中的异常情况,并能够以最快和最佳的方式发出警报和提供有用信息,从而能够更加有效地协助安全人员处理危 机,并最大限度的降低误报和漏报现象。

以往使用传统模拟技术的视频监控产品,画质粗糙、录像滞后,严重影响了监控质量并 无法充分发挥智能监控效用;随着信息技术的发展,视频监控产品已由模拟化时代步入数字化时代,在与IT产业、电信产业融合之后,压缩存储、人脸识别、智能 检索以及网络传输技术也应用在了视频监控产品中,使之功能和质量都得到了提升。随着技术的进步,除了安全防范,智能预警、自动报警、联网报警等也将成为安 防产品的最新功能。

在世界反恐斗争日趋严峻的今天,智能视频监控显然能够成为应对恐怖主义袭击和处理突发事件的有力辅助工具。此外,智能视频监控还可以应用在交通管理、客户行为分析、客户服务等多种非安全相关的场景,以提高用户的投资回报。

智能识别市场未来发展趋势

未来几年中国智能识别市场发展趋势会主要有以下几个方面:

市场:由垄断型转向多元竞争

前 几年,由于智能化市场处于起步阶段,进入这个领域的企业不多,少数产品垄断这个市场。随着近年来国际局势的变化,反恐的形式发展,智能识别市场这个蛋糕越 来越庞大,由于市场利润丰厚,越来越多的资金进入这个领域,后入者凭借资金优势和技术引进,将使智能识别市场由暴利转化为利润平均化,竞争将会越来越激 烈,只有那些掌握着核心技术和产品标准化的企业成为竞争的最大赢家。

用户:由特殊部门专用转向社会化

以 前,智能识别产品的用户大多集中在公安、安全、银行等特殊部门或行业,而很少涉及到通用领域。随着社会发展和治安形式的严峻,越来越多的普通行业需要智能 识别技术及产品,诸如智能家居,具有人脸识别功能的智能玩具,游戏互动等。智能识别领域由特殊行业客户向普通消费者转变将是大势所趋,成为不可阻挡的潮 流。

应用:由孤立使用转向网络化应用

现在的智能识别几乎都停留在单一识别上,不管是智能门禁还是智能监控,能与互联网相通的还不多,但是随着网络传输技术的发展,大容量、高速度传送将不再遥远,3G技术的成熟,将有越来越多的智能识别数据可以通过手机实时传输。
技术文章投稿、合作信箱:yktchina-admin@163.com

2009年1月6日星期二

车牌识别技术在城市交通管理中的应用

来源:eNet硅谷动力 作者:杨帆
关键词:车牌识别 识别技术 交通管理 卡口系统 车牌自动识别 治安卡 车辆监控
摘 要:随着识别技术的不断成熟,许多原来使用于特殊行业的技术也出现在了我们的日常生活当中,其中人面识别和指纹识别已经在出入口管理中获得广泛应用。在公安交管领域,车牌识别也逐渐被应用在城市交通管理系统中。
  随着识别技术的不断成熟,许多原来使用于特殊行业的技术也出现在了我们的日常生活当中,其中人面识别和指纹识别已经在出入口管理中获得广泛应用。在公安交管领域,车牌识别也逐渐被应用在城市交通管理系统中。

  下面,就车牌识别技术在治安卡口中的具体应用做一些介绍:

  车牌识别技术作为辅助交警的工具,它就需要在对违章车辆的现场捕获、识别信息的网络传输和中心控制管理等方面满足交警的工作方式。这就要求整个系统的设计也要符合交通行业的各种需求。

  首先,整个系统包括的设备应该有:

  1、前端采集、识别设备
  2、网络传输设备
  3、指挥中心信息管理设备

车牌识别技术系统图

  在实际工作时,前端采集系统接收到车辆触发信号后采集车辆图像,然后由管理软件调用识别软件DLL动态联接库,并将车辆图像按照约定的通信标准传给动态库,动态库识别车牌照,将识别结果返回管理软件。


车牌识别整体网络结构

  系统可以通过有/无线通信方式的标准网络拓扑结构和TCP/IP协议,在物理网络连通后,运行安装盘,即可将连接在网络上的所有工作站定义成为 最多3个网络级,每一个网络级分两层结构,即车道现场识别工作站(底层)与服务端工作站(上层),底层与上层之间的通信带宽要求不低于128k,各网络级 之间的通信带宽要求不低于2M。第一个网络级(最低级)最多可以定义8个服务端工作站和管理128个车道的数个现场识别工作站。第二个网络级(中间级)可 以定义8-32个第一网络级系统,即定义最多32x8个服务端工作站以及管理32x128=4096个车道的数个现场识别工作站,参见网络拓扑结构图。第 三个网络级(最高级)的系统构成,可以由用户需求决定。

中心联网系统集车牌自动识别,中心联网运行为一体,以指挥中心为核心,形成分布式网络系统。中心联网系统的任务是中心管理系统与各个车道应用管理系统进行实时数据交互,实现整个网络系统的远程管理和维护。

  其次,当车牌识别使用在特定的系统中时,也需要有特定的应用需求,我们也城市治安卡口系统为例。

  城市治安卡口是城市的出入动脉,每天都会有大量车辆通过它进出城市。加强对卡口的管理可以有效协助公安机关侦破案件,如从中找到特定的车辆,比如盗抢、肇事逃逸车辆等。

  面对每天如此大的车流量,仅依赖人工记录显然不现实,而车牌识别监控系统就可以有效补充人工的不足。为了保证车牌识别系统的准确性,它至少需要满足以下功能。

  1、指挥中心能够直观明了地显示和监控各个现场车道,并且对经过车辆的捕获率和动态识别率都应达到90%以上。

  2、指挥中心管理系统与各个车道应用管理系统能够进行点对点实时数据交互,能够对各个车道进行点对点以及分布式实时数据查询。

  3、指挥中心能够实时或分时可靠地接收和存储所有车道数据,并具备传输容错功能。

   4、指挥中心能够接收、显示、存储、分发和处理各个车道实时报警信息。当现场经过车辆与公安部公布的被抢、被盗车辆(或其他特殊车辆)相符时,中心将立 即发出声光报警信号提醒指挥人员注意,同时将该车辆相关信息显示大屏幕上,以便指挥人员及时与现场执勤人员联系,进行拦截处理。

  5、指挥中心能够远程管理和维护各车道,包括设置系统软硬件运行参数、查看运行状态和异常信息。

  6、黑名单车辆数据库在整个系统中的自动更新。可与公安网连接,也可以随时导入车辆信息。为处罚打击超速、逆行等严重违章现象提供证据。自动查找被盗、被抢、以及违章拒罚等通缉车辆

  7、各个现场车道系统既能够独立实现现场应用管理功能,又能实现中心网络化管理要求。

  8、具备人工查询、统计、打印、数据导入导出功能。查询需满足指挥人员的要求,按时间、地点、车牌等任意查询。并且统计出任意时段、任意地点的车流量。准确统计公路交通车辆流动情况,为合理调配警力、提高车辆管理水平提供科学依据

  9、系统稳定、可靠。可支持24小时连续工作的能力,并且断电后自动保护,来电后自动重启正常工作。

  10、接入网可以采用多种形式: ISDN、ADSL、GPRS、CDMA、光纤等等。

  现在行业内大多厂商按照这样的功能要求来设计系统,其中天津天地伟业数码科技有限公司的卡口车牌识别监控系统一次性通过无锡公安部交通管理科学研究所检测中心的30余项质量检测,并获得检测部门的高度评价。

  在满足了这些要求后就需要工程人员根据现场环境调试相关设备,最终达到令人满意的效果。相信随着识别技术的不断完善,车牌识别在交通的各个领域都可以发挥它的优势。最终使我们的道路更畅通,社会更繁荣。

2009年1月5日星期一

车牌识别系统在智能交通系统中的应用

来源:中国一卡通网 作者:语馨 收编 发布时间:2008-7-1 9:13:15 字体[]
关键词:车牌识别系统 车牌识别 智能交通 治安卡口系统
摘 要:车辆号牌是全世界唯一对车辆身份识别的标记,它的特殊性和重要性决定了车牌识别系统成为城市智能交通管理系统中不可或缺的重要组成部分。车牌识别系统为自动化的智能交通管理提供了高效、实用的手段。

一、车牌识别概述

车辆号牌是全世界唯一对车辆身份识别的标记,它的特殊性和重要性决定了车牌识别系统成为城市智能交通管理系统中不可或缺的重要组成部分。车牌识别系统为自动化的智能交通管理提供了高效、实用的手段。

目前市场中车牌识别系统主要功能包括:

1、车辆牌照自动识别,信息包括完整的牌照信息,颜色、字符、汉字、数字。
2、车速的自动检测。
3、违法黑牌车辆的识别报警。
4、车辆识别信息与车管所车辆信息的联动控制
5、车辆行驶方向判断监测

目前市场中车牌识别系统主要应用范围包括:

1、交通路口的智能化交通管理
2、交通信息的自动采集
3、警方及其它执法机关设立临时稽查站,对来往车辆实施稽查,优先识别待查车辆;
4、路桥、隧道等卡口的自动收费系统
5、现代住宅小区、停车场、重要机关单位的汽车出入口管理
6、道路治安卡口抓拍识别,车流量监测

车牌识别系统的优劣主要由二个关键性能参数共同决定:识别率、识别速度。

1、识别率

车牌识别系统是否实用,最重要的指标是识别率。国际公认的识别率指标要求是24小时全天候全牌正确识别率85%~95%。识别率的统计也分为以下三种方式:

a、自然流量识别率=识别车牌号的总数/实际通过的车辆总数
b、可识别车牌率=人工正确读取的车牌号总数/实际通过的车辆总数
c、全牌识别准确率=全牌正确识别的车牌总数/人工识别读取的车牌号总数

这三个指标决定了车牌识别系统的识别率。

2、识别速度

识别速度决定了车牌识别系统是否能够满足实时实际应用的要求。一个识别率很高的系统,如果需要几秒钟,甚至几分钟才能识别出结果,那么这个系统就会因为满 足不了实际应用中的实时要求而毫无实用意义。国际交通技术提出的识别速度是1秒以内,越快越好。目前市场的车牌识别系统在实际应用中识别速度平均为200 毫秒。较好的车牌识别系统已经达到了10毫秒的快速识别时间,实际应用识别速度能够达到平均40毫秒。

二、识别技术的实现原理和实现方式

车辆牌照的识别是基于图像分割和图像识别理论,对含有车辆号牌的图像进行分析处理,从而确定牌照在图像中的位置,并进一步提取和识别出文本字符。

识别步骤概括为:车牌定位、车牌提取、字符识别。三个步骤地识别工作相辅相成,各自的有效率都较高,整体的识别率才会提高。识别速度的快慢取决于字符识 别,字符的识别目前的主要应用技术为比对识别样本库,即将所有的字符建立样本库,字符提取后通过比对样本库实现字符的判断,识别过程中将产生可信度、倾斜 度等中间结果值;另一种是基于字符结构知识的字符识别技术,更加有效的提高识别速率和准确率,适应性较强。

车牌识别系统实现的方式主要分为两种:一种是静态图像图片的识别,另一种是动态视频流的实时识别。静态图像识别技术的识别有效率较大程度上受限于图像的抓 拍质量,为单帧图像识别,目前市场产品识别速度平均为200毫秒;而动态视频流的识别技术适应性较强,识别速度快,它实现了对视频每一帧图像进行识别,增 加识别比对次数,择优选取车牌号,关键在于较少的受到单帧图像质量的影响,目前市场产品识别较好的时间为10毫秒。

三、车牌识别在治安卡口系统中的应用

车牌识别系统目前已经成熟应用于各类的智能交通、安防系统中,对图像、视频中的车辆号牌进行自动的检测识别.典型的应用系统为:闯红灯自动监测系统,机动车超速监测系统,机动车逆行、压线监测系统,移动电子警察系统,治安卡口系统等智能交通系统。

较为典型的应用为治安卡口系统(学名:公路车辆智能监测记录系统),该系统如果没有车牌识别技术,就没有真正意义上的自动化智能。一个完善的治安卡口管理 系统应该具备车牌自动识别、卡口应用系统和中心联网管理三个主要功能。车牌识别是其中最为重要的一部分,只有达到快速实用识别技术指标的卡口系统才能有效 的实现自动比对报警,避免出现大量的误报。同时,识别速度快,系统需要占用的系统资源就少、人工介入的可能性就小,系统网络的运行负担也相应减小。车牌识 别的优劣直接影响的卡口系统的整体性能。

保尔安治安卡口系统就充分发挥了车牌识别技术和分布式架构设计的优势,搭建了高效统一的卡口系统平台。具备了汽车图像记录、速度测定、号牌识别、自动报 警、数据管理、流量统计、远程维护等综合性的业务功能,已被广泛应用于国道、省道、高速公路等路路面的交通事故预防和有关车辆案件的侦破。整个系统的运行 都是围绕着车牌号码这个核心,车牌号码识别的高效就直接影响了系统的整体性能。所以该系统前端设计采用了视频流实时识别技术,并且10ms的识别时间充分 保证了高流量道路车辆的一一识别,达到全天候全牌识别率不低于85-95%的国际指标。

随着技术的进步,图像视觉科技的发展,未来的车牌识别技术将会更加的智能化。

2009年1月2日星期五

使我的新年目标成功!

是时候开始规划我的新年目标了吗?

我想,每当大家走到旧一年快要结束时,你脑海中又重现了这个问题——是时候开始规划我的新年目标了吗?说句实话,我们承受了太多的失败,以往这个时候你也计划了新一年的目标,可结果总是不了了之。或许你已经认为新年目标不过是个愿望而已,它根本就不管用!年复一年,不出几个月不是忘得干干净净,就是一甩便放弃了。

为什么新年目标看起来不成功?

想像一下:在年终庆祝会上,一位好友蹭了过来跟你聊天:“你明年有什么打算?”你根本就还没有认真地考虑过,所以只好含糊地回答:“哦,嗯,我,打算跳槽到另外一个行业去。”

于是,在剩下的时间里,你就开始盘算自己的新年目标到底是什么,考虑到这个目标给你带来的好处和将遇到的困难。可是庆祝会结束回到家后,你就立马倒到床上,第二天早上起来什么都忘记了。

你明白了吗?我们从来没有真正地、认真地考虑过自己的新年目标。最少,你没有安静地坐下来,拿起笔和纸开始规划。你甚至觉得这根本不值得花时间去为新年目标制定详细的蓝图。更多是,你只是花了几分钟随便想想罢了。

当你在计划上失败时,你就是在计划自己的失败。以那样的态度去计划新年目标,你还能怎么期望去实现它?所以,并不是新年目标不起作用,而是自己没用 心。仔细地想想,你规划新年目标的目的是什么?是去引导自己未来的正确方向?还是督促自己远离错误的目的地?或者展现自己的雄心壮志?也许只是为了塞满自 己内心空虚的不满?

我要使我的新年目标成功!

你难道不想使你的新年目标能够真实落实下来,取得成功吗?

同弥缝一起参加褪墨的新年目标成功计划!我们说到做到,不是美好的愿望,而是一个要实现的目标。一年以后,你敢重新来到这儿,自豪地说我实现这些目标吗!

在这里,或者你的博客上写下你的新年目标和如何实现它们(并且TrackBack)——可以是自己事业上的目标、博客目标等等。弥缝将把所有的文章和留言全部集合起来,一年以后我们再回过头来看自己是否达到了目标。

弥缝已发表《如何规划成功的新年目标》和《2008年褪墨新年目标展望

博客串联,弥缝点名:Hugh(杂乱的书桌)、sofish(幸福收藏夹)、yiyix(逝水年华)、杨远骋(三秒钟改变世界)、邹鑫(GTD Life)、古道视野LiGhtxiangge(幸福生活)、漫步和所有褪墨链接里面的朋友!

2008年12月31日星期三

科技转型谈何容易! 张五常

要先对毕业的同学说几句话。目前国内的大学毕业同学难找工作,网上有云,其中一些接受零工资。做得对︰只要有值得学习的,接受零工资是正着。希望老板们能审时度势,尽量提供学习机会给毕业生。

青年初出道,论工资不对——不仅是经济困难的今 天。为人师表数十年,我对毕业同学的建议,永远是出道选工作不要论工资,要着重自己的兴趣与知识投资的机会。可惜市道好时这建议不易被接受︰钱作怪也。当 年我不论,今天儿子也不论,占了先机。我和儿子的际遇比今天国内的同学好︰我们不需要养家。需要养家的同学的困境我明白。辛苦一点吧。不要忘记,工作后还 要自修读书的。恨不得还年轻,可以在网上授课。利用互联网教育实在方便。我不成了,希望有识之士能先把自己介绍一下,然后把所知或讲义之类放到网上去。

不是要留难北京的朋友,但要问︰同学接受零工资, 是不是违反了国家的劳动法例呢?说是,要禁止,千夫指不易横眉冷对也。说因为同学自愿,所以不违法,那么任何雇主皆可要求最低工资之下的被雇者签下自愿 书。若说除了工资,其它劳动法则不能自愿,那么工资的弹性开了一处口,其它法则皆可用自愿的工资甚至负工资调校,化为零。

我知道新劳动法放宽了不少,而好些地区不执行。然 而,两个头痛问题仍在。一、不清楚地撤销,阴影还在,投资者不敢下注。二、员工因为此法的存在可以凭法投诉,弄得劳资双方的关系今天是改革以来最差的。新 劳动法可能对某些人有利,或对某层面的员工有利。都不肯定,肯定的是最低下阶层的劳工受到损害。今天纷纷倒闭的是我认为对农转工贡献最大的接单工厂,这些 工厂养起很多穷人,而又提供给无数没有学识的劳苦大众有各行各业的学习机会。苦吗?那当然,但穷人那么多,资源那么少,有较好的办法吗?我很不同意那些自 以为是学者的贬低他们认为可笑的血汗工厂,而对认为这些工厂应该被淘汰的言论,反感更大。政府凭什么资格封自己为淘汰大师呢?

说实话,就是北京立刻撤销新劳动法,短期内不会有起死回生之效。一则太迟了,二则地球经济很不对头。面对今天的困境,撤销此法有助,助多助少不要斤斤计较吧。肯定有助就不要再等了。

说到工业转型,要向高科技励进,有谁不懂得说,但谈何容易哉?好些年前我和瑞典的一位经济学者详谈此事,因为该国主要靠科技生存。当时大家的结论,是高科技不可以话搞就搞。瑞典地大人少,一般国民的知识高,也有多年的科技传统。中国没有这些条件。

中国的重要资源是人,学识水平一般低下的人。但千 万不要小看这些人。我认为高科技在中国有得搞,也应该搞,但绝对不是把穷人淘汰出局那种搞法!地球上没有什么资源比人更可贵,而炎黄子孙这个品种,上苍早 就照顾着,认为中国人多所以命贱的想法是不对的。我说过中国人聪明,吃得苦,学得快。论及科学,中国人不仅聪明那么简单,更重要的是想象力强。论智商,地 球上不亚于炎黄子孙的民族有的是,但论到想象力,比得起中国血统的我没有见过。

不知是天生基因使然还是文化传统所致,中国人的想 象力自成一家应无疑问。不需要拿出鬼才李贺了。昔日苏子写《赤壁赋》──逝者如斯,而未尝往也──其想象力的来去纵横,彷佛随意挥洒,其它文化不易读到。 写花,杜牧说「落花犹似坠楼人」,李清照说「人比黄花瘦」。论白发吗?李白「高堂明镜悲白发」,辛弃疾「白发空垂三千丈」。想象免不了有点夸张,但来得那 么新奇而又自然,我认识的西方文化不多见。中国的文化呢?想象是惯例。

想象力是科学研究最重要的──爱因斯坦这样说过。 昔日学而优则仕的传统无疑扼杀了中国的科学发展,但传统归传统,今天归今天,上苍赐予炎黄子孙的想象本领没有变。另一方面,我们知道这本领不会因为人穷就 没有。我自己的双亲皆出自广东农村的破落户,而四十年前在美国出道时,师友们不少认为我的想象力胜出几条街。在神州大地我可没有这种优越性。然而,论到逻 辑思考与客观辩证,中国人却是输了。输出两条街吧。逻辑推理是可以学的。中国人需要的是教育,是机会。不是说每个穷人都可以杀出重围。成功的机会其实不 高。纵观中国的资源局限,爱莫能助,只是提供自力更生机会的社会成本是零。

转谈科技产出,人的质素当然也要论想象力,但远不 及科学研究那么重要。科技产出是制造,重点是产品质量的调控。这方面我们真的比较弱。有两点。其一是中国人不够清洁。其二,虽然中国人的手工艺无敌天下, 但奇怪地产品规格需要一致的要求,目前看中国比不上日本或韩国那么稳定。可能是风俗习惯使然,更肯定是教育出了问题。

要在中国大幅提升产品的科技水平,三个要素不可或 缺。其一是工人的知识水平要大幅提升。工程方面中国基本上没有问题,设计也可以,困难在于一般工人知识不足。需要细节严格、精确的产品,中国人做得不够 好。认识做厂的朋友无数,很多外地的优质产品,他们不是不懂得造,而是做不到,或成本要比进口的高。

第二个要点,是中国目前在商标、商业秘密、发明专 利等法律上还有好一段路要走。改进了很多,但还有不能漠视的不足之处。思想或知识产权的保障历来困难,就是先进之邦也头痛。是非常复杂的学问。七十年代初 期,受美国科学研究基金的委托,几个助手和我花了几年时间研究发明专利与商业秘密。一九七七年五月我写下很长的研究报告(见《张五常英语论文选》,第二十 章,《产权与发明》)。当时的同事与资助基金认为是全面而又深入的,促我继续,但题材实在太难,放弃了。今天在国内管理知识产权的朋友不妨细读这篇长文, 问题所在是说清楚了的。中国不一定要仿效西方的知识产权法律与执行的方法,考虑要点及西方遇到的困难会有助。

第三个要点,是工业科技的上升一般是由他人推上去 的。以西方为例,发明专利的注册一定要详细地公开,专利权只十七年。要持久地维护这专利,发明者要不断地继续研究、改进,希望再获其它有关的发明专利,使 十七年后自己的原先发明被自己的新发明替代了。然而,原先的发明早就公开了,其它竞争者也会研究,也会改进,有机会得到改进的注册而捷足先登。

后浪推前浪永远是科技发展得好的程序。这就带来为 什么我认为在中国的资源局限下,接单工业是那么重要了。我说过接单工业可以养起很多人,是农转工的命脉,而每间接单工厂都是一所学校,培训工业人材。这里 要强调的,是接单工厂一般力争上游,希望有自己的商标,有自己的发明专利。这样一来,上头的科技水平较高的就逼着要发愤图强,否则会被下面的淘汰。香港昔 日满是这样的故事。接单接单,到后来可以生存的都有自己的商标,也有自己的发明专利注册。行业的发展也如是。老一辈的朋友应该记得,当年香港的工业以假 发、胶花等雄视地球,后来转到玩具、手表、成衣等工业去,让假发、胶花给其它工资较低的地区造。这是工业转型的应有过程。强迫转型,淘汰了接单工业,是拿 起石头砸自己的脚。

千万不要考李嘉诚先生胶花是怎样制造的!

欢迎访问、交流!对本博客有何建议,请
来信告知!
本博内容来源于网络,如有不当或侵犯权益,请来信告知,将及时撤除!
如引用博客内容、论文,请注明原作者!

Google一下本博客

  • [原]Linux下编译使用boost库 - Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一。 Boost库由C++标准委员会库工作组成员发起,其中有些内容有望成为下一代C++标准库内容。在C++社区中影响甚大,是不折不扣的“准”标准库。Boost由于其对跨平台的强调,对标准C++的强调,与...
    8 年前
  • [原]猎头、培训与咨询的价值(2)【补1】——北漂18年(93) - 【上期用手机写的,同时用语音输入转化成文字,错字较多,经好友霍师傅提醒本期重写,并增加一部分新内容】 简单谈下我对猎头、培训与咨询的看法。三样都干过,算是有些浅见。 猎头 简单的说就是人才中介。虽然在公司看来是可以直接解决现有企业问题的一个直接方法,但很多时候都不太管用。 猎头费一般是人才的一个月月...
    9 年前
  • 我的时间管理道与术(三) - 本系列来自 水中颉 原创投稿。 本文续上篇《我的时间管理道与术(一):接受现实和感知时间》和《我的时间管理道与术(二):目标与计划》。 建立至上而下的检视机制 六个关注层面和检视周期 宗旨和使命、关键路径是云端;关键点和平衡点是方向指导层;项目是最接地气的现实目标层;下一步行动 是非常具体的待执行事务层...
    10 年前
  • OpenCV統計應用-Mahalanobis距離 - Mahalanobis距離是一個可以準確找出資料分布上面極端值(Outliers)的統計方法,使用線性迴歸的概念,也就是說他使用的是共變數矩陣以及該資料分布的平均數來找尋極端值的產生,而可以讓一群資料系統具有穩健性(Robust),去除不必要的雜訊訊息,這邊拿前面共變數矩陣的資料為例,並且新增了兩個點座標向量來做...
    17 年前
  • 努力推进模式识别实际产品的开发与应用 - Salu 无论是手写体识别、文档处理、人脸识别、基于内容的图片搜索、嵌入人工智能的搜索技术、虚拟网络社区、还是其它相关新科技下的信息整合领域,现在都在努力实用化。 前两年、即使现在还有很多人在抱怨说人脸的方法都不能用,但是就今年出现的和正在做的有关人脸识别实际应用的各种形式的产品可以说如雨后春笋。这是一个趋...
    18 年前