⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 barrecogview.cpp

📁 采用Visual C++开发平台开发了一个条形码识别系统。该系统采用图像处理技术对条形码图像的噪声进行处理
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	for(i=0; i<ImageHeight; i++)
	{
		if(arPixelV[i]>tempMax)
			tempMax = arPixelV[i];
		arMark[i] = false;
	}
	
	for(i=0; i<ImageHeight-1; i++)
	{
		//计算差分
		arDifference[i] = arPixelV[i+1] - arPixelV[i];

		//如果该行像素足够多且变化不大,标记为true
		if( (abs(arDifference[i])<20) && (arPixelV[i]>(0.75*tempMax)) )
			arMark[i] = true;
	}
	
	//确定包含条码的行
	int iLengthThrehold = 40;
	int iCount;
	for(i=0; i<ImageHeight-iLengthThrehold; i++)
	{
		iCount = 0;
		for(j=0; j<iLengthThrehold; j++)
		{
			if(arMark[i+j] == true)
				iCount++;
		}
		if(iCount >= 37)
		{
			ImageTop = i+10;		//确定顶部
			break;
		}
	}

	for(i=ImageHeight-1; i>=iLengthThrehold-1; i--)
	{
		iCount = 0;
		for(j=0; j<iLengthThrehold; j++)
		{
			if(arMark[i-j] == true)
				iCount++;
		}
		if(iCount >= 37)	//iLengthThrehold-3
		{
			ImageBottom = i-10;		//确定底部
			break;
		}
	}
	
	//寻找包含条形码的区域,
	//线寻找水平方向上黑象素最大的列

	//寻找左边缘,为了保证鲁棒性,在已经确定的上下边界内全局搜索
	for(i=ImageTop; i<=ImageBottom; i++)
	{
		for(j=2; j<ImageWidth; j++)
		{
			if(*(ImageArray+lRowBytes*(i)+(j-1))==(BYTE)255 && *(ImageArray+lRowBytes*(i)+(j))==(BYTE)0)
			{
				arLeftEdge[i] = j;
				break;
			}
		}
	}
	
	//为消除噪声的干扰,下面确定准确的左边界
	tempMax = 0;
	int iMax = 0;
	for(i=ImageTop; i<=ImageBottom; i++)
	{
		if(arLeftEdge[i] > tempMax)
		{
			tempMax = arLeftEdge[i];
			iMax = i;
		}
	}
	
	//倾斜度不能大于1/10
	iCount = 0;
	for(i=ImageTop; i<=ImageBottom; i++)
	{
		if( abs(tempMax-arLeftEdge[i]) < abs(i-iMax)/6+1 )
		{
			iCount++;
		}
	}
	
	if( (iCount/(ImageBottom-ImageTop))<0.6 )
		return false;
	
	//调整起点
	for(i=iMax; i>ImageTop; i--)
	{
		if( abs(arLeftEdge[i]-arLeftEdge[i-1])>=2 )
		{
			if(*(ImageArray+lRowBytes*(i-1)+(arLeftEdge[i]-1))-*(ImageArray+lRowBytes*(i-1)+(arLeftEdge[i]))==(BYTE)255)
				arLeftEdge[i-1] = arLeftEdge[i];
			else if(*(ImageArray+lRowBytes*(i-1)+(arLeftEdge[i]-2))-*(ImageArray+lRowBytes*(i-1)+(arLeftEdge[i]-1))==(BYTE)255)
				arLeftEdge[i-1] = arLeftEdge[i]-1;
			else if(*(ImageArray+lRowBytes*(i-1)+(arLeftEdge[i]))-*(ImageArray+lRowBytes*(i-1)+(arLeftEdge[i]+1))==(BYTE)255)
				arLeftEdge[i-1] = arLeftEdge[i]+1;
			else
				arLeftEdge[i-1] = arLeftEdge[i];
		}
	}
	
	for(i=iMax; i<ImageBottom; i++)
	{
		if(i == ImageBottom)
			break;
	
		if( abs(arLeftEdge[i]-arLeftEdge[i+1])>=2 )
		{
			if(*(ImageArray+lRowBytes*(i+1)+(arLeftEdge[i]-1))-*(ImageArray+lRowBytes*(i+1)+(arLeftEdge[i]))==(BYTE)255)
				arLeftEdge[i+1] = arLeftEdge[i];
			else if(*(ImageArray+lRowBytes*(i+1)+(arLeftEdge[i]-2))-*(ImageArray+lRowBytes*(i+1)+(arLeftEdge[i]-1))==(BYTE)255)
				arLeftEdge[i+1] = arLeftEdge[i]-1;
			else if(*(ImageArray+lRowBytes*(i+1)+(arLeftEdge[i]))-*(ImageArray+lRowBytes*(i+1)+(arLeftEdge[i]+1))==(BYTE)255)
				arLeftEdge[i+1] = arLeftEdge[i]+1;
			else
				arLeftEdge[i+1] = arLeftEdge[i];
		}
	}
	
	int n;
	//搜索出所有的宽度
	for(n=0; n<29; n++)
	{
		//搜索条的右边缘
		for(i=ImageTop; i<=ImageBottom; i++)
		{
			for(j = arLeftEdge[i]+1; j<ImageWidth; j++)
			{
				if(*(ImageArray+lRowBytes*(i)+(j-1))==(BYTE)0 && *(ImageArray+lRowBytes*(i)+(j))==(BYTE)255)
				{
					arLeftEdge1[i] = j;
					break;
				}
			}
			arDelta[i] = arLeftEdge1[i] - arLeftEdge[i];
		}
		
		//假定条和空的宽度最多为11
		//排序,可以认为最中间的5个宽度是平均宽度
		for(i=ImageTop; i<ImageBottom; i++)
			tempArray[i] = arDelta[i];
		
		for(i=ImageTop; i<ImageBottom; i++)
		{
			for(j=ImageBottom; j>i; j--)
			{
				int tempSwap;
				if(tempArray[j] < tempArray[j-1])
				{
					tempSwap = tempArray[j];
					tempArray[j] = tempArray[j-1];
					tempArray[j-1] = tempSwap;
				}
			}
		}
		
		if(tempArray[ImageTop+(ImageBottom-ImageTop)/2+2]-tempArray[ImageTop+(ImageBottom-ImageTop)/2-2]>1)
			return false;
		else
			arWidth[2*n] = tempArray[ImageTop+(ImageBottom-ImageTop)/2];
		
		//调整下一列边缘
		for(i=ImageTop; i<=ImageBottom; i++)
		{
			if(abs(arDelta[i] - arWidth[2*n])>2)
				arLeftEdge1[i] = arLeftEdge[i] + arWidth[2*n];
			arLeftEdge[i] = arLeftEdge1[i];
		}
		
		//搜索空的右边缘
		for(i=ImageTop; i<=ImageBottom; i++)
		{
			for(j = arLeftEdge[i]+1; j<ImageWidth; j++)
			{
				if( (*(ImageArray+lRowBytes*(i)+(j-1))==(BYTE)255) && (*(ImageArray+lRowBytes*(i)+(j))==(BYTE)0) )
				{
					arLeftEdge1[i] = j;
					break;
				}
			}
			arDelta[i] = arLeftEdge1[i] - arLeftEdge[i];
		}
		
		//假定条和空的宽度最多为11
		//排序,可以认为最中间的5个宽度是平均宽度
		for(i=ImageTop; i<ImageBottom; i++)
			tempArray[i] = arDelta[i];
		
		for(i=ImageTop; i<ImageBottom; i++)
		{
			for(j=ImageBottom; j>i; j--)
			{
				int tempSwap;
				if(tempArray[j] < tempArray[j-1])
				{
					tempSwap = tempArray[j];
					tempArray[j] = tempArray[j-1];
					tempArray[j-1] = tempSwap;
				}
			}
		}
		
		if(tempArray[ImageTop+(ImageBottom-ImageTop)/2+2]-tempArray[ImageTop+(ImageBottom-ImageTop)/2-2]>1)
			return false;
		else
			arWidth[2*n+1] = tempArray[ImageTop+(ImageBottom-ImageTop)/2];
		
		//调整下一列边缘
		for(i=ImageTop; i<=ImageBottom; i++)
		{
			if(abs(arDelta[i] - arWidth[2*n+1])>2)
				arLeftEdge1[i] = arLeftEdge[i] + arWidth[2*n+1];
			arLeftEdge[i] = arLeftEdge1[i];
		}
	}
	
	//搜索最后一个条的右边缘
	for(i=ImageTop; i<=ImageBottom; i++)
	{
		for(j = arLeftEdge[i]+1; j<ImageWidth; j++)
		{
			if( (*(ImageArray+lRowBytes*(i)+(j-1))==(BYTE)0) && (*(ImageArray+lRowBytes*(i)+(j))==(BYTE)255) )
			{
				arLeftEdge1[i] = j;
				break;
			}
		}
		arDelta[i] = arLeftEdge1[i] - arLeftEdge[i];
	}
	
	//假定条和空的宽度最多为11
	//排序,可以认为最中间的5个宽度是平均宽度
	for(i=ImageTop; i<ImageBottom; i++)
		tempArray[i] = arDelta[i];
	
	for(i=ImageTop; i<ImageBottom; i++)
	{
		for(j=ImageBottom; j>i; j--)
		{
			int tempSwap;
			if(tempArray[j] < tempArray[j-1])
			{
				tempSwap = tempArray[j];
				tempArray[j] = tempArray[j-1];
				tempArray[j-1] = tempSwap;
			}
		}
	}
	
	if(tempArray[ImageTop+(ImageBottom-ImageTop)/2+2]-tempArray[ImageTop+(ImageBottom-ImageTop)/2-2]>1)
		return false;
	else
		arWidth[2*n] = tempArray[ImageTop+(ImageBottom-ImageTop)/2];
	
	//调整下一列边缘
	for(i=ImageTop; i<=ImageBottom; i++)
	{
		if(abs(arDelta[i] - arWidth[2*n+1])>2)
			arLeftEdge1[i] = arLeftEdge[i] + tempArray[ImageTop+(ImageBottom-ImageTop)/2];
		arLeftEdge[i] = arLeftEdge1[i];
	}

	return true;
}

