基于朴素贝叶斯的扑克牌花色识别

本程序只对扑克牌的花色进行训练和识别,对扑克牌上的数字的识别在以后的学习中再进行完善。

本次只是简单的提取了扑克牌的RGB均值、HSV均值、7 个不变矩以及长宽比等14个简单的特征,其中,长宽比为了防止图像的位置等因素的影响,提取了目标区域的最小外接矩形。

部分图像如下图所示:



特征提取的部分代码如下所示:

void CPokeAlgorithmDlg::CollectCharacter(IplImage* img, CvMat* mat, int rows)
{
	if (img != nullptr)
	{
		showImage(img, IDC_PIC1);					//显示图像

		IplImage* bitImage = nullptr, *grayImage = nullptr, *hsvImage = nullptr;

		bitImage = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
		grayImage = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
		hsvImage = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3);


		cvCvtColor(img, hsvImage, CV_RGB2HSV);
		cvCvtColor(img, grayImage, CV_RGB2GRAY);

		cvSmooth(grayImage, grayImage, CV_MEDIAN);
		cvThreshold(grayImage, bitImage, 128, 255.0, CV_THRESH_BINARY);

		cvNot(bitImage, bitImage);

		IplConvKernel* element = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);
		cvSmooth(bitImage, bitImage, CV_MEDIAN);
		cvErode(bitImage, bitImage, element, 1);
		cvDilate(bitImage, bitImage, element, 1);
		cvReleaseStructuringElement(&element);
		element = NULL;


		CvMemStorage* storage = cvCreateMemStorage(0);
		CvSeq* contour = 0;
		cvFindContours(bitImage, storage, &contour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);  	//轮廓检索

		for (; contour != 0; contour = contour->h_next)
		{
			double area = fabs(cvContourArea(contour, CV_WHOLE_SEQ));

			if (area > 2000)   //此处阈值需重新调节
			{
				cvDrawContours(bitImage, contour, cvScalarAll(255), cvScalarAll(255), -1, CV_FILLED, 8);
				CvRect rect = cvBoundingRect(contour, 0);

				CvBox2D minRect = cvMinAreaRect2(contour, storage);

				CvPoint2D32f rectPts[4] = { 0 };
				cvBoxPoints(minRect, rectPts);
				int nPts = 4;	// 4 个顶点

				CvPoint minRectPts[4] = { 0 };
				for (int i = 0; i < 4; ++i)
				{
					minRectPts[i] = cvPointFrom32f(rectPts[i]);    //将 cvPoint2D32f 转化为 CvPoint
				}
				CvPoint *pt = minRectPts;

				//在图像中绘制矩形框
				cvPolyLine(bitImage, &pt, &nPts, 1, 1, cvScalarAll(255), 1);

				int l1 = sqrtf((pt[0].x - pt[1].x)*(pt[0].x - pt[1].x) + (pt[0].y - pt[1].y)*(pt[0].y - pt[1].y));
				int l2 = sqrtf((pt[2].x - pt[1].x)*(pt[2].x - pt[1].x) + (pt[2].y - pt[1].y)*(pt[2].y - pt[1].y));

				int length = l1 > l2 ? l1 : l2;   //取较长边为图形的长
				int width = l1 > l2 ? l2 : l1;	  //取较短边为图形的宽

				double r = (width * 1.0) / length;   //长宽比

				cvSetReal2D(mat, rows, 0, r);
			
				double RMean = 0, GMean = 0, BMean = 0;
				double HMean = 0, SMean = 0, VMean = 0;
				int nCount = 0;

				for (int imgRow = rect.y; imgRow < rect.y + rect.height; ++imgRow)
				{
					for (int imgCol = rect.x; imgCol < rect.x + rect.width; ++imgCol)
					{
						CvScalar s = cvGet2D(bitImage, imgRow, imgCol);

						if (s.val[0] == 255)
						{
							s = cvGet2D(img, imgRow, imgCol);
							RMean += s.val[2];
							GMean += s.val[1];
							BMean += s.val[0];

							s = cvGet2D(hsvImage, imgRow, imgCol);
							HMean += s.val[0];
							SMean += s.val[1];
							VMean += s.val[2];

							++nCount;
						}
					}
				}// end RGB,HSV for

				RMean /= nCount;
				GMean /= nCount;
				BMean /= nCount;

				HMean /= nCount;
				SMean /= nCount;
				VMean /= nCount;

				
				cvSetReal2D(mat, rows, 1, RMean);
				cvSetReal2D(mat, rows, 2, GMean);
				cvSetReal2D(mat, rows, 3, BMean);
				cvSetReal2D(mat, rows, 4, HMean);
				cvSetReal2D(mat, rows, 5, SMean);
				cvSetReal2D(mat, rows, 6, VMean);

				//7个不变矩

				CvMoments moments;
				cvMoments(contour, &moments, 1);
				CvHuMoments  huMoments;
				cvGetHuMoments(&moments, &huMoments);

				double hu1 = huMoments.hu1;
				double hu2 = huMoments.hu2;
				double hu3 = huMoments.hu3;
				double hu4 = huMoments.hu4;
				double hu5 = huMoments.hu5;
				double hu6 = huMoments.hu6;
				double hu7 = huMoments.hu7;

				cvSetReal2D(mat, rows, 7, hu1);
				cvSetReal2D(mat, rows, 8, hu2);
				cvSetReal2D(mat, rows, 9, hu3);
				cvSetReal2D(mat, rows, 10, hu4);
				cvSetReal2D(mat, rows, 11, hu5);
				cvSetReal2D(mat, rows, 12, hu6);
				cvSetReal2D(mat, rows, 13, hu7);
			}// end if
		}

		showImage(hsvImage, IDC_PIC3);
		showImage(bitImage, IDC_PIC2);


		//释放内存
		cvReleaseMemStorage(&storage);
		storage = nullptr;
		cvReleaseImage(&bitImage);
		bitImage = nullptr;
		cvReleaseImage(&grayImage);
		grayImage = nullptr;
		cvReleaseImage(&hsvImage);
		hsvImage = nullptr;
	}

	//释放内存
	cvReleaseImage(&img);
	img = nullptr;
}

