银行卡的识别与车牌识别都是类似的,有了opencv方便了很多,许多函数都不要自己动手去写。


// #include "stdafx.h"  
 #include "cv.h"  
 #include "highgui.h"  
 #include "cxcore.h"  

 int main(int argc, char* argv[])
 {
IplImage* imgQie=NULL;
IplImage* imgSrc = cvLoadImage("D:\\1.jpg", CV_LOAD_IMAGE_COLOR);//加载图像
IplImage* img_gray = cvCreateImage(cvGetSize(imgSrc), IPL_DEPTH_8U, 1);//创建灰度图,定义灰度图
cvCvtColor(imgSrc, img_gray, CV_BGR2GRAY);//灰度图的转换函数
cvThreshold(img_gray, img_gray, 50, 255, CV_THRESH_BINARY_INV);// CV_THRESH_BINARY_INV使得背景为黑色,字符为白色,这样找到的最外层才是字符的最外层  
cvShowImage("ThresholdImg", img_gray);//显示灰度图像
CvSeq* contours = NULL;//可增长的序列,不是固定的序列,存储轮廓信息的链表头
CvSeq* contours1 = NULL;
CvMemStorage* storage = cvCreateMemStorage(0);//用来创建一个内存存储器,来统一管理各种动态对象的内存
// 上面源图片有瑕疵可以用腐蚀,膨胀来祛除  
IplImage* imgPeng = cvCreateImage(cvGetSize(imgSrc), IPL_DEPTH_8U, 1);
IplImage* imgFu = cvCreateImage(cvGetSize(imgSrc), IPL_DEPTH_8U, 1);

cvErode(img_gray, imgFu, NULL, 1);//腐蚀函数
cvNamedWindow("腐蚀", CV_WINDOW_AUTOSIZE);
cvShowImage("腐蚀", imgFu);

cvDilate(imgFu,imgPeng,NULL,11);
cvNamedWindow("膨胀", CV_WINDOW_AUTOSIZE);
cvShowImage("膨胀", imgPeng);

int count = cvFindContours(imgPeng, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL);//轮廓检验返回的是轮廓的个数
printf("轮廓个数:%d", count);

int idx = 0;
char szName[56] = { 0 };


int tempCount = 0;
for (CvSeq* c = contours; c != NULL; c = c->h_next) 
{
CvRect rc = cvBoundingRect(c, 0);
 
if (rc.width/rc.height<=5||rc.height<1||rc.width<1)      
      {    
          continue;     //这里可以根据轮廓的大小进行筛选  
      }  

cvDrawRect(imgSrc, cvPoint(rc.x-10, rc.y-3), cvPoint(rc.x + rc.width-6, rc.y + rc.height-3), CV_RGB(255, 0, 0));
IplImage* imgNo = cvCreateImage(cvSize(rc.width, rc.height), IPL_DEPTH_8U, 3);// //为分割后的单个字符分配一个存储空间
cvSetImageROI(imgSrc, rc); //基于给定的矩形设置图像的ROI(感兴趣区域)
cvCopyImage(imgSrc, imgNo);//将ROI复制到imgNo
cvResetImageROI(imgSrc);//释放基于给定的矩形设置图像的ROI
sprintf(szName, "wnd_%d", idx++);
cvNamedWindow(szName);
cvShowImage(szName, imgNo); //如果想切割出来的图像从左到右排序,或从上到下,可以比较rc.x,rc.y;  

IplImage* imgQie = imgNo;
IplImage* imgQiegray = cvCreateImage(cvGetSize(imgQie), IPL_DEPTH_8U, 1);//创建灰度图,定义灰度图
cvCvtColor(imgQie, imgQiegray, CV_BGR2GRAY);//灰度图的转换函数
cvThreshold(imgQiegray, imgQiegray, 70, 255, CV_THRESH_BINARY_INV);// CV_THRESH_BINARY_INV使得背景为黑色,字符为白色,这样找到的最外层才是字符的最外层  
cvShowImage("灰度二", imgQiegray);//显示灰度图像


int count1 = cvFindContours(imgQiegray, storage, &contours1, sizeof(CvContour), CV_RETR_EXTERNAL);//轮廓检验返回的是轮廓的个数
printf("轮廓个数:%d", count1);
//嵌套在里面再进行处理,在定位出后在处理。
int idx1 = 0;
//int i = 0;
char szName1[56] = { 0 };


int i = 0;
//int a[100];
CvRect rc1[100],temp;
int tempCount1 = 0;
for (CvSeq* c1 = contours1; c1 != NULL; c1 = c1->h_next)
{
rc1[i] = cvBoundingRect(c1, 0);//得到所有外部轮廓的
//a[i] = rc.x;
i++;
}
for (int j = 0; j <19; j++)
{
for (i = 0; i<19- j; i++)
if (rc1[i].x>rc1[i + 1].x)
{
temp = rc1[i];
rc1[i] = rc1[i + 1];//由小到小依次排序
rc1[i + 1] = temp;
}


}


for (i = 0; i<count1; i++)
{
if (rc1[i].width>rc1[i].height)
{
continue;     //这里可以根据轮廓的大小进行筛选  
}

cvDrawRect(imgQie, cvPoint(rc1[i].x, rc1[i].y), cvPoint(rc1[i].x + rc1[i].width, rc1[i].y + rc1[i].height), CV_RGB(255, 0, 0));
IplImage* imgNo1 = cvCreateImage(cvSize(rc1[i].width, rc1[i].height), IPL_DEPTH_8U, 3);// //为分割后的单个字符分配一个存储空间
cvSetImageROI(imgQie, rc1[i]); //基于给定的矩形设置图像的ROI(感兴趣区域)
cvCopyImage(imgQie, imgNo1);//将ROI复制到imgNo
cvResetImageROI(imgQie);//释放基于给定的矩形设置图像的ROI


sprintf(szName1, "wnd_%d", idx1++);
cvNamedWindow(szName1);
cvShowImage(szName1, imgNo1); //如果想切割出来的图像从左到右排序,或从上到下,可以比较rc.x,rc.y;  
cvReleaseImage(&imgNo1);


}
cvReleaseImage(&imgNo);


}

cvNamedWindow("src");
cvShowImage("src", imgSrc);
cvWaitKey(0);
cvReleaseMemStorage(&storage);
cvReleaseImage(&imgSrc);
cvReleaseImage(&img_gray);
cvReleaseImage(&imgQie);
//cvReleaseImage(&imgQiegray);
cvDestroyAllWindows();
return 0;

 }很多在吧字符切割后不知道怎么排序,上面有完整的代码,希望可以帮助大家,大家一起进步。