BOOL CBarRecogView::Recognize()
{
	//总共有7×12+3×2+5= 95个单位宽度
	//有4×12+3×2+5=59个宽度,
	int i;
	int result[12];
	double mx = 0.0;	//平均宽度

	for(i=0; i<59; i++)
		mx += (double)arWidth[i];
	mx /= 95.0;

	//起始条文
	for(i=0; i<3; i++)
	{
		double dTemp = (double)arWidth[i]/mx;
		if( dTemp<0.6 || dTemp>1.4 )
			break;
	}
	//起始码不符合要求
	//if(i<3)
	//	return false;
	
	//识别前6个
	for(i=0; i<6; i++)
	{
		result[i] = JudgNum(arWidth[i*4+3], arWidth[i*4+4], arWidth[i*4+5], arWidth[i*4+6], mx);
	}
	//识别后6个
	for(i=6; i<12; i++)
	{
		result[i] = JudgNum(arWidth[i*4+8], arWidth[i*4+9], arWidth[i*4+10], arWidth[i*4+11], mx);
	}

	//判断码制
	if( result[0]==7 && result[1]==7 )
	{
		strcpy(strCodeStyle,"条形码类型:ISSN\n\n编码: 9");
	}
	else if( result[0]==7 && result[1]==8 )
	{
		strcpy(strCodeStyle,"条形码类型:ISBN\n\n编码: 9");
	}
	else
		strcpy(strCodeStyle,"条形码类型:Unknown!\n\n编码: 9");
	

	//判断是否全部识别出来
	for(i=0; i<12; i++)
		if(result[i] == -1)
			return false;

//	CString strTemp;
//	strCodeNumber.Format("");
	for(i=0; i<12; i++)
	{
//		strTemp.Format("%d", result[i]);
//		strCodeNumber += strTemp;
		strCodeNumber[i]=(char)(result[i]+0x30);
	}
	strCodeNumber[i]='\0';

	int t1=0,t2=0;

	for(i=0;i<12;i+=2)
	{
		t1+=result[i];
	}

	for(i=1;i<11;i+=2)
	{
		t2+=result[i];
	}

	if((10-(t1*3+(t2+9))%10)!=result[11])
	{MessageBox("校验出错!", "识别结果", MB_ICONERROR | MB_OK);
	 SystemCode='x';
	}

	strcat(strCodeStyle,strCodeNumber);
	strcat(strCodeStyle,"   ");
	return true;
}

