VC++ 利用Opencv 做的一個發票識別程式,識別有誤
如題,如圖
上圖為識別有誤樣張,下圖為識別正常樣張。
現在是簡單的貼票識別沒問題,但是較複雜的貼票就會識別有誤,識別不全,請教大家誰能幫我看下原因?
程式碼段:
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<int, RECT> mapRC;
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<UINT> vecHistogramSum;
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<UINT>::iterator it = vecHistogramSum.begin();
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<RECT> vecRegionalism;
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<RECT>::iterator it = vecRegionalism.begin();
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<RECT> vecRegsm;
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<int, RECT> mapRcs; // 記錄符合條件的橢圓數量
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<int, RECT>::value_type(rc.top, rc));
//畫橢圓
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<RECT> vecRegiona;
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<RECT>::iterator it1, it2;
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<RECT>::iterator ittemp1;
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<int, RECT>::iterator it;
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<UINT> vecHistogramSum;
vecHistogramSum.clear();
removice_noise_image(lpImgBinary, 3);
cvErode(lpImgBinary, lpImgBinary, NULL, 3);
// 記錄圖片的水平投影
std::vector<RECT> vecRegsm;
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<RECT>::iterator it;
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<RECT> vecRegsmons;
vecRegsmons.clear();
statistical_image_chang_count_pos(lpImgOut, rc, vecRegsmons, 3, 3, false);
if (!vecRegsmons.empty())
{
int iCount = 0;
std::vector<RECT>::iterator itor;
itor = vecRegsmons.begin();
while (itor != vecRegsmons.end())
{