在好例子网,分享、交流、成长!
您当前所在位置:首页C/C++ 开发实例图形和图像处理 → C++ 二维码识别

C++ 二维码识别

图形和图像处理

下载此实例
  • 开发语言:C/C++
  • 实例大小:4.03M
  • 下载次数:152
  • 浏览次数:3813
  • 发布时间:2015-01-07
  • 实例类别:图形和图像处理
  • 发 布 人:love
  • 文件格式:.rar
  • 所需积分:2
 相关标签: c++

实例介绍

【实例简介】

【实例截图】

from clipboard

【核心代码】


// 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];

}


标签: c++

实例下载地址

C++ 二维码识别

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

第 1 楼 KienLu 发表于: 2017-04-06 16:33 48
666

支持(0) 盖楼(回复)

发表评论

(您的评论需要经过审核才能显示)

查看所有2条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警