Bayes训练代码:

Book* book = xlCreateXMLBookW();

	CvMat* dataMat = NULL;

	if (book->load(L"Data.xlsx"))
	{
		Sheet *sheet = book->getSheet(0);

		int myrow = sheet->lastRow();
		int mycol = sheet->lastCol();

		if (sheet)
		{
			CvMat* importMat = cvCreateMat(myrow, mycol, CV_32FC1);  //存储导入数据

			for (auto i = 0; i < myrow; ++i)
			{
				for (auto j = 0; j < mycol; j++)
				{
					double temp = sheet->readNum(i, j);
					cvSetReal2D(importMat, i, j, temp);
				}
			}// end for

			dataMat = cvCloneMat(importMat);
		}// end if
	}

	book->release();

	MessageBox(L"数据导入完成");

	CvMat* lableMat = cvCreateMat(dataMat->rows, 1, CV_32FC1);		//构建样本的分类标签
	cvZero(lableMat);

	for (int i = 0; i < 4; ++i)			//共分了 20 个不同的种类
	{
		for (int j = 0; j < 10; ++j)		//每个品种共50个籽粒
		{
			cvSetReal2D(lableMat, i * 10 + j, 0, i + 1);
		}
	}

	CvNormalBayesClassifier nbc;
	nbc.train(dataMat, lableMat);
	nbc.save("bayes.txt");

	MessageBox(L"数据训练完成");

	CvMat* nbcResult = cvCreateMat(dataMat->rows, 1, CV_32FC1);
	CvMat* nbcRow = NULL;

	for (int i = 0; i < dataMat->rows; ++i)
	{
		nbcRow = cvCreateMat(1, dataMat->cols, CV_32FC1);

		for (int j = 0; j < dataMat->cols; ++j)
		{
			float temp = cvGetReal2D(dataMat, i, j);
			cvSetReal2D(nbcRow, 0, j, temp);
		}

		unsigned int ret = 0;
		ret = nbc.predict(nbcRow);
		cvSetReal2D(nbcResult, i, 0, ret);
		cvReleaseMat(&nbcRow);
		nbcRow = NULL;
	}

	int nCount = 0;

	for (int i = 0; i < 4; ++i)
	{
		for (int j = 0; j < 10; ++j)
		{
			int ret = cvGetReal2D(nbcResult, i * 10 + j, 0);
			if (ret == (i + 1))
			{
				++nCount;
			}
		}
	}

	float recognize = 100 * nCount / 10 / 4;

	CString str;
	str.Format(L"朴素贝叶斯 识别率为: %f", recognize);
	str = str + L"%";
	MessageBox(str);
	

识别代码如下所示:

CvNormalBayesClassifier nbc;
	nbc.load("bayes.txt");

	CFileDialog dlg(TRUE, NULL, NULL, 0, L"图片文件(*.jpg)|*.jpg||");
	if (dlg.DoModal() == IDOK)
	{
		USES_CONVERSION;
		const char* loadPath = W2A(dlg.GetPathName());
		IplImage* testImage = cvLoadImage(loadPath);

		CvMat* mat = cvCreateMat(1, 14, CV_32FC1);
		CollectCharacter(testImage, mat, 0);

		int  ret = nbc.predict(mat);
		CString str;
		switch (ret)
		{
		case 1:
			str = L"黑桃";
			break;
		case 2:
			str = "红桃";
			break;
		case 3:
			str = "梅花";
			break;
		case 4:
			str = "方块";
			break;
		}
		AfxMessageBox(str);
		cvReleaseMat(&mat);
		mat = NULL;
	}//end if	


  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值