精华内容
下载资源
问答
  • halcon学习笔记(14)——模板匹配

    万次阅读 多人点赞 2017-02-01 12:28:42
    halcon的模板匹配种类有很种,方法各有优缺点,一般有基于灰度的匹配,基于形状的匹配等等,这里具体理论和方法再做详解,这里简单总结一个实例。图像匹配一般需要对旋转放缩进行处理,另外为了提高搜索效率,常用...

    halcon的模板匹配种类有很多种,方法各有优缺点,一般有基于灰度的匹配,基于形状的匹配等等,这里具体理论和方法不做详解,只简单总结一个实例。图像匹配一般需要对旋转放缩进行处理,另外为了提高搜索效率,常用用图像金字塔来处理模板图像,图像金子塔就是把图像按一定算法,缩小为不同比例的模板,减少像素。一般的模板匹配流程如下:

     

    所以首先创建模板,模板的创建就是采集一张自己需要的原始图像,如下我采集的原始图像:

     

    我需要的是银联那个标志,生成模板的源代码如下:

    read_image (Image, 'E:/HalconTest/实验2d匹配/exp/110.jpg')
    *读取模板图像
    rgb1_to_gray (Image, GrayImage)
    *灰度操作
    gen_rectangle1 (ROI_0, 189.5, 531.5, 325.5, 717.5)
    *选择要匹配的图像,去除不必要的
    reduce_domain (GrayImage, ROI_0, ImageReduced2)
    *减少图像,分割出切除的那部分
    bin_threshold (ImageReduced2, Region1)
    *自动灰度阈值处理
    connection (Region1, ConnectedRegions1)
    *求联通域
    select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 8, 14016)
    *选择图像
    reduce_domain (ImageReduced2, SelectedRegions1, ImageReduced3)
    *分割出图像
    inspect_shape_model (ImageReduced3, ModelImages1, ModelRegions1, 4, 30)
    *创建一个形状的表示模型
    create_scaled_shape_model (ImageReduced3, 'auto', rad(-45), rad(90), 'auto', 0.9, 1, 0, 'no_pregeneration', 'ignore_global_polarity', 'auto', 'auto', ModelID)
    *使用用图像创建带有缩放的匹配模板,上面的灰度分割什么的其实可以不要
    *NumLevels 最高金子塔层数
    *AngleStart 开始角度加rad(90)是将弧度制转为角度值
    *AngleExtent 角度范围
    *AngleStep 旋转角度步长
    *ScaleMin 模板行方向缩放最小尺度
    *ScaleMax 模板行方向缩放最大尺寸
    *MinScore 最低匹配分值 百分比
    *ScaleStep 步长
    *Optimization 优化选项 是否减少模板点数
    *Metric 匹配度量级性旋转 
    *MinContrast 最小对比度
    *ModelID 生成模板ID
    write_shape_model (ModelID, 'C:/Users/shanwenjun/Desktop/img_model3.shm')
    *生成模板文件
    

    生成的模板文件要用来进行匹配,下面是我用摄像头进行实时匹配的图像:

     

    匹配的的源代码如下,左上角是图像处理过程叠加的:

    dev_close_window ()
    dev_open_window (0, 0, 640, 480, 'black', WindowHandle)
    *先关闭活动图形窗口,再打开这个窗口,标识符为WindowHandle;
    *相对于界面左上角第0行、第0列,大小是我相机的拍照比例,颜色为黑色。
    open_framegrabber ('MindVision11', 1, 1, 0, 0, 0, 0, 'progressive', 8, 'Gray', -1, 'false', 'auto', 'Camera MV-U130RC#C17D8221-3', 0, -1, AcqHandle)
    *DirectShow是笔记本摄像头或者其他DirectShow的摄像头,MindVision11是我相机的摄像头;
    * 注意摄像头的名称,可以用工具栏中的“助手”——打开新的Image Acquisition获取摄像头及插入代码
    
    grab_image_start (AcqHandle, -1)
    while (true)
     grab_image_async (Image, AcqHandle, -1) 
    * Calibration 01: Code generated by Calibration 01
    CamParOriginal:= [0.01629,-2024.24,8.30436e-006,8.3e-006,710.402,361.975,1280,960]
    CameraPose := [-0.0236413,0.0135896,0.152813,16.2821,3.05758,76.5791,0]
    *上面是我相机的标定量,根据自己相机标定填写,此段代码不可直接用
    
    CamParVirtualFixed:=CamParOriginal  
    CamParVirtualFixed[1]:=0  
    *上面是标定时候的参数设置
    
    gen_radial_distortion_map(MapFixed,CamParOriginal,CamParVirtualFixed,'bilinear')  
    *生产径向畸变映射图,  
    *mapfixed是输出,  
    *CamParOriginal是标定后的参数,  
    *CamParVirtualFixed也是输出的参数,  
    *'bilinear'映射类型 
    
    map_image(Image,MapFixed,ImageRectifiedFixed)  
    *利用映射,消除图像畸变算子 
    
    read_shape_model ('E:/HalconTest/实验2d匹配/img_model/img_model3.shm', ModelID)
    *读取图像
    find_scaled_shape_model (ImageRectifiedFixed, ModelID, rad(-180), rad(180), 0.5, 1.2, 0.3, 1, 0.5, 'none', 4, 0.9, Row, Column, Angle, Scale, Score)
    *寻找单个带尺度形状模板最佳匹配
    *ImageRectifiedFixed 要搜索的图像
    *ModelID 模板ID
    *AngleStart 开始角度加rad(90)是将弧度制转为角度值
    *AngleExtent 角度范围
    *ScaleMin 模板行方向缩放最小尺度
    *ScaleMax 模板行方向缩放最大尺寸
    *MinScore 最低匹配分值 百分比
    *NumMatches 匹配实例的个数
    *MaxOverlap 最大重叠 在有重叠时也可检测匹配
    *SubPixel 是否亚像素精度
    *NumLevels 金子塔层数
    *Greediness 搜索贪婪度; 0安全慢;1块不稳定;其他就是介于中间值
    *剩下的几个参数是匹配图像的位置状态等参数
    get_shape_model_contours (ModelContours, ModelID, 1)
    *返回匹配结果的轮廓
    
    for I := 0 to |Score| - 1 by 1
        *for循环查找匹配
         vector_angle_to_rigid (0, 0, 0, Row[I], Column[I], Angle[I], HomMat2DRotate)
        *单匹配计算刚性变换矩阵 为了显示匹配图像
         hom_mat2d_scale (HomMat2DRotate, Scale[I], Scale[I], Row[I], Column[I], HomMat2DScale)
         *添加一个扩展到一个均匀的二维变换矩阵 为了显示匹配图像
         affine_trans_contour_xld (ModelContours, ModelTrans, HomMat2DScale)       
         *应用任意二维仿射变换XLD轮廓 为了显示匹配图像
         disp_message (WindowHandle,'匹配一个', 'image', Row[I], Column[I]+100, 'blue', 'true') 
         *添加文本
         dev_display (ModelTrans)
         *显示模型 为了显示匹配图像
    endfor
     
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
    * ****
    * step: destroy model
    * ****
    endwhile
    clear_shape_model (ModelID)


     

    展开全文
  • AC自动机果断是神一样的东西,我赶在比赛前学习还是有用的,AC自动机最基本的是可以解决个模式串在一个长字符串中出现的种类数或次数: 我暂时还是修改大神们的模板的昂 满满个人注释版帮助自己理解版: 1...

    AC自动机果断是神一样的东西,我赶在比赛前学习还是有用的,AC自动机最基本的是可以解决多个模式串在一个长字符串中出现的种类数或次数:

    我暂时还是修改大神们的模板的昂

    满满个人注释版帮助自己理解版:

     

     1 //该程序不能判别相同模式串,因此若模式串重复,答案会将相同模式串当做不同的处理,因此若需要可以用map去重或修改insert
     2 #include<stdio.h>
     3 #include<string.h>
     4 #include<queue>
     5 using namespace std;
     6 const int maxm=500006;    //maxm是总结点数:约为字母数+++
     7 
     8 char s[1000005],word[55];
     9 int nxt[maxm][26],tail[maxm],f[maxm],size;    //nxt是结点指向不同字母的结点下标,tail是表示该结点为几个单词的词尾(可能需要计算重复的模式串情况),f是当不匹配时转跳到的结点下标,size是结点数
    10 
    11 int newnode(){    //初始化整个trie或建立新的结点时,首先初始化当前结点所指向的26个字母的结点为0,表示暂时还没有指向的字母,然后暂定该结点不是单词尾结点,暂无失配时转跳位置(即转跳到根节点),返回结点标号
    12     memset(nxt[size],0,sizeof(nxt[size]));
    13     f[size]=tail[size]=0;
    14     return size++;
    15 }
    16 
    17 void insert(char s[]){    //构造trie,p为当前结点的上一个结点标号,初始为0;x即为当前结点(上个结点标号指向当前字母的结点)标号,若此结点还未出现过,那么就建立这个结点;然后更新p为当前结点标号以便后续操作
    18     int i,p=0;
    19     for(i=0;s[i];i++){
    20         int &x=nxt[p][s[i]-'a'];
    21         p=x?x:x=newnode();
    22     }
    23     tail[p]++;    //此时仅将s串记录,即将s串结尾的结点加1,若无相同模式串,则此操作只会使所有串尾结点的tail值由0变为1,但有相同模式串,则会重复记录,需要去重可以用map或用tail[p]=1;语句来完成
    24 }
    25 
    26 void makenxt(){    //利用bfs来构造失配指针
    27     int i;
    28     queue<int>q;
    29     f[0]=0;    //先将0结点挂的字母加入队列,失配指针指向0结点
    30     for(i=0;i<26;i++){
    31         int v=nxt[0][i];
    32         if(v){
    33             f[v]=0;
    34             q.push(v);
    35         }
    36     }
    37     while(!q.empty()){
    38         int u=q.front();
    39         q.pop();
    40         for(i=0;i<26;i++){
    41             int v=nxt[u][i];
    42             if(!v)nxt[u][i]=nxt[f[u]][i];    //当u结点没有i对应字母,则视为失配,将其指向失配后转跳到的结点所指向的i对应字母
    43             else{
    44                 q.push(v);    //u结点存在指向i的结点,则将所指向的结点下标加入队列
    45                 f[v]=nxt[f[u]][i];    //失配指针指向上个结点失配指针指向结点所挂当前字母的结点
    46             }
    47         }
    48     }
    49 }
    50 
    51 int query(char s[]){    //查询s串中模式串出现了多少种/次
    52     int ans=0,v=0;
    53     for(int i=0;s[i];i++){
    54         while(v&&!nxt[v][s[i]-'a'])v=f[v];    //先匹配直到没有失配
    55         v=nxt[v][s[i]-'a'];
    56         int tmp=v;
    57         while(tmp){
    58             ans+=tail[tmp];
    59             tail[tmp]=0;    //这里加这句是为了仅计算出现多少种模式链,而若不加这句则可以计算累计出现多少次
    60             tmp=f[tmp];
    61         }
    62     }
    63     return ans;
    64 }
    65 
    66 int main(){
    67     int T;
    68     scanf("%d",&T);
    69     while(T--){
    70         int n;
    71         scanf("%d",&n);
    72         size=0,newnode();
    73         for(int i=0;i<n;i++){
    74             scanf("%s",word);
    75             insert(word);
    76         }
    77         makenxt();
    78         scanf("%s",s);
    79         printf("%d\n",query(s));
    80     }
    81     return 0;
    82 }

     

     

     另:加上last数组的版本,last数组可以很大程度上缩短时间,但是也同样要考虑卡空间的问题,另外鹏神也说last比较适用于纯匹配问题,可能套算法的话用处不是非常大:

     

     

     1 // 有nxt数组版本。。该程序不能判别相同模式串,因此若模式串重复,答案会将相同模式串当做不同的处理,因此若需要可以用map去重或修改insert
     2 #include<stdio.h>
     3 #include<string.h>
     4 #include<queue>
     5 using namespace std;
     6 const int maxm=500006;        //maxm是总结点数:约为字母数+++
     7 
     8 char s[1000005],word[55];
     9 int nxt[maxm][26],tail[maxm],f[maxm],size;        //nxt是结点指向不同字母的结点下标,tail是表示该结点为几个单词的词尾(可能需要计算重复的模式串情况),f是当不匹配时转跳到的结点下标,size是结点数
    10 int last[maxm];    //last指针是指向上一个是单词结尾的结点,由于是由失配指针拓展得到的,因此所指向的单词都是该结点表示的单词的后缀单词,但由于可能卡空间,所以虽然可以在时间上优化,但是有时并不使用
    11 
    12 int newnode(){        //初始化整个trie或建立新的结点时,首先初始化当前结点所指向的26个字母的结点为0,表示暂时还没有指向的字母,然后暂定该结点不是单词尾结点,暂无失配时转跳位置(即转跳到根节点),返回结点标号
    13     memset(nxt[size],0,sizeof(nxt[size]));
    14     f[size]=tail[size]=0;
    15     return size++;
    16 }
    17 
    18 void insert(char s[]){    //构造trie,p为当前结点的上一个结点标号,初始为0;x即为当前结点(上个结点标号指向当前字母的结点)标号,若此结点还未出现过,那么就建立这个结点;然后更新p为当前结点标号以便后续操作
    19     int i,p=0;
    20     for(i=0;s[i];i++){
    21         int &x=nxt[p][s[i]-'a'];
    22         p=x?x:x=newnode();
    23     }
    24     tail[p]++;    //此时仅将s串记录,即将s串结尾的结点加1,若无相同模式串,则此操作只会使所有串尾结点的tail值由0变为1,但有相同模式串,则会重复记录,需要去重可以用map或用tail[p]=1;语句来完成
    25 }
    26 
    27 void makenxt(){    //利用bfs来构造失配指针
    28     int i;
    29     queue<int>q;
    30     f[0]=0;
    31     for(i=0;i<26;i++){    //首先将0结点(根节点)连接的字母结点加入队列,并定失配指针和last指针都指向0结点
    32         int v=nxt[0][i];
    33         if(v){
    34             f[v]=last[v]=0;
    35             q.push(v);
    36         }
    37     }
    38     while(!q.empty()){
    39         int u=q.front();
    40         q.pop();
    41         for(i=0;i<26;i++){
    42             int v=nxt[u][i];
    43             if(!v)nxt[u][i]=nxt[f[u]][i];    //当u结点没有i对应字母,则视为失配,将其指向失配后转跳到的结点所指向的i对应字母
    44             else{
    45                 q.push(v);    //u结点存在指向i的结点,则将所指向的结点下标加入队列
    46                 f[v]=nxt[f[u]][i];    //设置这个结点的失配指针指向上个结点失配后的指向字母i的结点,由于bfs一定会从字典树浅层到深层,即从字符串短到长,而失配转跳后表示的字符串长度严格减少,所以只需要指向一次即可
    47                 last[v]=tail[f[v]]?f[v]:last[f[v]];    //若失配指针指向的结点是单词结尾,那么当前结点失配后就可以直接指向失配结点,即失配路径上的上一个单词结点,若失配结点不是单词结尾,就指向失配结点的last
    48             }
    49         }
    50     }
    51 }
    52 
    53 int query(char s[]){    //查询s串中模式串出现了多少种/次
    54     int ans=0,v=0;
    55     for(int i=0;s[i];i++){
    56         while(v&&!nxt[v][s[i]-'a'])v=f[v];
    57         v=nxt[v][s[i]-'a'];
    58         int tmp=v;
    59         while(tmp){
    60             ans+=tail[tmp];
    61             tail[tmp]=0;    //这里加这句是为了仅计算出现多少种模式链,而若不加这句则可以计算累计出现多少次
    62             tmp=last[tmp];
    63         }
    64     }
    65     return ans;
    66 }
    67 
    68 int main(){
    69     int T;
    70     scanf("%d",&T);
    71     while(T--){
    72         int n;
    73         scanf("%d",&n);
    74         size=0,newnode();
    75         for(int i=0;i<n;i++){
    76             scanf("%s",word);
    77             insert(word);
    78         }
    79         makenxt();
    80         scanf("%s",s);
    81         printf("%d\n",query(s));
    82     }
    83     return 0;
    84 }

     

     

     

     

     

    并没有注释复制可以用用用版:

     

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<queue>
     4 using namespace std;
     5 const int maxm=500006;
     6 
     7 char s[1000005],word[55];
     8 int nxt[maxm][26],tail[maxm],f[maxm],size;
     9 int last[maxm];
    10 
    11 int newnode(){
    12     memset(nxt[size],0,sizeof(nxt[size]));
    13     f[size]=tail[size]=0;
    14     return size++;
    15 }
    16 
    17 void insert(char s[]){
    18     int i,p=0;
    19     for(i=0;s[i];i++){
    20         int &x=nxt[p][s[i]-'a'];
    21         p=x?x:x=newnode();
    22     }
    23     tail[p]++;
    24 }
    25 
    26 void makenxt(){
    27     int i;
    28     queue<int>q;
    29     f[0]=0;
    30     for(i=0;i<26;i++){
    31         int v=nxt[0][i];
    32         if(v){
    33             f[v]=last[v]=0;
    34             q.push(v);
    35         }
    36     }
    37     while(!q.empty()){
    38         int u=q.front();
    39         q.pop();
    40         for(i=0;i<26;i++){
    41             int v=nxt[u][i];
    42             if(!v)nxt[u][i]=nxt[f[u]][i];
    43             else{
    44                 q.push(v);
    45                 f[v]=nxt[f[u]][i];
    46                 last[v]=tail[f[v]]?f[v]:last[f[v]];
    47             }
    48         }
    49     }
    50 }
    51 
    52 int query(char s[]){
    53     int ans=0,v=0;
    54     for(int i=0;s[i];i++){
    55         while(v&&!nxt[v][s[i]-'a'])v=f[v];
    56         v=nxt[v][s[i]-'a'];
    57         int tmp=v;
    58         while(tmp){
    59             ans+=tail[tmp];
    60             tail[tmp]=0;
    61             tmp=last[tmp];
    62         }
    63     }
    64     return ans;
    65 }
    66 
    67 int main(){
    68     int T;
    69     scanf("%d",&T);
    70     while(T--){
    71         int n;
    72         scanf("%d",&n);
    73         size=0,newnode();
    74         for(int i=0;i<n;i++){
    75             scanf("%s",word);
    76             insert(word);
    77         }
    78         makenxt();
    79         scanf("%s",s);
    80         printf("%d\n",query(s));
    81     }
    82     return 0;
    83 }

     

    转载于:https://www.cnblogs.com/cenariusxz/p/4510904.html

    展开全文
  • 项目具体内容就是青岛的一个玻璃厂,想要区分其生产的瓶子,有具体十几个种类,我们的大致思路就是用摄像头在特定光照条件下,将瓶子的轮廓拍出来,然后利用模板匹配进行识别。但在思考的过程中,我们发现了很问题...

    [计算机视觉项目]【Day1】


    前言

    进入大学后,这是我接手的第一个项目
    项目具体内容就是青岛的一个玻璃厂,想要区分其生产的瓶子,有具体十几个种类,我们的大致思路就是用摄像头在特定光照条件下,将瓶子的轮廓拍出来,然后利用模板匹配进行识别。但在思考的过程中,我们发现了很多问题,例如瓶子是玻璃材质的,对于拍照的光照条件十分严苛,还有感谢@拾牙慧者,发现如果使用灰度图模板匹配的话,准确度会十分低。所以最终,我们尝试使用梯度来进行模板匹配。


    基本思路

    利用梯度ncc模板匹配,来进行相似度检测,利用模板匹配样图,取出ncc值最大的就是相似度最高的模型。

    ncc计算函数代码如下:

    //计算ncc系数
    //由于分母 (sqrtf(gx1*gx1 + gy1*gy1) * sqrtf(gx2*gx2 + gy2*gy2))
    //即mag1 和 mag2,存在重复计算部分,故在建立模型时预先计算,并且把除法转换为乘法
    //创建此版本作为加速
    float calcAccNCC(float gx1, float gy1, float gx2, float gy2, float magMinus1, float magMinus2)
    {
    	return ((gx1 * gx2 + gy1 * gy2) * (magMinus1 * magMinus2));
    }
    

    具体实现函数代码如下:

    int searchNcc(	        cv::Mat srcGx,
    						cv::Mat srcGy,
    						cv::Mat srcMag,
    						cv::Mat srcCannyMat,
    						int searchStep,
    						sttTemplateModel& srcModel)
    {
    	//检查参数
    	int t_width = srcModel.width;
    	int t_height = srcModel.height;
    	int s_width = srcGx.cols;
    	int s_height = srcGy.rows;
    
    	int d_width = s_width - t_width;  //标志点遍历的长和宽
    	int d_height = s_height - t_height;
    
    	if (d_width < 0 || d_height < 0) {
    		return 1;
    	}
    
    	cv::Mat nccMat(d_height, d_width, CV_64FC1);
    	nccMat = 0;
    
    	int nEdge = srcModel.vModel.size();           //数据点个数
    
    	//以步进为searchStep搜索整个图像
    	for (int i = 0; i < d_height; i = i + searchStep)
    	{
    		for (int j = 0; j < d_width; j = j + searchStep)
    		{
    			//遍历向量
    			int cnt = 0;
    			int nccSum = 0;
    			for (int m = 0; m < nEdge; m++) {
    
    				int dx = srcModel.vModel[m].x;
    				int dy = srcModel.vModel[m].y;
    				int srcx = j + dx;
    				int srcy = i + dy;
    
    				if (srcCannyMat.at<uchar>(srcy, srcx) == 255) {
    
    					//如果匹配图像上的边缘信息不为0,则计算
    					float gxs = srcGx.at<float>(srcy, srcx);
    					float gys = srcGy.at<float>(srcy, srcx);
    					float gxr = srcModel.vModel[m].gx;
    					float gyr = srcModel.vModel[m].gy;
    					float magr = srcModel.vModel[m].mag;
    					float mags = srcMag.at<float>(srcy, srcx);
    
    					//如果分母不为0
    					if (!((gxr == 0 && gyr == 0) || (gxs == 0 && gys == 0))) {
    
    						//计算ncc
    						float ncc = calcAccNCC(gxr, gyr, gxs, gys, magr, mags);
    						nccSum = ncc + nccSum;
    					}
    				}
    
    			}
    
    			nccMat.at<double>(i, j) = (float)nccSum;
    		}
    	}
    	//若步进大于1 就二次搜索
    	if (searchStep > 1)
    	{
    		//先找到nccMat中像素值前三大的坐标
    		double minVal1, maxVal1;//ncc矩阵里面的最小值和最大值
    		int minIdx1[2] = {}, maxIdx1[2] = {};	// minnimum Index, maximum Index
    		minMaxIdx(nccMat, &minVal1, &maxVal1, minIdx1, maxIdx1);
    		int maxX1 = maxIdx1[1];
    		int maxY1 = maxIdx1[0];
    
    		Mat nccMatForMaxIdx;
    		nccMat.copyTo(nccMatForMaxIdx);
    		nccMatForMaxIdx.at<double>(maxY1, maxX1) = minVal1;
    		minMaxIdx(nccMatForMaxIdx, &minVal1, &maxVal1, minIdx1, maxIdx1);
    		int maxX2 = maxIdx1[1];
    		int maxY2 = maxIdx1[0];
    
    		nccMatForMaxIdx.at<double>(maxY2, maxX2) = minVal1;
    		minMaxIdx(nccMatForMaxIdx, &minVal1, &maxVal1, minIdx1, maxIdx1);
    		int maxX3 = maxIdx1[1];
    		int maxY3 = maxIdx1[0];
    
    		//在像素点附近进行 步进为1的搜索
    		searchSecondNcc(maxX1, maxY2, searchStep, d_width, d_height, srcGx, srcGy, srcMag, srcCannyMat, srcModel, nccMat);
    		searchSecondNcc(maxX2, maxY2, searchStep, d_width, d_height, srcGx, srcGy, srcMag, srcCannyMat, srcModel, nccMat);
    		searchSecondNcc(maxX3, maxY3, searchStep, d_width, d_height, srcGx, srcGy, srcMag, srcCannyMat, srcModel, nccMat);
    	}
    	// 这里要注意 arr[0] 代表坐标y ,arr[1]代表坐标x。
    	double minVal, maxVal;
    	int minIdx[2] = {}, maxIdx[2] = {};	// minnimum Index, maximum Index
    	minMaxIdx(nccMat, &minVal, &maxVal, minIdx, maxIdx);
    
    	srcModel.resRect.x = maxIdx[1];
    	srcModel.resRect.y = maxIdx[0];
    	srcModel.resRect.height = srcModel.height;
    	srcModel.resRect.width = srcModel.width;
    	srcModel.score = maxVal;
    
    	return 0;
    }
    /**********************
    

    总结

    刚刚回到熟悉的学校,还有一点没走出智能车失利的心态,但是既然已经明确了目标,就不要不断的向这个方向努力,我就不相信努力没有结果,我命由我不由天,加油。

    展开全文
  • opencv-python车牌识别

    千次阅读 2020-01-20 11:12:55
    opencv-python车牌识别 本文尚有很不足的地方,例如车牌字符的定位,车牌种类的不同,复杂环境下车牌识别的问题等等。。。 不足之处请指教 ...模板匹配,找出匹配最大值 结果输出 子函数介绍 (1)color_c...

    opencv-python车牌识别

    本文尚有很多不足的地方,例如车牌字符的定位,车牌种类的不同,复杂环境下车牌识别的问题等等。。。
    不足之处请多指教
    

    主要步骤

    1. 读入图像
    2. 颜色识别,设定阈值
    3. 掩模、按位运算
    4. 图形灰度化、二值化
    5. 边缘检测
    6. 开运算、闭运算
    7. 轮廓识别,输出矩阵
    8. 判断长宽比
    9. 找出车牌四角坐标
    10. 检测字符位置
    11. 字符切割
    12. 模板匹配,找出匹配最大值
    13. 结果输出

    子函数介绍

    (1)color_change(picture)函数
    对输入的图片,现进行阈值的设定,不同颜色的车牌有不同的阈值,一般为蓝色,黄色和绿色。然后通过掩模运算突出二值化车牌的位置,极大的降低了其他背景对识别的干扰。然后在进行按位运算回复车牌原有的颜色,并返回处理过的图像。
    颜色识别后的车牌
    (2)binaryzation(value)函数
    把color_change(picture)返回的结果转化为和灰度图并进行二值化,然后进行边缘检测,并对检测后的图像进行开运算和开运算,将车牌区域的轮廓连为一个整体。然后通过cv2.findContours()函数找出图像中单独的轮廓并返回。
    cv2.findContours()参数说明:img为寻找轮廓的图像,且为二值图(黑白图)。
    mode为轮廓的检索模式,有四种:cv2.RETR_EXTERNAL只检测外轮廓。cv2.RETR_LIST检测的轮廓不建立等级关系。cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。cv2.RETR_TREE建立一个等级树结构的轮廓。
    method为轮廓的近似方法。cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1)) == 1。cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。
    返回值contours表示图像中的所有轮廓的list,np.array类型。
    开闭运算输出的轮廓:
    在这里插入图片描述
    函数画出的轮廓:
    在这里插入图片描述
    (3)cut_out(value1,value2)函数
    函数接收 binaryzation(value)返回的结果,利用cv2.minAreaRect(contour)函数计算识别轮廓的长宽比,确定车牌的位置。然后利用v2.boxPoints(rect)函数找出车牌四个角的坐标,最后切割车牌。
    切割出的车牌:
    在这里插入图片描述
    (4)car_binaryzation_cut(value)函数
    将cut_out(value1,value2)函数返回的图像进行二值化,然后获取图像行方向和列方向上字符的分布图,确定字符的分布位置。然后根据位置进行字符的分割。最后将分割后的字符和保存的字符库进行匹配,找出匹配度最高的图像,最后输出匹配结果。
    车牌二值化的图像:
    在这里插入图片描述
    字符行列像素分布图:
    在这里插入图片描述
    字符分割后的图像:
    在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
    (5)show(value,picture)函数
    该函数主要用于在原始图像上添加识别后的结果,因为有汉字,所以运用PIL库进行输出。其参数为原始图像和识别后的字符串结果。
    在这里插入图片描述

    主代码

    import cv2 
    import numpy as np
    import matplotlib.pyplot as plt
    from PIL import Image,ImageDraw,ImageFont
    
    def color_change(picture):
        '''
        将图片转化到HSV空间,并按位取反,突出车牌区域
        '''
        hsv=cv2.cvtColor(picture,cv2.COLOR_BGR2HSV)     #转化为HSV颜色空间
        lower_blue=np.array([100,43,46])                              #蓝色阈值
        upper_blue=np.array([124,255,255])
        mask1=cv2.inRange(hsv,lower_blue,upper_blue)     #构建掩模
        res1=cv2.bitwise_and(image,image,mask=mask1)  #按位运算
        cv2.imwrite('111.jpg',res1)
        return res1
    
    
    def binaryzation(value):
        '''
        把图象进行二值化,并进行开闭运算,最后找到可能存在的区域,并返回区域信息
        '''
        gray=cv2.cvtColor(value,cv2.COLOR_BGR2GRAY)                                          #转化为灰度图                                            
        ret,thresh=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)                       #图像二值化
    
        canny = cv2.Canny(thresh, 100, 200)                                                                #边缘检测
        kernel1 = np.ones((12,40), np.uint8)  
        img_edge1 = cv2.morphologyEx(canny, cv2.MORPH_CLOSE, kernel1)         # 闭运算  
        img_edge2 = cv2.morphologyEx(img_edge1, cv2.MORPH_OPEN, kernel1)  # 开运算
        cv2.imwrite('222.jpg',img_edge2)
    
        contours ,hierarchy = cv2.findContours(img_edge2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        #c=cv2.drawContours(image, contours, -1, (0, 255, 0), 3)
        return contours
    
    
    def cut_out(value1,value2):
        '''
        通过长宽比判断车牌的位置,并截取
        '''                                
        for contour in value1:
            rect = cv2.minAreaRect(contour)   #找出最小外接矩形 中心点、宽和高、角度
            if rect[1][1]>rect[1][0]:
                k=rect[1][1]/rect[1][0]
            else:
                k=rect[1][0]/rect[1][1]
            if (k>2.5)&(k<5):    #判断车牌的轮廓
            
                a=cv2.boxPoints(rect)     #获取外接矩形的四个点
                box = np.int0(a)
                aa=cv2.drawContours(value2, [box], -1, (0, 255, 0), 3)  #找出车牌的位置     
                cv2.imwrite('aa.jpg',aa)
                x=[]
                y=[]
                for i in range(4):
                    x.append(box[i][1])
                    y.append(box[i][0])
                min_x=min(x)
                max_x=max(x)
                min_y=min(y)
                max_y=max(y)         
                cut=image[min_x:max_x,min_y:max_y]
                cv2.imwrite('333.jpg',cut)  
                return cut
    
    
    def car_binaryzation_cut(value):
        '''
        截取车牌的二值化并切割
        '''  
        # RGB转GARY
        change_size= cv2.resize(value, (440, 140))
        gray_img = cv2.cvtColor(change_size, cv2.COLOR_BGR2GRAY)  
        ret,thresh=cv2.threshold(gray_img,127,255,cv2.THRESH_BINARY)       #图像二值化
        cv2.imwrite('444.jpg', thresh)
        
        x=list(range(440))
        y=[]
        for i in range(440):         #获取列方向上的字符像素分布图
            n=0
            for j in range(140):
                if thresh[j,i]==255:
                    n=n+1
            y.append(n)
        plt.subplot(1,2,1)
        plt.plot(x,y)     
        
        x1=list(range(140))
        y1=[]
        for i in range(140):         #获取行方向上的字符像素分布图
            n=0
            for j in range(440):
                if thresh[i,j]==255:
                    n=n+1
            y1.append(n)
        plt.subplot(1,2,2)
        plt.plot(x1,y1)     
        plt.show()
    
        p1=thresh[15:120,12:63]
        p2=thresh[15:120,65:117]
        p3=thresh[20:120,142:197]
        p4=thresh[20:120,200:260]
        p5=thresh[20:120,260:317]
        p6=thresh[20:120,320:365]
        p7=thresh[20:120,370:425]
    
        cv2.imshow('1',p1)
        cv2.imshow('2',p2)
        cv2.imshow('3',p3)
        cv2.imshow('4',p4)
        cv2.imshow('5',p5)
        cv2.imshow('6',p6)
        cv2.imshow('7',p7)
    
        p=[p1,p2,p3,p4,p5,p6,p7]
        tem=['0.jpg','5.jpg','6.jpg','7.jpg','8.jpg','9.jpg','B.jpg','C.jpg','E.jpg','J.jpg','K.jpg','M.jpg','Q.jpg','T.jpg','U.jpg','jin.jpg','chuan.jpg','yu.jpg','lu.jpg','su.jpg','ee.jpg']
        a=['0','5','6','7','8','9','B','C','E','J','K','M','Q','T','U','晋','川','豫','鲁','苏','鄂']
        ss=[]
        for i in range(7):    #模板匹配
            s=[]
            for j in range(len(tem)):
                image1=cv2.imread(tem[j],0)      #读入图像
                __,aaa=cv2.threshold(image1,127,255,cv2.THRESH_BINARY)
                bbb= cv2.resize(aaa, (50, 100))
                result=cv2.matchTemplate(p[i],bbb,cv2.TM_CCOEFF_NORMED)
                min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
                s.append(max_val)
            ss.append(a[s.index(max(s))])
        car=ss[0]+ss[1]+'.'+ss[2]+ss[3]+ss[4]+ss[5]+ss[6]
        print(car)
        return car
    
    
    def show(value,picture):
          cv2img = cv2.cvtColor(picture, cv2.COLOR_BGR2RGB) # cv2和PIL中颜色的hex码的储存顺序不同
          pilimg = Image.fromarray(cv2img)
          # PIL图片上打印汉字
          draw = ImageDraw.Draw(pilimg) # 图片上打印
          font = ImageFont.truetype("simhei.ttf", 40, encoding="utf-8") # 参数1:字体文件路径,参数2:字体大小
          draw.text((200, 200), value, (255, 0, 0), font=font) # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体
     
          # PIL图片转cv2 图片
          cv2charimg = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)
          cv2.imshow("result", cv2charimg)
          cv2.imwrite('555.jpg',cv2charimg)
    
    
    if __name__=='__main__':                                    
        image=cv2.imread('bbb.jpg')     #读入图像
        image = cv2.resize(image, (570, 430))
        
        res=color_change(image)        #转化到HSV,并大致取出车牌位置
        a=binaryzation(res)                  #对颜色识别过的区域进行二值化,并进行开闭运算识别轮廓
        b=cut_out(a,image)                  #找到符合条件的区域,并进行切割
        c=car_binaryzation_cut(b)
        show(c,image)
    
        while(1):
            k=cv2.waitKey(5)&0xFF
            if k==27:
                cv2.destroyAllWindows()
                break
    
    
    展开全文
  • opencv 追踪算法

    千次阅读 2018-04-24 19:40:47
    如果对象非常简单且没有什么外貌上的变化,我们可以使用模板匹配。但是现实并未如此,当前模型可能随时随地变换(如人脸,你可能下一秒变成侧脸)。 Opencv中集成了诸多算法,随着其不断更新,算法的种类也越来越,...
  • 正则表达式

    2021-01-09 17:04:38
    文章目录一、概述二、字符种类三、非捕获元素与反向引用四、元字符五、运算符优先级六、匹配规则七、正则表达式实例八、正则表达式分组 一、概述 正则表达式(regular expression)是由普通字符和特殊字符组成的...
  • 通常情况下,深度学习模型对于场景,目标种类范围较大时并不能得到很好的计算精度,例如检测模型即使...模板匹配算法: def makejson(img_name,bboxes,signbit,filename): offer={} offer['img_name']=img_name
  • 为了提高虹膜识别的准确率,通过对虹膜图像进行处理,实现了对...实验结果表明,提出的虹膜识别方法有效地避免了虹膜匹配过程中因为虹膜数据库中种类多、数量带来的计算量大、计算时间长的问题,提高了识别准确率。
  • 为了提高虹膜识别的准确率,通过对虹膜图像进行处理,实现了对虹膜...实验结果表明,提出的虹膜识别方法有效地避免了虹膜匹配过程中因为虹膜数据库中种类多、数量带来的计算量大、计算时间长的问题,提高了识别准确率。
  • 该模式秒杀在查找文章主体时待匹配的一个或个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 正则表达式的常用元字符(全为英文状态,注意可以代表的字符种类和个数): ...
  • 问答系统总结

    2019-05-16 14:01:30
    最近在研究问答系统,但是在查找资料的过程中一直处于懵逼状态,因为问答系统分类比较,根据不同的依据可以分为不同种类,总是搞混,也没有找到资料详细全面的介绍,所以在一边学习查找资料的同时,自己也整理出一份总结,...
  • STL提供了几种类容器(包括数组、队列、链表、集合和映 射)的模板表示。它还提供了高效的通用算法库,这些算法可用于STL容器,也可用于常规数组。模板类 valarray为数值数组提供了支持。 第17章:输入、输出和...
  • STL提供了几种类容器(包括数组、队列、链表、集合和映 射)的模板表示。它还提供了高效的通用算法库,这些算法可用于STL容器,也可用于常规数组。模板类 valarray为数值数组提供了支持。 第17章:输入、输出和...
  • STL提供了几种类容器(包括数组、队列、链表、集合和映 射)的模板表示。它还提供了高效的通用算法库,这些算法可用于STL容器,也可用于常规数组。模板类 valarray为数值数组提供了支持。 第17章:输入、输出和...
  • STL提供了几种类容器(包括数组、队列、链表、集合和映 射)的模板表示。它还提供了高效的通用算法库,这些算法可用于STL容器,也可用于常规数组。模板类 valarray为数值数组提供了支持。 第17章:输入、输出和...
  • 3.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对三套) 4.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大...
  •  本书知识系统全面,拥有字典般的容量,可随用随查,涵盖指针、面向对象、操作符重载、流、命名空间、模板、异常处理、宏等主流c++开发技术。为了使读者能够活学活用,本书针对重要的概念精心设计了438个实用范例,...
  • 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对三套) 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大...
  • 经验上来说,对于实体类型较以及实体关系种类的知识库,使用图数据进行知识存储是个较好的选择。而对应实体类型较少,实体关系较少,实体属性较以及带有时序性的数据时,选用文档型数据库mongodb是个不错的...
  • 8.5 基于边缘和模板匹配的印鉴识别 443 8.6 部分算法代码 446 8.6.1 背景去除(利用颜色) 446 8.6.2 基于矩不变量的代码 450 8.7 本章小结 455 第9章 光学字符识别技术(上) 456 9.1 概述 456 9.1.1 ...
  • 习题 MATLAB编程和练习 参考文献 第7章 特征生成II 7.1 引言 7.2 区域特征 7.3 字符形状和大小的特征 7.4 分形概述 7.5 语音和声音分类的典型特征 习题 MATLAB编程和练习 参考文献 第8章 模板匹配 8.1 引言 8.2 基于...
  • 02_函数模板为什么和函数模板语法基础 03_课堂答疑_遇到莫名其妙的问题_重新编译 04_函数模板当函数参数 05_普通函数和模板函数区别_传智扫地僧 06_函数模板和函数重载在一起(调用规则研究)_传智扫地僧 07_函数模板...
  • 已出版部著作和译著,包括《程序设计语言基础》(译著,1990),《Mathematica数学软件系统的应用与程序设计》(1994),《从问题到程序——程序设计与C语言引论》(1999) [同作者作品] 计算机基础教程(上下)...
  • C++程序设计语言(特别版)--源代码

    热门讨论 2012-04-23 07:33:51
    已出版部著作和译著,包括《程序设计语言基础》(译著,1990),《Mathematica数学软件系统的应用与程序设计》(1994),《从问题到程序——程序设计与C语言引论》(1999) [同作者作品] 计算机基础教程(上下)...
  • 已出版部著作和译著,包括《程序设计语言基础》(译著,1990),《Mathematica数学软件系统的应用与程序设计》(1994),《从问题到程序——程序设计与C语言引论》(1999) [同作者作品] 计算机基础教程(上下)...
  • 简易式雇员养老金(SEP)和雇员储蓄激励匹配计划(SIMPLE) 基奥计划 D继续教育 网络 文摘 版权页: 插图: 4.下一步,将你朋友的设备连接到你的音序器上。将该设备的数据转储到音序器中。然后根据...
  • 人力资源管理软件(完全免费)

    热门讨论 2011-03-08 11:36:20
    人力资源管理软件考勤计算匹配请假、出差的漏洞(感谢iplan) 自动执行选项限制为本人(感谢iplan) 籍贯如果有县则不显示市的信息(感谢☆缘☆) 2008-04-10 人力资源管理软件修正了一些问题 修正了考勤班组无法...

空空如也

空空如也

1 2 3 4
收藏数 63
精华内容 25
关键字:

多种类模板匹配