#include "StdAfx.h" #include "Util.h" #include "..\zxinglib\zxing\BinaryBitmap.h" #include "..\zxinglib\zxing\qrcode\QRCodeReader.h" #include "GrayImageSource.h" #include "..\zxinglib\zxing\common\GlobalHistogramBinarizer.h" #include "schema_struct.h" #include "zxing\MultiFormatReader.h" #include "zxing\oned\Code128Reader.h" using namespace std; using namespace identify::result; bool sort_locate_point_by_x(const CvRect c1, const CvRect c2) { return c1.x < c2.x; } bool sort_locate_point_by_y(const CvRect c1, const CvRect c2) { return c1.y < c2.y; } bool sortx(const CvContour * c1, const CvContour * c2) { return c1->rect.x < c2->rect.x; } bool sorty(const CvContour * c1, const CvContour * c2) { return c1->rect.y < c2->rect.y; } struct parrent_desc { CvPoint2D32f center; double angle; double d; }; template inline double get_distance(P1 p1, P2 p2){ double dx = p1.x - p2.x; double dy = p1.y - p2.y; return sqrt(dx*dx + dy*dy); } //该函数主要用于修复二维码,通过轮廓查找二维码的3个定位点,保证3个定位点完整性,其他区域不做处理 int RepairQrCode(IplImage* gray, IplImage*& dst){ #define REPAIRQRCODE_DEBUG 0 try{ CvSize size = cvGetSize(gray); int w = size.width; int h = size.height; #if REPAIRQRCODE_DEBUG IplImage* gray_debug=cvCloneImage(gray); IplImage* color=cvCreateImage(cvSize(w,h),IPL_DEPTH_8U,3); cvCvtColor(gray,color,CV_GRAY2BGR); #endif IplImage* binary = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); cvThreshold(gray, binary, 150, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); //cvThreshold(gray,binary,150,255,CV_THRESH_BINARY_INV); //cvAdaptiveThreshold(gray,binary,255,CV_ADAPTIVE_THRESH_GAUSSIAN_C,CV_THRESH_BINARY_INV,21,20); CvSeq * contour = NULL; CvMemStorage * storage = cvCreateMemStorage(); IplImage* temp_binary = cvCloneImage(binary); int contours = cvFindContours(temp_binary, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE); std::vector parrents; for (CvContour * c = (CvContour *)contour; c != NULL; c = (CvContour *)c->h_next) { CvBox2D box = cvMinAreaRect2(c, storage); if (box.size.width >= 20 && box.size.height >= 20 && box.size.width < max((double)box.size.height + 1, box.size.height*1.2) && box.size.height < max((double)box.size.width + 1, box.size.width*1.2)){ double area = cvContourArea(c); if (area < box.size.width*box.size.height*0.8)continue; double d = sqrt(box.size.width*box.size.height); //可能的半径 double r[] = { d / (3.0 / 7.0) / 2.0, d / (5.0 / 7.0) / 2.0, d / (7.0 / 7.0) / 2.0 }; double sina = sin(box.angle); double cosa = cos(box.angle); int w[10], b[10]; BOOL _find = FALSE; for (int i = 0; i < 3; i++) { memset(w, 0, sizeof(w)); memset(b, 0, sizeof(b)); int xx, yy; for (int x = (int)-(r[i] + 1); x < r[i] + 1; x++) { for (int y = (int)-(r[i] + 1); y < r[i] + 1; y++) { xx = static_cast( cosa*x + sina*y + box.center.x); yy = static_cast(-sina*x + cosa*y + box.center.y); if (xx < 0 || yy < 0 || xx >= binary->width || yy >= binary->height){ continue; } if (CV_IMAGE_ELEM(binary, unsigned char, yy, xx)){ if (max(abs(x), abs(y)) <= 1.5 / 3.5*r[i]){ b[0]++; } else if (max(abs(x), abs(y)) <= 2.5 / 3.5*r[i]){ b[1]++; } else if (max(abs(x), abs(y)) <= 3.5 / 3.5*r[i]){ b[2]++; } } else{ if (max(abs(x), abs(y)) <= 1.5 / 3.5*r[i]){ w[0]++; } else if (max(abs(x), abs(y)) <= 2.5 / 3.5*r[i]){ w[1]++; } else if (max(abs(x), abs(y)) <= 3.5 / 3.5*r[i]){ w[2]++; } } } } if (w[0]b[1] && w[2] < b[2]){ _find = TRUE; parrent_desc parrent_t; parrent_t.center = box.center; parrent_t.d = r[i] * 2; parrent_t.angle = box.angle; parrents.push_back(parrent_t); break; } } if (!_find)continue; } } vector flags(parrents.size()); vector marged; for (std::size_t i = 0; i < parrents.size(); i++) { if (flags[i] == 1)continue; flags[i] = 1; vector temp_v; temp_v.push_back(&parrents[i]); for (std::size_t j = i + 1; j < parrents.size(); j++) { if (flags[j] == 0){ if ( parrents[i].dmin(parrents[j].d - 2, parrents[j].d*0.8) && get_distance(parrents[i].center, parrents[j].center) < max((double)2, parrents[i].d * 5 / 7) ){ temp_v.push_back(&parrents[j]); flags[j] = 1; } } } parrent_desc parrent_de; parrent_de.angle = 0; parrent_de.d = 0; parrent_de.center.x = 0; parrent_de.center.y = 0; for (std::size_t j = 0; j < temp_v.size(); j++) { parrent_de.angle += temp_v[j]->angle; parrent_de.d += temp_v[j]->d; parrent_de.center.x += temp_v[j]->center.x; parrent_de.center.y += temp_v[j]->center.y; } parrent_de.angle /= temp_v.size(); parrent_de.d /= temp_v.size(); parrent_de.center.x /= temp_v.size(); parrent_de.center.y /= temp_v.size(); marged.push_back(parrent_de); #if REPAIRQRCODE_DEBUG cvDrawRect(color,cvPoint(parrent_de.center.x-parrent_de.d/2,parrent_de.center.y-parrent_de.d/2),cvPoint(parrent_de.center.x+parrent_de.d/2,parrent_de.center.y+parrent_de.d/2),cvScalar(0,0,255),1,CV_AA); #endif } BOOL success = FALSE; if (marged.size() == 3){//如果找到3个定位点//生成二维码 double d = (marged[0].d + marged[1].d + marged[2].d) / 3; CvPoint2D32f center; CvPoint2D32f o; double d0_1 = get_distance(marged[0].center, marged[1].center); double d1_2 = get_distance(marged[1].center, marged[2].center); double d2_0 = get_distance(marged[2].center, marged[0].center); double maxd; if (d0_1 > d2_0){ if (d0_1 > d1_2){ center = cvPoint2D32f((marged[0].center.x + marged[1].center.x) / 2, (marged[0].center.y + marged[1].center.y) / 2); o = marged[2].center; maxd = d0_1; } else{ center = cvPoint2D32f((marged[2].center.x + marged[1].center.x) / 2, (marged[2].center.y + marged[1].center.y) / 2); o = marged[0].center; maxd = d1_2; } } else{ if (d2_0 > d1_2){ center = cvPoint2D32f((marged[0].center.x + marged[2].center.x) / 2, (marged[0].center.y + marged[2].center.y) / 2); o = marged[1].center; maxd = d2_0; } else{ center = cvPoint2D32f((marged[2].center.x + marged[1].center.x) / 2, (marged[2].center.y + marged[1].center.y) / 2); o = marged[0].center; maxd = d1_2; } } double qr_size = maxd*sqrt(2.0) / 2 + d; double per_size = (d / 7); int qr_count = static_cast(qr_size / per_size + 0.5); per_size = qr_size / qr_count; double sin_dst; double cos_dst; double sin_src; double cos_src; double da, db; caculate_sc(cvPoint2D32f(100, 100), cvPoint2D32f(0, 0), sin_src, cos_src, db); caculate_sc(center, o, sin_dst, cos_dst, da); double sina_b = -sin_dst*cos_src + cos_dst*sin_src; double cosa_b = cos_dst*cos_src + sin_dst*sin_src; int xx, yy; int * wf = new int[qr_count*qr_count]; int * bf = new int[qr_count*qr_count]; int * gh = new int[qr_count*qr_count]; memset(wf, 0, sizeof(int)*qr_count*qr_count); memset(bf, 0, sizeof(int)*qr_count*qr_count); memset(gh, 0, sizeof(int)*qr_count*qr_count); double dddx = -3.5*per_size; for (int x = 0; x <= qr_size; x++, dddx++) { double dddy = -3.5*per_size; for (int y = 0; y <= qr_size; y++, dddy++) { xx = static_cast(cosa_b*dddx + sina_b*dddy + o.x); yy = static_cast(-sina_b*dddx + cosa_b*dddy + o.y); if (xx < 0 || yy < 0 || xx >= binary->width || yy >= binary->height){ continue; } int indexx = static_cast(x / per_size); int indexy = static_cast(y / per_size); #if REPAIRQRCODE_DEBUG CV_IMAGE_ELEM(gray_debug,unsigned char,yy,xx) /= 2; if(x-indexx*per_size<1||y-indexy*per_size<1)CV_IMAGE_ELEM(gray_debug,unsigned char,yy,xx) = 255; #endif if (indexx < 0 || indexx >= qr_count || indexy < 0 || indexy >= qr_count){ continue; } gh[indexy*qr_count + indexx] += CV_IMAGE_ELEM(gray, unsigned char, yy, xx); if (CV_IMAGE_ELEM(binary, unsigned char, yy, xx)){ bf[indexy*qr_count + indexx]++; } else{ wf[indexy*qr_count + indexx]++; } #if REPAIRQRCODE_DEBUG CV_IMAGE_ELEM(gray_debug,unsigned char,yy,xx) /= 2; if(x-indexx*per_size<1||y-indexy*per_size<1)CV_IMAGE_ELEM(binary,unsigned char,yy,xx) = 128; #endif } } long sum_gray = 0; for (int i = 0; i < qr_count*qr_count; i++) { sum_gray += gh[i]; } double gray_avg = sum_gray / (double)(qr_count*qr_count); #if REPAIRQRCODE_DEBUG cvShowImage("binary",binary); cvShowImage("gray_debug",gray_debug); cvShowImage("color",color); #endif //生成二维码 IplImage* _img = cvCreateImage(cvSize(qr_count * 5, qr_count * 5), IPL_DEPTH_8U, 1); for (int x = 0; x < qr_count; x++) { for (int y = 0; ywf[y*qr_count + x] * 70) ? 0 : 255; v = gh[y*qr_count + x] < gray_avg ? 0 : 255; for (int mm = 0; mm < 5; mm++) { for (int nn = 0; nn < 5; nn++) { CV_IMAGE_ELEM(_img, unsigned char, (y * 5 + mm), (x * 5 + nn)) = v; } } } } delete bf; delete wf; #if REPAIRQRCODE_DEBUG cvShowImage("_img",_img); cvWaitKey(0); #endif //重画3个定位点,保证正确无误 CvPoint p[3] = { cvPoint(3, 3), cvPoint(qr_count - 4, 3), cvPoint(3, qr_count - 4) }; int vs[5] = { 0, 0, 255, 0, 255 }; int fx[] = { 1, 1, -1, -1 }; int fy[] = { 1, -1, 1, -1 }; for (int i = 0; i < 3; i++) { for (int k = 0; k < 4; k++) { for (int m = 0; m < 5; m++) { int x = p[i].x + fx[k] * m; if (x < 0 || x >= qr_count)continue; for (int n = 0; n < 5; n++) { int y = p[i].y + fy[k] * n; if (y < 0 || y >= qr_count)continue; for (int mm = 0; mm < 5; mm++) { for (int nn = 0; nn < 5; nn++) { CV_IMAGE_ELEM(_img, unsigned char, (y * 5 + mm), (x * 5 + nn)) = vs[max(m, n)]; } } } } } } dst = _img; #if REPAIRQRCODE_DEBUG cvShowImage("_img",_img); cvWaitKey(0); #endif success = TRUE; } cvReleaseImage(&binary); return success ? IDF_SUCCESS : IDF_FAILURE; } catch (...){ return IDF_FAILURE; } } int PraseQRCode_Normal(IplImage* img, std::string & resultString){ try { Ref source(new CGrayImageSource(img)); Ref binarizer(new GlobalHistogramBinarizer(source)); Ref image(new BinaryBitmap(binarizer)); DecodeHints hints(DecodeHints::DEFAULT_HINT); hints.setTryHarder(true); zxing::qrcode::QRCodeReader reader; Ref result(reader.decode(image, hints)); resultString = result->getText()->getText(); } catch (...){ return IDF_FAILURE; } return IDF_SUCCESS; } int PraseBarCode_Normal(IplImage* img, std::string & resultString){ try { Ref source(new CGrayImageSource(img)); Ref binarizer(new GlobalHistogramBinarizer(source)); Ref image(new BinaryBitmap(binarizer)); //DecodeHints hints(DecodeHints::CODE_128_HINT|DecodeHints::CODE_39_HINT); DecodeHints hints; hints.setTryHarder(true); //zxing::MultiFormatReader reader; zxing::oned::Code128Reader reader; Ref result(reader.decode(image, hints)); resultString = result->getText()->getText(); } catch (std::exception e){ const char* str = e.what(); return IDF_FAILURE; } return IDF_SUCCESS; } int PraseQRCode(IplImage* img, std::string & resultString) { int ret; ret = PraseQRCode_Normal(img, resultString); if (ret == IDF_SUCCESS) return ret; CvRect rect = cvGetImageROI(img); IplImage* resized_gray = cvCreateImage(cvSize(rect.width * 3, rect.height * 3), IPL_DEPTH_8U, 1); IplImage* resized_binary = cvCreateImage(cvSize(rect.width * 3, rect.height * 3), IPL_DEPTH_8U, 1); if (img->nChannels > 1){ IplImage* tmp_gray = cvCreateImage(cvSize(rect.width, rect.height), IPL_DEPTH_8U, 1); cvCvtColor(img, tmp_gray, CV_BGR2GRAY); cvResize(tmp_gray, resized_gray); cvReleaseImage(&tmp_gray); } else{ cvResize(img, resized_gray); } cvThreshold(resized_gray, resized_binary, 80, 255, CV_THRESH_BINARY); ret = PraseQRCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 170, 255, CV_THRESH_BINARY); ret = PraseQRCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 200, 255, CV_THRESH_BINARY); ret = PraseQRCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } IplImage * repaired_img = NULL; int repaired = RepairQrCode(resized_gray, repaired_img); if (repaired == IDF_SUCCESS){ ret = PraseQRCode_Normal(repaired_img, resultString); cvReleaseImage(&repaired_img); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } } if (TRUE) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return IDF_PRASE_QR_ERROR; } } int PraseBarCode0(IplImage* img, std::string & resultString); int PraseBarCode(IplImage* img, std::string & resultString){ int ret; ret = PraseBarCode_Normal(img, resultString); if (ret == IDF_SUCCESS) return ret; IplImage *temp = cvCreateImage(cvSize(img->height, img->width), img->depth, img->nChannels); cvTranspose(img, temp); cvFlip(temp, temp, 0); ret = PraseBarCode_Normal(temp, resultString); if (ret == IDF_SUCCESS){ cvReleaseImage(&temp); return ret; } ret = PraseBarCode0(img, resultString); if (ret == IDF_SUCCESS){ cvReleaseImage(&temp); return ret; } ret = PraseBarCode0(temp, resultString); { cvReleaseImage(&temp); return ret; } } int PraseBarCode0(IplImage* img, std::string & resultString) { int ret; IplImage *temp = cvCreateImage(cvSize(img->height, img->width), img->depth, img->nChannels); cvTranspose(img, temp); cvFlip(temp, temp, 0); ret = PraseBarCode_Normal(temp, resultString); cvReleaseImage(&temp); if (ret == IDF_SUCCESS) return ret; ret = PraseBarCode_Normal(img, resultString); if (ret == IDF_SUCCESS) return ret; CvRect rect = cvGetImageROI(img); IplImage* resized_gray = cvCreateImage(cvSize(rect.width * 3, rect.height * 3), IPL_DEPTH_8U, 1); IplImage* resized_binary = cvCreateImage(cvSize(rect.width * 3, rect.height * 3), IPL_DEPTH_8U, 1); if (img->nChannels > 1){ IplImage* tmp_gray = cvCreateImage(cvSize(rect.width, rect.height), IPL_DEPTH_8U, 1); cvCvtColor(img, tmp_gray, CV_BGR2GRAY); cvResize(tmp_gray, resized_gray); cvReleaseImage(&tmp_gray); } else{ cvResize(img, resized_gray); } cvThreshold(resized_gray, resized_binary, 80, 255, CV_THRESH_BINARY); ret = PraseBarCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 170, 255, CV_THRESH_BINARY); ret = PraseBarCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 200, 255, CV_THRESH_BINARY); ret = PraseBarCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 215, 255, CV_THRESH_BINARY); ret = PraseBarCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 230, 255, CV_THRESH_BINARY); ret = PraseBarCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 240, 255, CV_THRESH_BINARY); ret = PraseBarCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } cvThreshold(resized_gray, resized_binary, 250, 255, CV_THRESH_BINARY); ret = PraseBarCode_Normal(resized_binary, resultString); if (ret == IDF_SUCCESS) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return ret; } if (TRUE) { cvReleaseImage(&resized_gray); cvReleaseImage(&resized_binary); return IDF_PRASE_QR_ERROR; } } double degree(const int& x1, const int& y1, const int& x2, const int& y2) { return acos((x2 - x1) / sqrt((double)(y2 - y1)*(y2 - y1) + (x2 - x1)*(x2 - x1))); } int GetBlackArea(const IplImage * dst, int valve /*=180*/) { int blackArea = 0; CvRect rect = cvGetImageROI(dst); int(*GetGray)(const IplImage * dst, int x, int y); if (dst->nChannels == 1)GetGray = GetGrayValue; else GetGray = GetBGRGray; for (int y = rect.y, endy = rect.y + rect.height; y < endy; y++) { for (int x = rect.x, endx = rect.x + rect.width; x < endx; x++) { if (GetGray(dst, x, y) < valve)blackArea++; } } return blackArea; } void rgb2hsv(const int& r, const int& g, const int& b, float& h, float& s, float& v) { float _min = r g ? (r > b ? r : b) : (g>b ? g : b); v = _max; s = (_max == 0) ? 0 : (_max - _min) / _max; if (_max == _min)h = 0; else if (_max == r)h = 60 * (g - b) / (_max - _min); else if (_max == g)h = 60 * (b - r) / (_max - _min) + 120; else if (_max == b)h = 60 * (r - g) / (_max - _min) + 240; if (h < 0)h = h + 360; } int GetBGRGray(const IplImage * dst, int x, int y) { /*http://blog.sina.com.cn/s/blog_74cf26810100rjc3.html Gray = (R*38 + G*75 + B*15) >> 7 */ return ((0xff & dst->imageData[y*dst->widthStep + x*dst->nChannels]) * 15 + (0xff & dst->imageData[y*dst->widthStep + x*dst->nChannels + 1]) * 75 + (0xff & dst->imageData[y*dst->widthStep + x*dst->nChannels + 2]) * 38) >> 7; } int GetGrayValue(const IplImage * dst, int x, int y) { return 0xff & dst->imageData[y*dst->widthStep + x]; } IplImage* CutRotateImage(const IplImage* img, CvPoint center, CvSize size, float degree) { double angle = degree*CV_PI / 180.; IplImage * result = cvCreateImage(size, img->depth, img->nChannels); float m[6] = { cos(angle), sin(angle), center.x, -sin(angle), cos(angle), center.y }; CvMat M = cvMat(2, 3, CV_32F, m); cvGetQuadrangleSubPix(img, result, &M); return result; } IplImage* CutImage(IplImage* img, CvRect rect) { IplImage* result = cvCreateImage(cvSize(rect.width, rect.height), img->depth, img->nChannels); cvGetRectSubPix(img, result, cvPoint2D32f(rect.x + rect.width*0.5, rect.y + rect.height*0.5)); return result; } //注意:当字符串为空时,也会返回一个空字符串 void split(std::string& s, std::string& delim, std::vector< std::string >* ret) { size_t last = 0; size_t index = s.find_first_of(delim, last); while (index != std::string::npos) { ret->push_back(s.substr(last, index - last)); last = index + 1; index = s.find_first_of(delim, last); } if (index - last > 0) { ret->push_back(s.substr(last, index - last)); } } void SetTBLR(identify::autoschema::ASCH_SchemaQuestionScore& score) { score.lt.x = score.lb.x = (int)(0.5 + score.centerx - score.width / 2.0); score.rt.x = score.rb.x = (int)(0.5 + score.centerx + score.width / 2.0); score.lt.y = score.rt.y = (int)(0.5 + score.centery - score.height / 2.0); score.lb.y = score.rb.y = (int)(0.5 + score.centery + score.height / 2.0); }