1. 程式人生 > >基於OpenCV的機器視覺應用&影象分割

基於OpenCV的機器視覺應用&影象分割

對“ 待分割識別影象”資料夾中的 ” 所有 整版麻將圖片進行 分割 ,並輸出 識別 結果 :
原始碼:

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
static int issame(Mat out, Mat std);
int minvalue = INT_MAX;
void HorizonProjection(const Mat& src, Mat& dst)	//水平投影,const表示常量
{
	CV_Assert(src.depth() != sizeof(uchar));
	dst.create(src.rows, 1, CV_32F);
	int i, j;
	const uchar* p;
	float* p_dst;
	for (i = 0; i < src.rows; i++) {
		p = src.ptr<uchar>(i);
		p_dst = dst.ptr<float>(i);
		p_dst[0] = 0;
		for (j = 0; j < src.cols; j++) {
			p_dst[0] += p[j];
		}
		p_dst[0] = p_dst[0] / src.cols;
	}
}
void VerticalProjection(const Mat& src, Mat& dst)		//垂直投影
{
	CV_Assert(src.depth() != sizeof(uchar));
	dst.create(1, src.cols, CV_32F);
	int i, j;
	const uchar* p;
	float* p_dst = dst.ptr<float>(0);
	for (j = 0; j < src.cols; j++) {
		p_dst[j] = 0;
		for (i = 0; i < src.rows; i++) {
			p = src.ptr<uchar>(i);
			p_dst[j] += p[j];
		}
		p_dst[j] = p_dst[j] / src.rows;
	}
}
int main()
{
	Mat dstImage,gImage,sgImage,ogImage, srcImage = imread("a.jpg");		//有路徑要輸入
	Mat hImage, vImage;
	int x1, x2, y1, y2;
	int x_proj_out, y_proj_out;
	int width_single, heigth_single;
	float *dst;
	float *t;
	int a[100],b[100],d[100];
	int n=0,m=0,g=0;
	int w,h;
	int maxw=0,maxh=0;
	int numx=0, numy=0;
	//步驟一
	cvtColor(srcImage, gImage, CV_BGR2GRAY);		//顏色轉換函式
	threshold(gImage, dstImage, 0, 255, THRESH_OTSU);
	//步驟二
	HorizonProjection(dstImage, hImage);
	VerticalProjection(dstImage, vImage);
	for (int i = 0;;i++) {
		dst = hImage.ptr<float>(i);
		float t1 = dst[0], t2 = dst[1], t3 = dst[2], t4 = dst[3], t5 = dst[4];
		if (t1!= 0 && t2 != 0 && t3!= 0 && t4 != 0 && t5 != 0)
		{
			y1 = i - 2;
			break;
		}
	}
	for (int i = hImage.rows;;i--) {
		dst = hImage.ptr<float>(i-5);
		float t1 = dst[0], t2 = dst[1], t3 = dst[2], t4 = dst[3], t5 = dst[4];
		if (t1 != 0 && t2 != 0 && t3 != 0 && t4 != 0 && t5 != 0)
		{
			y2 = i + 2;
			break;
		}
	}
	for (int i = 0;;i++) {
		dst = vImage.ptr<float>(0);
		float t1 = dst[i], t2 = dst[i+1], t3 = dst[i+2], t4 = dst[i+3], t5 = dst[i+4];
		if (t1 != 0 && t2 != 0 && t3 != 0 && t4 != 0 && t5 != 0)
		{
			x1 = i - 2;
			break;
		}
	}
	for (int i = vImage.cols;;i--) {
		dst = vImage.ptr<float>(0);
		float t1 = dst[i-4], t2 = dst[i-3], t3 = dst[i-2], t4 = dst[i-1], t5 = dst[i];
		if (t1 != 0 && t2 != 0 && t3 != 0 && t4 != 0 && t5 != 0)
		{
			x2 = i + 2;
			break;
		}
	}
	sgImage = gImage(Range(y1, y2), Range(x1, x2));
	imshow("擷取的灰度圖", sgImage);
//	waitKey(0);
	//步驟三
	threshold(sgImage, dstImage, 0, 255, THRESH_OTSU);
	imshow("二值影象", dstImage);
	Mat element = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
	morphologyEx(dstImage, dstImage, CV_MOP_OPEN, element);
	imshow("形態學濾波", dstImage);
	waitKey(0);
	HorizonProjection(dstImage, hImage);
	VerticalProjection(dstImage, vImage);
	dst = hImage.ptr<float>(0);dst[0] = 255;
	dst = hImage.ptr<float>(1);dst[0] = 255;
	dst = hImage.ptr<float>(hImage.rows-1);dst[0] = 255;
	dst = hImage.ptr<float>(hImage.rows-2);dst[0] = 255;
	dst = vImage.ptr<float>(0);dst[0] = 255, dst[1] = 255, dst[vImage.cols - 1] = 255, dst[vImage.cols - 2] = 255;
	for (int i = 1;i < vImage.cols;i++) {
		dst = vImage.ptr<float>(0);
		if (dst[i] > 255 * 0.9)
		{
			dst[i] = 255;
			if (dst[i-1] == 0) {
				a[n] = i;
				n++;
			}
		}
		else {
			dst[i] = 0;
			if (dst[i-1] == 255) {
				a[n] = i;
				n++;
			}
		}
	}
//	imshow("111111111", vImage);
	for (int i = 0;i <= n-1;i += 1) {
		if ((a[i + 1] - a[i]) < 5) {
			for (int j = a[i];j <= a[i + 1];j++) {
				dst = vImage.ptr<float>(0);
				dst[j] = 255;
			}
		}
	}
	for (int i = 1;i < vImage.cols;i++) {
		dst = vImage.ptr<float>(0);
		if (dst[i]!=dst[i - 1] ) {
			b[m] = i;
			m++;
		}
	}
//	imshow("222222222", vImage);
	for (int i = 0;i <= m;i += 2) {
		if (maxw < b[i + 1] - b[i]) maxw = b[i + 1] - b[i];//maxw單個麻將最大寬度
	}
	for (int i = 0;i <= m;i += 2) {
		w = b[i + 1] - b[i];
		if (w > (maxw / 2)) {
			numx++;
			d[g] = b[i];
			d[g+1] = b[i + 1];
			g += 2;
		}
	}
	x_proj_out = (d[0] + d[g - 1]) / 2;
	n = 0, m = 0, g = 0;
	for (int i = 1;i < hImage.rows;i++) {
		t = hImage.ptr<float>(i - 1);
		dst = hImage.ptr<float>(i);
		if (dst[0] > 255 * 0.9) {
			dst[0] = 255;
			if (t[0] == 0) {
				a[n] = i;
				n++;
			}
		}
		else {
			dst[0] = 0;
			if (t[0] == 255) {
				a[n] = i;
				n++;
			}
		}
	}
//	imshow("111111", hImage);

	for (int i = 0;i <= n-1;i += 2) {
		if ((a[i + 1] - a[i]) < 10) {
			for (int j = a[i];j <= a[i + 1];j++) {
				dst = hImage.ptr<float>(j);
				dst[0] = 255;
			}
		}
	}

//	imshow("22222", hImage);
	for (int i = 1;i < hImage.rows;i++) {
		t = hImage.ptr<float>(i - 1);
		dst = hImage.ptr<float>(i);
		if (t[0] != dst[0]) {
			b[m] = i;
			m++;
		}
	}
	for (int i = 0;i <= m-2;i += 2) {
		h = b[i + 1] - b[i];
		if (h < 0.95*maxw) {
			h = b[i + 3] - b[i];
			if (h < 0.95*maxw) {
				h = b[i + 5] - b[i];
				d[g] = b[i];
				d[g + 1] = b[i + 5];
				g += 2;
				i += 4;
				numy++;
			}
			else {
				d[g] = b[i];
				d[g + 1] = b[i + 3];
				g += 2;
				i += 2;
				numy++;
			}
		}
		else {
			d[g] = b[i];
			d[g + 1] = b[i + 1];
			g += 2;
			numy++;
		}
	}
	for (int i = 0;i <= g;i += 2) {
		if (maxh < d[i + 1] - d[i]) maxh = d[i + 1] - d[i];
	}
	y_proj_out = (d[0] + d[g - 1]) / 2;
	heigth_single =(sgImage.rows-10) / numy;
	width_single =(sgImage.cols-10) / numx;
	int num = numx*numy;
	Mat *singleImage = new Mat[num];
	int xb, yb;
	int xb1,yb1,xe, ye;
	int count=0;
	xb = x_proj_out - (width_single*((float)numx / 2));
	printf("%d %d", xb,x_proj_out);
	yb = y_proj_out - (heigth_single*((float)numy / 2));
	for (int i=0;i < numy;i++) {
		for (int j = 0;j < numx;j++) {
			xb1 = xb + width_single*(j);
			xe = xb + width_single*(j + 1);
			yb1 = yb + heigth_single*(i);
			ye = yb + heigth_single*(i + 1);
			singleImage[count] = sgImage(Range(yb1,ye), Range(xb1,xe));
			count++;
		}
	}
	char filename[30];
	char filename2[30];
	char filename3[30];
	char filename4[30];
	char filename5[30];
	char filename6[30];
	char filename7[30];
	Mat *dsImage=new Mat[num], *outImage=new Mat[num];
	Mat stdImage[34], grayImage[34], threImage[34], tempImage[34];
	//步驟4
	//分割出來的單個麻將灰度圖片
	for (int i = 0; i <num; i++)
	{
		sprintf_s(filename, "%d.jpg", i + 1);
		imshow(filename, singleImage[i]);
	}

	//縮放尺寸
	for (int i = 0; i <num; i++)
	{
		resize(singleImage[i], dsImage[i], Size(32, 48), INTER_LINEAR);
		sprintf_s(filename2, "change(%d).jpg", i + 1);
		//imwrite(filename2, dstImage[i]);
		//imshow(filename2,dstImage[i]);
	}

	//閾值化
	for (int i = 0; i <num; i++)
	{
		threshold(dsImage[i], outImage[i], 0, 255, THRESH_OTSU);
		sprintf_s(filename3, "threshold(%d).jpg", i + 1);
		//imshow(filename3, outImage[i]);
		for (int m = 0; m < outImage[i].cols; m++)
		{
			outImage[i].ptr<uchar>(0)[m] = 255;
		}
		for (int m = 0; m < outImage[i].cols; m++)
		{
			outImage[i].ptr<uchar>(47)[m] = 255;
		}
		for (int m = 0; m < outImage[i].rows; m++)
		{
			outImage[i].ptr<uchar>(m)[0] = 255;
		}
		for (int m = 0; m < outImage[i].rows; m++)
		{
			outImage[i].ptr<uchar>(m)[31] = 255;
		}
		sprintf_s(filename4, "thresholdchange(%d).jpg", i + 1);
		//imshow(filename4, outImage[i]);
	}
	//步驟5
	//閾值化模板麻將
	for (int i = 0; i <34; i++)
	{
		sprintf_s(filename5, "%d.jpg", i + 1);
		stdImage[i] = imread(filename5);
		//imshow(filename5,stdImage[i]);
	}

	for (int i = 0; i <34; i++)
	{
		cvtColor(stdImage[i], grayImage[i], CV_RGB2GRAY);
		threshold(grayImage[i], threImage[i], 0, 255, THRESH_OTSU);
		for (int m = 0; m < threImage[i].cols; m++)
		{
			threImage[i].ptr<uchar>(0)[m] = 255;
		}
		for (int m = 0; m < threImage[i].cols; m++)
		{
			threImage[i].ptr<uchar>(47)[m] = 255;
		}
		for (int m = 0; m < threImage[i].rows; m++)
		{
			threImage[i].ptr<uchar>(m)[0] = 255;
		}
		for (int m = 0; m < threImage[i].rows; m++)
		{
			threImage[i].ptr<uchar>(m)[31] = 255;
		}
		sprintf_s(filename6, "thresholdstandard(%d).jpg", i + 1);
		//imshow(filename6, threImage[i]);
	}

	//擴大成模板麻將
	for (int i = 0; i <34; i++)
	{
		copyMakeBorder(threImage[i], tempImage[i], 9, 9, 6, 6, BORDER_REPLICATE);
		sprintf_s(filename7, "temp(%d).jpg", i + 1);
//		imshow(filename7, tempImage[i]);
	}

	//步驟6  待識別outImage[i]  模板tempImage[i]
	int nvalue;
	int minv = INT_MAX;
	int n1;
	for (int j = 0; j < num; j++)
	{
		for (int i = 0; i < 34; i++)
		{
			nvalue = issame(outImage[j], tempImage[i]);
			if (nvalue < minv)
			{
				minv = nvalue;
				n1 = i;
			}

		}
		printf("(%d).jpg = %d.jpg \n", j + 1, n1 + 1);
		minv = INT_MAX;
	}
	

	waitKey(0);
	return 0;
}

static int issame(Mat out, Mat std)
{
	Mat temp;
	int value = INT_MAX;
	int res = 0;
	int x, y;
	for (int x1 = 0; x1 < 13; x1++)
	{
		for (int y1 = 0; y1 < 19; y1++)
		{
			temp = std(Range(y1, y1 + 47), Range(x1, x1 + 31));
			for (int j = 0; j < 47; j++)
			{
				for (int i = 0; i < 31; i++)
				{
					res = res + abs(out.at<uchar>(j, i) - temp.at<uchar>(j, i));
				}
			}
			if (res < minvalue)
			{
				minvalue = res;
			}
			if (minvalue < value)
			{
				value = minvalue;
			}
			res = 0;
			minvalue = INT_MAX;
		}
	}
	return value;
}

處理的結果:
在這裡插入圖片描述
關閉擷取的灰度圖、二值影象、形態學濾波視窗後:
在這裡插入圖片描述
程式執行後出現的結果:
在這裡插入圖片描述

即為分割識別後的結果。