上图为识别有误样张,下图为识别正常样张。
现在是简单的贴票识别没问题,但是较复杂的贴票就会识别有误,识别不全,请教大家谁能帮我看下原因?
代码段:
void do_bill_image(const char* pTifFile)
{
if (NULL == pTifFile)
return;
int p[3];
p[0] = CV_IMWRITE_JPEG_QUALITY;
p[1] = 85;
p[2] = 0;
IplImage* lpImgSrc = cvLoadImage(pTifFile, CV_LOAD_IMAGE_COLOR);*/
if (lpImgSrc)
{
std::map
mapRC.clear();
IplImage* lpImgBinary = get_image_binary(lpImgSrc, 0);
if (lpImgBinary)
{
removice_noise_image(lpImgBinary, 3);//降噪
cvErode(lpImgBinary, lpImgBinary, NULL, 3);//腐蚀
//cvDilate(lpImgBinary, lpImgBinary, NULL, 3);//膨胀
removeblack(lpImgBinary);//漫水填充
int iSpace = lpImgBinary->width/2;
std::vector
vecHistogramSum.clear();
{ // 图片像素统计(垂直投影)
IplImage* lpImageOut = cvCreateImage(cvGetSize(lpImgBinary), lpImgBinary->depth, lpImgBinary->nChannels);
if (lpImageOut)
{
SumImageHistogram(lpImgBinary, lpImageOut, vecHistogramSum, 8, 0);
int iCount = 0;
unsigned long ulSum = 0;
std::vector
while (it != vecHistogramSum.end())
{
if (*it)
{
ulSum += *it;
iCount++;
}
it++;
}
int iAvg = ulSum / iCount;
int ithreshold = iAvg / 5;
//如果获取的高度小于50个像素,认为是空白
if (8 > ithreshold)
return;
RECT rc;
ZeroMemory(&rc, sizeof(RECT));
rc.right = lpImageOut->width-1;
rc.bottom = lpImageOut->height/2;
std::vector
vecRegionalism.clear();
statistical_image_chang_count_pos(lpImageOut, rc, vecRegionalism, ithreshold/2, ithreshold/2, false);
if (!vecRegionalism.empty())
{
//if (1 == vecRegionalism.size())
//{
//
//}
//else
{
std::vector
while (it != vecRegionalism.end())
{
if (100 > (it->right - it->left))
{
it++;
continue;
}
IplImage* lpImgTemp = Copy_Image_roi_data(lpImgBinary, it->left, 0, it->right, lpImgBinary->height);
if (lpImgTemp)
{
// 记录图片的水平投影
std::vector
vecRegsm.clear();
{ // 图片像素统计(水平投影)
IplImage* lpImgOut = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, lpImgTemp->nChannels);
if (lpImgOut)
{
vecHistogramSum.clear();
SumImageHistogram(lpImgTemp, lpImgOut, vecHistogramSum, 8, 1);
rc.left = 0;
rc.top = 0;
rc.right = lpImgOut->width - 1;
rc.bottom = lpImgOut->height - 1;
statistical_image_chang_count_pos(lpImgOut, rc, vecRegsm, 8, 8, true);
cvReleaseImage(&lpImgOut);
}
}
std::map
mapRcs.clear();
{ // 图片轮廓跟踪
//contour = cvApproxPoly(contour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1);
IplImage* pContourImg = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, 3);
IplImage* pImgeare = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, 3);
//cvZero(pContourImg);
//cvZero(pImgeare);
RECT rcClear;
memset(&rcClear, 0, sizeof(RECT));
rcClear.right = pContourImg->width - 1;
rcClear.bottom = pContourImg->height - 1;
clear_Image_rect(pContourImg, rcClear);
clear_Image_rect(pImgeare, rcClear);
CvBox2D32f *box;
CvPoint *PointArray;
CvPoint2D32f *PointArray2D32f;
CvScalar external_color;
CvScalar hole_color;
int color;
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* contour = 0;
int contours_num = cvFindContours(lpImgTemp, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(0, 0)); // 轮廓跟踪
int iIndex = 0;
//绘制所有轮廓并用椭圆拟合
while (contour)
{
int i;
int count = contour->total;//轮廓个数
CvPoint center;
CvSize size;
/*个数必须大于6,这是cvFitEllipse_32f的要求*/
if (count < 6)
{
contour = contour->h_next;
continue;
}
cout << "count: " << count << ", Index: " << iIndex++ << endl;
//分配内存给点集
PointArray = (CvPoint *)malloc(count * sizeof(CvPoint));
PointArray2D32f = (CvPoint2D32f*)malloc(count * sizeof(CvPoint2D32f));
//分配内存给椭圆数据
box = (CvBox2D32f *)malloc(sizeof(CvBox2D32f));
//得到点集(这个方法值得借鉴)
cvCvtSeqToArray(contour, PointArray, CV_WHOLE_SEQ);
//将CvPoint点集转化为CvBox2D32f集合
for (i = 0; i < count; i++)
{
PointArray2D32f[i].x = (float)PointArray[i].x;
PointArray2D32f[i].y = (float)PointArray[i].y;
}
//拟合当前轮廓
cvFitEllipse(PointArray2D32f, count, box);
double c = sqrt((box->size.height)*(box->size.height) / 4 - (box->size.width)*(box->size.width) / 4);
double lxl = 2 * c / box->size.height;
if ((48.00 < box->size.height && 100.00 < box->size.width) &&
(lpImgBinary->height/3 > box->size.height && lpImgBinary->width/2 > box->size.width))
{
cout << "离心率: " << lxl << ", Height: " << box->size.height << ", Width: " << box->size.width << ", Height/Width: " << (box->size.height/box->size.width) << endl;
//绘制当前轮廓
cvDrawContours(pImgeare, contour, CV_RGB(0, 0, 0), CV_RGB(0, 0, 0), 0, 3, CV_AA, cvPoint(0, 0));
//将椭圆数据从浮点转化为整数表示
center.x = cvRound(box->center.x);
center.y = cvRound(box->center.y);
size.width = cvRound(box->size.width*0.5);
size.height = cvRound(box->size.height*0.5);
box->angle = -box->angle;
RECT rc;
rc.left = box->center.x - box->size.height*0.5;
rc.top = box->center.y - box->size.width *0.5;
rc.right = rc.left + box->size.height;
rc.bottom = rc.top + box->size.width;
//mapRcs.insert(std::map
//画椭圆
if (TRUE == InsertRcMap(mapRcs, rc))
cvEllipse(pContourImg, center, size, box->angle, 0, 360, CV_RGB(0, 0, 0), 3, CV_AA, 0);
}
free(PointArray);
free(PointArray2D32f);
free(box);
contour = contour->h_next;
}
cvReleaseMemStorage(&storage);
IplImage* pImgEareBin = get_image_binary(pImgeare, 0);
cvReleaseImage(&pContourImg);
cvReleaseImage(&pImgeare);
if (pImgEareBin)
{
std::vector
vecRegiona.clear();
RECT rcTmp;
memset(&rcTmp, 0, sizeof(RECT));
rcTmp.right = pImgEareBin->width - 1;
rcTmp.bottom = pImgEareBin->height - 1;
statistical_image_chang_count_pos(pImgEareBin, rcTmp, vecRegiona, 2, 2, true);
cvReleaseImage(&pImgEareBin);
if (!vecRegiona.empty())
{
int iSize = vecRegiona.size();
int iCount = iSize%2;
if (iCount)
{ // 奇数各
}
else
{ // 偶数个
std::vector
it1 = vecRegiona.begin();
it2 = vecRegiona.begin();
it2++;
while (it1 != vecRegiona.end() && it2 != vecRegiona.end())
{
RECT rect;
memset(&rect, 0, sizeof(RECT));
rect.top = it1->top;
rect.bottom = it2->bottom;
rect.left = it->left;
rect.right = it->right;
{
std::vector
ittemp1 = vecRegsm.begin();
while (ittemp1 != vecRegsm.end())
{
if (64 > abs(rect.top - ittemp1->top))
{
rect.top = __min(rect.top, ittemp1->top);
}
if (100 > abs(rect.bottom - ittemp1->bottom))
{
rect.bottom = __max(rect.bottom, ittemp1->bottom);
}
ittemp1++;
}
}
mapRC[rect.top] = rect;
it1++;
it2++;
if (it1 != vecRegiona.end() && it2 != vecRegiona.end())
{
it1++;
it2++;
}
}
}
}
}
}
cvReleaseImage(&lpImgTemp);
}
it++;
}
}
}
else
{
// 空的白纸
return ;
}
cvReleaseImage(&lpImageOut);
}
}
cvReleaseImage(&lpImgBinary);
}
{
std::map
it = mapRC.begin();
while (it != mapRC.end())
{
// 判断加载图片的长宽比是否满足VAT发票的要求
int itemp = (int)(((double)(it->second.right-it->second.left)/(double)(it->second.bottom-it->second.top))*10.00); // 一般发票长宽比例为1.5% ~ 1.8%左右
if (itemp > 20)
{ // 清单
mapRC.erase(it);
if (!mapRC.empty())
{
it = mapRC.begin();
continue;
}
else
{
break;
}
}
it++;
}
}
if (mapRC.empty())
{
IplImage* lpImgBinary = get_image_binary(lpImgSrc, 0);
if (lpImgBinary)
{
std::vector
vecHistogramSum.clear();
removice_noise_image(lpImgBinary, 3);
cvErode(lpImgBinary, lpImgBinary, NULL, 3);
// 记录图片的水平投影
std::vector
vecRegsm.clear();
{ // 图片像素统计(水平投影)
IplImage* lpImgOut = cvCreateImage(cvGetSize(lpImgBinary), lpImgBinary->depth, lpImgBinary->nChannels);
if (lpImgOut)
{
vecHistogramSum.clear();
SumImageHistogram(lpImgBinary, lpImgOut, vecHistogramSum, 8, 1);
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = lpImgOut->width - 1;
rc.bottom = lpImgOut->height - 1;
statistical_image_chang_count_pos(lpImgOut, rc, vecRegsm, 8, 8, true);
cvReleaseImage(&lpImgOut);
}
}
if (!vecRegsm.empty())
{
std::vector
it = vecRegsm.begin();
while (it != vecRegsm.end())
{
if (it->bottom - it->top > 100)
{
IplImage* lpImgTemp = Copy_Image_roi_data(lpImgBinary, it->left, it->top, it->right, it->bottom);
if (lpImgTemp)
{
IplImage* lpImgOut = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, lpImgTemp->nChannels);
if (lpImgOut)
{
vecHistogramSum.clear();
SumImageHistogram(lpImgTemp, lpImgOut, vecHistogramSum, 8, 0);
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = lpImgOut->width - 1;
rc.bottom = lpImgOut->height - 1;
std::vector
vecRegsmons.clear();
statistical_image_chang_count_pos(lpImgOut, rc, vecRegsmons, 3, 3, false);
if (!vecRegsmons.empty())
{
int iCount = 0;
std::vector
itor = vecRegsmons.begin();
while (itor != vecRegsmons.end())
{
if (itor->right - itor->left > 100)
{
RECT rt;
rt.left = itor->left;
rt.top = it->top;
rt.right = itor->right;
rt.bottom = it->bottom;
mapRC[rt.top+iCount] = rt;
}
iCount++;
itor++;
}
}
cvReleaseImage(&lpImgOut);
}
cvReleaseImage(&lpImgTemp);
}
}
it++;
}
}
cvReleaseImage(&lpImgBinary);
}
}
if (!mapRC.empty())
{
std::map
it = mapRC.begin();
while (it != mapRC.end())
{
cv::Point pt1, pt2;
pt1.x = it->second.left;
pt1.y = it->second.top;
pt2.x = it->second.right;
pt2.y = it->second.bottom;
//cv::rectangle(cv::cvarrToMat(&lpImgSrc), pt1, pt2, CV_RGB(0, 255, 0), 4, 8, 0);
CvPoint pt[4];
pt[0].x = it->second.left;
pt[0].y = it->second.top;
pt[1].x = it->second.right;
pt[1].y = it->second.top;
pt[2].x = it->second.right;
pt[2].y = it->second.bottom;
pt[3].x = it->second.left;
pt[3].y = it->second.bottom;
cvLine( lpImgSrc, pt[0], pt[1], CV_RGB(0, 255, 0), 8, 8, 0);
cvLine( lpImgSrc, pt[1], pt[2], CV_RGB(0, 255, 0), 8, 8, 0);
cvLine( lpImgSrc, pt[2], pt[3], CV_RGB(0, 255, 0), 8, 8, 0);
cvLine( lpImgSrc, pt[3], pt[0], CV_RGB(0, 255, 0), 8, 8, 0);
it++;
}
char szFile[MAX_PATH];
memset(szFile, 0, sizeof(char)*MAX_PATH);
strcpy(szFile, pTifFile);
char* pPos = strrchr(szFile, '.');
if (pPos)
{
strcpy(pPos, "_result");
const char * pP = strrchr(pTifFile, '.');
if (pP)
{
strcat(szFile, pP);
}
}
pPos = strrchr(szFile, '.');
if (pPos && 0 == stricmp(pPos, ".jpg"))
{
cvSaveImage(szFile, lpImgSrc, p);
}
else
{
cvSaveImage(szFile, lpImgSrc);
}
}
cvReleaseImage(&lpImgSrc);
}
}