Visual C++数字图像模式识别典型案例详解
上QQ阅读APP看书,第一时间看更新

4.4.1 图像的标识及特征提取

编程实现

[1] 在Demo1中创建类CCluster以实现模糊聚类的相应功能,在其中添加函数GetFeature(),进行有关图像的标识和特征提取。具体实现代码如代码4-1所示。

代码4-1 GetFeature()函数

        void CCluster::GetFeature()
        {
            ////////////////////以下对数据区域标号whx/////////////////////
            BYTE * p_temp;
            int stop;
            int i,j;
            int counter;//记录相互独立的连通区域的个数
            int present;//记录当前点的值1,2,...,counter
            stop=0;
            counter=0;
            p_temp=new BYTE[wide*height];//开辟一个临时内存区×××××
            memset(p_temp,255,wide*height);//置白
            //从左到右、从上到下标号
            const int T=5;//T为阈值,RGB值小于该阈值被认为是黑
            for(i=0; i<wide; i++)//将第零行置白
                *(m_pData+(height-1)*wide+i)=255;
            for(j=0;j<height;j++)//将第零列置白
                *(m_pData+(height-j-1)*wide)=255;
            for( j=1;j<height-1;j++) // 从第一行开始搜索
            {
                if(stop==1)//判断连通区是否太多
                    break;
                for( i=1;i<wide-1;i++)   // 从第一列开始搜索
                {
                    if(counter>255)
                    {
                          AfxMessageBox("连通区数目太多,请减少样品个数");
                          stop=1;
                          return;
                    }
                    if(*(m_pData+(height-j-1)*wide+i)<T)//若当前点为黑点
                    {
                          if(*(m_pData+(height-j-1+1)*wide+i+1)<T)//若当前点的右上点为黑点
                          {
                              *(p_temp+(height-j-1)*wide+i)=*(p_temp+(height-j-1+1)
                                    *wide+i+1);
                              //当前点标号应该与右上点相同
                              present=*(p_temp+(height-j-1+1)*wide+i+1);//记录当前点的标号
                            if(*(m_pData+(height-j-1)*wide+i-1)<T && *(p_temp+
    (height-j-1)*wide+i-1)!=present)//左前与右上点都为黑且标号不同
                            {
                                int temp=*(p_temp+(height-j-1)*wide+i-1);//记录左前点的标号
                                if (present>temp)//当前点标号记录两者中的较小值
                                {
                                    present=temp;
                                    temp=*(p_temp+(height-j-1+1)*wide+i+1);
                                }
                                counter--;//合并左前和右上标号,标号总数减一
                                for(int m=1;m<=height-1;m++)
                                    for(int n=1;n<=wide-1;n++)
                                    {
                                        if(*(p_temp+(height-m-1)*wide+n)==temp)
                                        //将较大标号改成较小标号
                                        {
                                              *(p_temp+(height-m-1)*wide+n)=present;
                                        }
                                        else if (*(p_temp+(height-m-1)*wide+n)>temp)
                                        //将较大标号以后的所有标号减一,以保持标号的连续性
                                        {
*(p_temp+(height-m-1)*wide+n)-=1;
                                        }
                                    }
                            }
                            if( *(m_pData+(height-j-1+1)*wide+i-1)<T && *(p_temp+
    (height-j-1+1)*wide+i-1)!=present)//左上与右上点都为黑且标号不同
                            {
                                counter--;//合并左上和右上标号,标号总数减一
                                int temp=*(p_temp+(height-j-1+1)*wide+i-1);//记录左上点的值
                                if (present<temp)//当前点标号记录两者中的较小值
                                {
                                    temp=present;
                                    present=*(p_temp+(height-j-1+1)*wide+i-1);
                                }
                                for(int m=1;m<=height-1;m++)
                                    for(int n=1;n<=wide-1;n++)
                                    {
                                        if(*(p_temp+(height-m-1)*wide+n)==present)
                                        //将较大标号改成较小标号
                                        {
                                              *(p_temp+(height-m-1)*wide+n)=temp;
                                        }
                                        else if (*(p_temp+(height-m-1)*wide+n)>present)
                                        //将较大标号以后的所有标号减一,以保持标号的连续性
                                        {
                                              *(p_temp+(height-m-1)*wide+n)-=1;
                                          }
                                      }
                                  present=temp;
                            }
                        }
                    else if(*(m_pData+(height-j-1+1)*wide+i)<T)
                                                          //当前点黑,右上不为黑,正上为黑
                        {
                            *(p_temp+(height-j-1)*wide+i)=*(p_temp+(height-j-1+1)
                                  *wide+i);
                                          //当前标号=正上标号
                            present=*(p_temp+(height-j-1+1)*wide+i);
                        }
                        else if(*(m_pData+(height-j-1+1)*wide+i-1)<T)//左上
                        {
                            *(p_temp+(height-j-1)*wide+i)=*(p_temp+(height-j-1+1)
    *wide+i-1);
                            present=*(p_temp+(height-j-1+1)*wide+i-1);}
                        else if(*(m_pData+(height-j-1)*wide+i-1)<T)//左前
                        {
                            *(p_temp+(height-j-1)*wide+i)=*(p_temp+(height-j-1)
    *wide+i-1);
                            present=*(p_temp+(height-j-1)*wide+i-1);
                        }
                        else//产生新标号
                        {
                            ++counter;
                            present=counter;
                            *(p_temp+(height-j-1)*wide+i)=present;
                        }
                    }//end if
                }// 列
            }//end行
        // //////////////////////以上对数据区域标号//////////////////////////
        //////////////////////以下获得各个样品所在位置及编号///////////////////
            patternnum=counter;//样品总数
            if (m_pattern!=NULL)
                delete []m_pattern;
            m_pattern=new Pattern[patternnum];
            for( i=0;i<patternnum;i++)
            {
                m_pattern[i].index=i+1;
                m_pattern[i].category=0;
                m_pattern[i].lefttop.x=wide;
                m_pattern[i].lefttop.y=height;
                m_pattern[i].rightbottom.x=0;
                m_pattern[i].rightbottom.y=0;
            }
            for(int t=1;t<=patternnum;t++)//记录每个样品(独立连通区域)的左上、右下点坐标
            {
                for(int j=1;j<height-1;j++)//搜索整幅图像
                    for(int i=1;i<wide-1;i++)
                    {
                        if(*(p_temp+(height-j-1)*wide+i)==t)
                        {
                            if (m_pattern[t-1].lefttop.x>i)//get the lefttop point
                                  m_pattern[t-1].lefttop.x=i;
                            if (m_pattern[t-1].lefttop.y>j)
                                  m_pattern[t-1].lefttop.y=j;
                            if (m_pattern[t-1].rightbottom.x<i)//get the rightbottom point
                                  m_pattern[t-1].rightbottom.x=i;
                            if (m_pattern[t-1].rightbottom.y<j)
                                  m_pattern[t-1].rightbottom.y=j;
                        }
                    }
            }
            delete []p_temp;
            //////////////////////以下获得所有样品特征放入m_pattern中////////////////////
            for ( i=0;i<patternnum;i++)//=patternnum
            {
                CalFeature(&m_pattern[i]);//调用函数计算第i号模板的值
            }
            //////////////////////以上获得所有样品特征放入m_pattern中////////////////////
        }

[2] 上述代码中,CalFeature ()函数用于计算样品的特征值,该函数的实现代码如代码4-2所示。

代码4-2 CalFeature ()函数

        void CCluster::CalFeature(CCluster::Pattern *m_pattern)
        {
            int w,h,count;
            int i,j;
            w=(int)(m_pattern->rightbottom.x-m_pattern->lefttop.x)/N;//特征值中每个特征的宽
            h=(int)(m_pattern->rightbottom.y-m_pattern->lefttop.y)/N;//特征值中每个特征的高
            for ( j=0;j<N;j++)
            {
                for ( i=0;i<N;i++)
                {
                    count=0;//每个特征内黑点的个数
                    for(int m= height-m_pattern->rightbottom.y+h*j;m<height-m_pattern->
                          rightbottom.y+h*j+h;m++)
                        for (int n=m_pattern->lefttop.x+i*w; n<m_pattern->lefttop.x+i*w
                              +w; n++)
                              if (*(m_pData+m*wide+n)==0)
                                  count++;
                    m_pattern->feature[j*N+i]=(double)count/(double)(w*h);
                }
            }
        }