基本信息
源码名称:C++ 二维码识别
源码大小:4.03M
文件格式:.rar
开发语言:C/C++
更新时间:2015-01-07
友情提示:(无需注册或充值,赞助后即可获取资源下载链接)
嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300
本次赞助数额为: 2 元×
微信扫码支付:2 元
×
请留下您的邮箱,我们将在2小时内将文件发到您的邮箱
源码介绍
// FinderPattern.cpp: implementation of the FinderPattern class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "QRcodeDecoder.h" #include "FinderPattern.h" #include<vector> using std::vector; #include<math.h> #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// FinderPattern::FinderPattern() { } FinderPattern::~FinderPattern() { } //探测图形检查 void FinderPattern::findFinderPattern(BYTE ** mybitmap, int mynWidth, int mynHeight, int myDECIMAL_POINT) { DECIMAL_POINT=myDECIMAL_POINT; bitmap=mybitmap; nWidth=mynWidth; nHeight=mynHeight; findLineAcross(); findLineCross(); getCenter(m_lineCross,m_lineCrossCnt); getAngle(m_center,m_centerCnt); sort(m_center,m_sincos); getWidth(); // moduleSize for version recognition m_moduleSize[0]=(m_width[UL] << DECIMAL_POINT)/7; m_moduleSize[1]=(m_width[UR] << DECIMAL_POINT)/7; m_moduleSize[2]=(m_width[DL] << DECIMAL_POINT)/7; m_version = calcRoughVersion(m_center, m_width); if (m_version > 6) { m_version = calcExactVersion(m_center, m_sincos, m_moduleSize); } //return FinderPattern (center, version, sincos, width, moduleSize); } //粗略版本号 int FinderPattern::calcRoughVersion(Point * center, int * width) { const int dp = DECIMAL_POINT; int lengthAdditionalLine = (Line(center[UL], center[UR]).getLength()) << dp ; int avarageWidth = ((width[UL] width[UR]) << dp) / 14; int roughVersion = ((lengthAdditionalLine / avarageWidth) - 10) / 4; if (((lengthAdditionalLine / avarageWidth) - 10) % 4 >= 2) { roughVersion ; } return roughVersion; } //精确版本号 int FinderPattern::calcExactVersion(Point * centers, int * angle, int * moduleSize) { BYTE * VersionInfo = new BYTE[18]; Point * points = new Point[18]; Point target; //右上 --- 版本信息1 Axis axis = Axis(angle, moduleSize[UR], DECIMAL_POINT); //UR axis.setOrigin(centers[UR]); for (int y = 0; y < 6; y ) { for (int x = 0; x < 3; x ) { target = axis.translate(x - 7, y - 3); VersionInfo[x y * 3] = bitmap[target.x][target.y]; points[x y * 3] = target; } } //纠错检查 int errorCount=0,versionBase; for(versionBase=0;versionBase<=33;versionBase ) { errorCount=0; for(int j=0;j<18;j ) { if((VersionInfo[j]^(VersionInfoBit[versionBase]>>j))%2==1) errorCount ; } if(errorCount<=3)break; } if(errorCount<=3) return 7 versionBase; else { int k=0; //左下 --- 版本信息2 axis.setOrigin(centers[DL]); axis.setModulePitch(moduleSize[DL]); //DL for (int x = 0; x < 6; x ) { for (int y = 0; y < 3; y ) { target = axis.translate(x - 3, y - 7); VersionInfo[y x * 3] = bitmap[target.x][target.y]; points[x y * 3] = target; } } //纠错检查 errorCount=0; for(versionBase=0;versionBase<=33;versionBase ) { errorCount=0; for(int j=0;j<18;j ) { if((VersionInfo[j]^(VersionInfoBit[versionBase]>>j))%2==1) errorCount ; } if(errorCount<=3)break; } if(errorCount<=3) return 7 versionBase; else { AfxMessageBox("版本信息纠错失败"); exit(0); } } } //获取探测图形中心点 void FinderPattern::getCenter(Line * crossLines,int crossLinesCnt) { int i,j; vector<Point> centers; for (i = 0; i < crossLinesCnt - 1; i ) { Line compareLine = crossLines[i]; for (j = i 1; j < crossLinesCnt; j ) { Line comparedLine = crossLines[j]; if (line.isCross(compareLine, comparedLine)) { int x = 0; int y = 0; if (compareLine.isHorizontal()) { x = compareLine.getCenter().x; y = comparedLine.getCenter().y; } else { x = comparedLine.getCenter().x; y = compareLine.getCenter().y; } centers.push_back(Point(x,y)); } } } m_centerCnt=centers.size(); m_center=new Point[centers.size()]; for (i = 0; i < m_centerCnt; i ) m_center[i] = centers[i]; if (m_centerCnt != 3) { AfxMessageBox("Invalid number of Finder Pattern detected"); exit(0); } } //检查角度 obtain slope of symbol void FinderPattern::getAngle(Point * centers,int centersCnt) { int i; Line * additionalLine = new Line[3]; for (i = 0; i < 3; i ) { additionalLine[i] = Line(centers[i],centers[(i 1) % 3]); } // remoteLine - does not contain UL center Line remoteLine = line.getLongest(additionalLine,3); Point originPoint; for (i = 0; i < centersCnt; i ) { if (!remoteLine.getP1().equals(centers[i]) && !remoteLine.getP2().equals(centers[i])) { originPoint = centers[i]; break; } } //canvas.println("originPoint is: " originPoint); Point remotePoint; //with origin that the center of Left-Up Finder Pattern, determine other two patterns center. //then calculate symbols angle if (originPoint.y <= remoteLine.getP1().y && //1st or 2nd quadrant originPoint.y <= remoteLine.getP2().y) if (remoteLine.getP1().x < remoteLine.getP2().x) remotePoint = remoteLine.getP2(); else remotePoint = remoteLine.getP1(); else if (originPoint.x >= remoteLine.getP1().x && //2nd or 3rd quadrant originPoint.x >= remoteLine.getP2().x) if (remoteLine.getP1().y < remoteLine.getP2().y) remotePoint = remoteLine.getP2(); else remotePoint = remoteLine.getP1(); else if (originPoint.y >= remoteLine.getP1().y && //3rd or 4th quadrant originPoint.y >= remoteLine.getP2().y) if (remoteLine.getP1().x < remoteLine.getP2().x) remotePoint = remoteLine.getP1(); else remotePoint = remoteLine.getP2(); else //1st or 4th quadrant if (remoteLine.getP1().y < remoteLine.getP2().y) remotePoint = remoteLine.getP1(); else remotePoint = remoteLine.getP2(); int r = Line(originPoint, remotePoint).getLength(); m_sincos[0] = ((remotePoint.y - originPoint.y) << DECIMAL_POINT) / r; //Sin m_sincos[1] = ((remotePoint.x - originPoint.x) << DECIMAL_POINT) / r; //Cos } //按顺序存储探测图形 sort center of finder patterns as Left-Up: points[0], Right-Up: points[1], Left-Down: points[2]. void FinderPattern::sort(Point * centers, int * angle) { Point * sortedCenters = new Point[3]; int quadrant; int sin = angle[0]; int cos = angle[1]; if (sin >= 0 && cos > 0)quadrant=1; else if (sin > 0 && cos <= 0)quadrant=2; else if (sin <= 0 && cos < 0)quadrant=3; else if (sin < 0 && cos >= 0)quadrant=4; else quadrant=0; switch (quadrant) { case 1: sortedCenters[1] = getPointAtSide(centers, 3, RIGHT, BOTTOM); sortedCenters[2] = getPointAtSide(centers, 3, BOTTOM, LEFT); break; case 2: sortedCenters[1] = getPointAtSide(centers, 3, BOTTOM, LEFT); sortedCenters[2] = getPointAtSide(centers, 3, TOP, LEFT); break; case 3: sortedCenters[1] = getPointAtSide(centers, 3, LEFT, TOP); sortedCenters[2] = getPointAtSide(centers, 3, RIGHT, TOP); break; case 4: sortedCenters[1] = getPointAtSide(centers, 3, TOP, RIGHT); sortedCenters[2] = getPointAtSide(centers, 3, BOTTOM, RIGHT); break; } //last of centers is Left-Up patterns one for (int i = 0; i < 3; i ) { if (!centers[i].equals(sortedCenters[1]) && !centers[i].equals(sortedCenters[2])) { sortedCenters[0] = centers[i]; } } for (i = 0; i < 3; i ) centers[i]=sortedCenters[i]; } //获取宽度 void FinderPattern::getWidth() { for (int i = 0; i < 3; i ) { boolean flag = false; int lx, rx; int y = m_center[i].y; for (lx = m_center[i].x; lx >= 0; lx--) { if (bitmap[lx][y] == 1/*QRCodeImageReader.POINT_DARK*/ && bitmap [lx - 1][y] == 0/*QRCodeImageReader.POINT_LIGHT*/) { if (flag == false) flag = true; else break; } } flag = false; for (rx = m_center[i].x; rx < nWidth; rx ) { if (bitmap[rx][y] == 1/*QRCodeImageReader.POINT_DARK*/ && bitmap[rx 1][y] == 0/*QRCodeImageReader.POINT_LIGHT*/) { if (flag == false) flag = true; else break; } } m_width[i] = (rx - lx 1); } } Point FinderPattern::getPointAtSide(Point * points,int pointCnt,int side1,int side2) { int x = ((side1 == RIGHT || side2 == RIGHT) ? 0 : MAX_VALUE); int y = ((side1 == BOTTOM || side2 == BOTTOM) ? 0 : MAX_VALUE); Point sidePoint = Point(x, y); for (int i = 0; i < pointCnt; i ) { switch (side1) { case RIGHT: if (sidePoint.x < points[i].x) { sidePoint = points[i]; } else if (sidePoint.x == points[i].x) { if (side2 == BOTTOM) { if (sidePoint.y < points[i].y) { sidePoint = points[i]; } } else { if (sidePoint.y > points[i].y) { sidePoint = points[i]; } } } break; case BOTTOM: if (sidePoint.y < points[i].y) { sidePoint = points[i]; } else if (sidePoint.y == points[i].y) { if (side2 == RIGHT) { if (sidePoint.x < points[i].x) { sidePoint = points[i]; } } else { if (sidePoint.x > points[i].x) { sidePoint = points[i]; } } } break; case LEFT: if (sidePoint.x > points[i].x) { sidePoint = points[i]; } else if (sidePoint.x == points[i].x) { if (side2 == BOTTOM) { if (sidePoint.y < points[i].y) { sidePoint = points[i]; } } else { if (sidePoint.y > points[i].y) { sidePoint = points[i]; } } } break; case TOP: if (sidePoint.y > points[i].y) { sidePoint = points[i]; } else if (sidePoint.y == points[i].y) { if (side2 == RIGHT) { if (sidePoint.x < points[i].x) { sidePoint = points[i]; } } else { if (sidePoint.x > points[i].x) { sidePoint = points[i]; } } } break; } } return sidePoint; } //检验探测图形比例 bool FinderPattern::checkPattern(int * buffer, int pointer) { int modelRatio[] = {1, 1, 3, 1, 1}; int baselength = 0; for (int i = 0; i < 5; i ) { baselength = buffer[i]; } // pseudo fixed point calculation. I think it needs smarter code baselength <<= DECIMAL_POINT; baselength /= 7; for (i = 0; i < 5; i ) { int leastlength = baselength * modelRatio[i] - baselength / 2; int mostlength = baselength * modelRatio[i] baselength / 2; //TODO rough finder pattern detection int targetlength = buffer[(pointer i 1) % 5] << DECIMAL_POINT; if (targetlength < leastlength || targetlength > mostlength) { return false; } } return true; } void FinderPattern::findLineAcross() { int i,j; const int READ_HORIZONTAL = 0; const int READ_VERTICAL = 1; //int currentX = 0, currentY = 0; Point current; vector<Line> lineAcross; //buffer contains recent length of modules which has same brightness int * lengthBuffer = new int[5]; for(i=0;i<5;i ) lengthBuffer[i]=0; int bufferPointer = 0; int direction = READ_HORIZONTAL; //start to read horizontally BYTE lastElement = 0;/*QRCodeImageReader.POINT_LIGHT*/ while(true) { //check points in image BYTE currentElement = bitmap[current.x][current.y]; if (currentElement == lastElement) { //target point has same brightness with last point lengthBuffer[bufferPointer] ; } else { //target point has different brightness with last point if (currentElement == 0/*QRCodeImageReader.POINT_LIGHT*/) { if (checkPattern(lengthBuffer, bufferPointer)) { //detected pattern int x1, y1, x2, y2; if (direction == READ_HORIZONTAL) { //obtain X coordinates of both side of the detected horizontal pattern x1 = current.x; for (j = 0; j < 5; j ) { x1 -= lengthBuffer[j]; } x2 = current.x - 1; //right side is last X coordinate y1 = y2 = current.y; } else { x1 = x2 = current.x; //obtain Y coordinates of both side of the detected vertical pattern // upper side is sum of length of buffer y1 = current.y; for (j = 0; j < 5; j ) { y1 -= lengthBuffer[j]; } y2 = current.y - 1; // bottom side is last Y coordinate } lineAcross.push_back(Line(x1, y1, x2, y2)); } } bufferPointer = (bufferPointer 1) % 5; lengthBuffer[bufferPointer] = 1; lastElement = !lastElement; } // determine if read next, change read direction or terminate this loop if (direction == READ_HORIZONTAL) { if (current.x < nWidth - 1) { current.translate(1, 0); } else if (current.y < nHeight - 1) { current.set(0, current.y 1); lengthBuffer = new int[5]; } else { current.set(0, 0); //reset target point lengthBuffer = new int[5]; direction = READ_VERTICAL; //start to read vertically } } else { //reading vertically if (current.y < nHeight - 1) current.translate(0, 1); else if (current.x < nWidth - 1) { current.set(current.x 1, 0); lengthBuffer = new int[5]; } else { break; } } } m_lineAcrossCnt = lineAcross.size(); m_lineAcross = new Line[lineAcross.size()]; for (i = 0; i < lineAcross.size(); i ) m_lineAcross[i] = lineAcross[i]; } bool FinderPattern::cantNeighbor(Line line1, Line line2) { if (line.isCross(line1, line2)) return true; return line1.isHorizontal()? abs(line1.getP1().y - line2.getP1().y) > 1 : abs(line1.getP1().x - line2.getP1().x) > 1; } void FinderPattern::findLineCross() { int i,j; vector<Line> crossLines; vector<Line> lineNeighbor; vector<Line> lineCandidate; Line compareLine; for (i = 0; i < m_lineAcrossCnt; i ) lineCandidate.push_back(m_lineAcross[i]); for (i = 0; i < lineCandidate.size() - 1; i ) { lineNeighbor.clear(); lineNeighbor.push_back(lineCandidate[i]); for (j = i 1; j < lineCandidate.size(); j ) { if (line.isNeighbor(lineNeighbor.back(), lineCandidate[j])) { lineNeighbor.push_back(lineCandidate[j]); compareLine = lineNeighbor.back(); if (lineNeighbor.size() * 5 > compareLine.getLength() && j == lineCandidate.size() - 1) { crossLines.push_back(lineNeighbor[lineNeighbor.size()/2]); for (int k = 0; k < lineNeighbor.size(); k ) { for(int index=0;index<lineCandidate.size();index ) { if(lineCandidate[index].x1==lineNeighbor[k].x1 && lineCandidate[index].y1==lineNeighbor[k].y1 && lineCandidate[index].x2==lineNeighbor[k].x2 && lineCandidate[index].y2==lineNeighbor[k].y2) lineCandidate.erase(&lineCandidate[index]); } //lineCandidate.removeElement(lineNeighbor.elementAt(k)); } } } //terminate comparison if there are no possibility for found neighbour lines else if(cantNeighbor(lineNeighbor.back(), lineCandidate[j]) || (j == lineCandidate.size() - 1)) { compareLine = lineNeighbor.back(); //determine lines across Finder Patterns when number of neighbour lines are bigger than 1/6 length of theirselves if (lineNeighbor.size() * 6 > compareLine.getLength()) { crossLines.push_back(lineNeighbor[lineNeighbor.size()/2]); for (int k = 0; k < lineNeighbor.size(); k ) { for(int index=0;index<lineCandidate.size();index ) { if(lineCandidate[index].x1==lineNeighbor[k].x1 && lineCandidate[index].y1==lineNeighbor[k].y1 && lineCandidate[index].x2==lineNeighbor[k].x2 && lineCandidate[index].y2==lineNeighbor[k].y2) lineCandidate.erase(&lineCandidate[index]); } //lineCandidate.removeElement(lineNeighbor.elementAt(k)); } } break; } } } m_lineCrossCnt = crossLines.size(); m_lineCross = new Line[crossLines.size()]; for (i = 0; i < crossLines.size(); i ) m_lineCross[i] = crossLines[i]; }