int CBarRecogView::JudgNum(int w1, int w2, int w3, int w4, double mx)
{
	double a1, a2, a3;
	int ia1, ia2, ia3;
	a1 = (double)(w1+w2)/mx;
	a2 = (double)(w2+w3)/mx;
	a3 = (double)(w3+w4)/mx;
	ia1 = (int)(a1+0.5);
	ia2 = (int)(a2+0.5);
	ia3 = (int)(a3+0.5);
		
	//判断该码值
	if( (ia1==5 && ia2==3 && ia3==2) || (ia1==2 && ia2==3 && ia3==5) )
		return 0;
	
	if( (ia1==4 && ia2==4 && ia3==3) || (ia1==3 && ia2==4 && ia3==4) )
	{
		if(ia1 == 4)
		{
			double dw2 = (double)w2/mx;
			if(dw2 < 2.4)
				return 1;
			else if(dw2 > 2.6)
				return 7;
			else return -1;
		}
	
		if(ia1 == 3)
		{
			double dw3 = (double)w3/mx;
			if(dw3 < 2.4)
				return 1;
			else if(dw3 > 2.6)
				return 7;
			else return -1;
		}
	}
	
	if( (ia1==3 && ia2==3 && ia3==4) || (ia1==4 && ia2==3 && ia3==3) )
	{
		if(ia1 == 3)
		{
			double dw4 = (double)w4/mx;
			if(dw4 < 2.4)
				return 2;
			else if(dw4 > 2.6)
				return 8;
			else return -1;
		}
	
		if(ia1 == 4)
		{
			double dw1 = (double)w1/mx;
			if(dw1 < 2.4)
				return 2;
			else if(dw1 > 2.6)
				return 8;
			else return -1;
		}
	}
	
	if( (ia1==5 && ia2==5 && ia3==2) || (ia1==2 && ia2==5 && ia3==5) )
		return 3;
	
	if( (ia1==2 && ia2==4 && ia3==5) || (ia1==5 && ia2==4 && ia3==2) )
		return 4;
	
	if( (ia1==3 && ia2==5 && ia3==4) || (ia1==4 && ia2==5 && ia3==3) )
		return 5;
	
	if( (ia1==2 && ia2==2 && ia3==5) || (ia1==5 && ia2==2 && ia3==2) )
		return 6;
	
	if( (ia1==4 && ia2==2 && ia3==3) || (ia1==3 && ia2==2 && ia3==4) )
		return 9;

	return false;
}

void CBarRecogView::OnRecog() 
{
	// TODO: Add your command handler code here
	CBarRecogDoc* pDoc = GetDocument();

	BeginWaitCursor();  //更改光标形状;

	if(PreProcess()!=FALSE)   //调用处理函数;
	{if(Recognize()==false)
	{MessageBox("无法识别!", "识别结果", MB_ICONERROR | MB_OK);
     return;
	}
    if(SystemCode=='x'){SystemCode=' ';return;}
	MessageBox(strCodeStyle, "识别结果", MB_ICONINFORMATION | MB_OK);
	}
	else
	{if(Step<3)
	MessageBox("无法识别!\n\n请执行灰度转换,二值化和滤波操作!", "识别结果", MB_ICONERROR | MB_OK);
	else
	MessageBox("无法识别!", "识别结果", MB_ICONERROR | MB_OK);
	}

	pDoc->SetModifiedFlag(TRUE);  //设置脏标记;

	pDoc->UpdateAllViews(NULL);  //更新视图;

	EndWaitCursor();   //恢复光标
	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -