1. 程式人生 > >手寫體識別(基於Opencv)

手寫體識別(基於Opencv)

#include "cv.h"
#include "highgui.h"
#include "iostream"
#include "string"
#include "cmath"
#include <sstream>
#define PI 3.1415926
using namespace std;
using namespace cv;
FILE* fp;
struct Lines{
	double k;
	double b;
	bool per;
};
double rotationAngle = 0.0;
bool LineCmp(const Vec2f& a, const Vec2f& b) {
	double threshold = 0.1;
	if (abs(a[1] - b[1]) < threshold) {
		return a[0] < b[0];
	}
	return a[1] < b[1];
}

bool PointCmp(const Point2f& a, const Point2f& b) {
	return a.x + a.y < b.x + b.y;
}
vector<Lines> Findlines(Mat img) {
	vector<Vec2f> lines;
	vector<Lines> mls;
	//rotationAngle = 0.0;
	HoughLines(img, lines, 1, CV_PI / 100, 80, 0, 0);
	sort(lines.begin(), lines.end(), LineCmp);
	int last = lines.size() - 1;
	const double minTheta = 0.1;
	const double maxTheta = 3.1;
	const double rhoThreshold = 50;<a target=_blank href="https://github.com/yinmingwang/identifyhandwriting">github連結</a>

	while (lines[0][1] <= minTheta && lines[last][1] >= maxTheta) {
		vector<Vec2f>::iterator it = lines.begin() + 1;
		for (size_t i = 1; i < last; ++i) {
			if (lines[i][1] <= minTheta && abs(lines[0][0] - lines[i][0]) < rhoThreshold) {
				++it;
			}
		}
		lines.insert(it, lines[last]);
		it = lines.end() - 1;
		lines.erase(it);
	}

	rotationAngle = lines[0][1] * 180 / CV_PI;
	const double rotationThreshold = 0.1;
	if (lines[0][1] > rotationThreshold) {
		rotationAngle -= 90;
	}
	for (size_t i = 0; i < lines.size(); i++) {
		float rho = lines[i][0], theta = lines[i][1];
		const float deltaRho = 200;
		const float deltaTheta = 0.25;
		if (i > 0 && abs(abs(rho) - abs(lines[i - 1][0])) < deltaRho &&
			(abs(CV_PI - (theta + lines[i - 1][1])) < deltaTheta || abs(theta - lines[i - 1][1]) < deltaTheta)) {
			vector<Vec2f>::iterator it = lines.begin() + i;
			lines.erase(it);
			--i;
			continue;
		}
		if (i > 0 && i < lines.size() - 1 &&
			abs(theta - lines[i - 1][1]) > deltaTheta && abs(theta - lines[i + 1][1]) > deltaTheta &&
			abs(CV_PI - (theta + lines[i - 1][1])) > deltaTheta) {
			vector<Vec2f>::iterator it = lines.begin() + i;
			lines.erase(it);
			--i;
			continue;
		}
		Point pt1, pt2;
		double a = cos(theta), b = sin(theta);
		double x0 = a * rho, y0 = b * rho;
		pt1.x = cvRound(x0 + 1000 * (-b));
		pt1.y = cvRound(y0 + 1000 * (a));
		pt2.x = cvRound(x0 - 1000 * (-b));
		pt2.y = cvRound(y0 - 1000 * (a));
		line(img, pt1, pt2, Scalar(255, 255, 255), 1, CV_AA);
		struct Lines ml;
		if (b == 0) {
			ml.per = 1;
			ml.b = rho;
		}
		else {
			ml.per = 0;
			double m = -a / b, c = rho / b;
			ml.k = m;
			ml.b = c;
		}
		mls.push_back(ml);
	}
	return mls;
}

Mat get_edge(Mat img) {
	Mat dstimg, blurImg;
	blur(img, blurImg, Size(3, 3));
	Canny(blurImg, dstimg, 130, 550, 3);
	return dstimg;
}


vector<Point2f> findintersection(vector<Lines> mls, Mat image) {
	vector<Point2f> points;
	for (int i = 0; i < 2; ++i) {
		for (int j = 2; j < 4; ++j) {
			double a = mls[i].k, b = mls[j].k;
			double c = mls[i].b, d = mls[j].b;
			double x, y;
			if (mls[i].per == 1) {
				x = c;
				y = b * c + d;
			}
			else {
				x = (d - c) / (a - b);
				y = (a * d - b * c) / (a - b);
			}
			//printf("Point: (%lf, %lf)\n", x, y);
			Point2f pt1;
			pt1.x = x;
			pt1.y = y;
			points.push_back(pt1);
			circle(image, pt1, 3, Scalar(255, 0, 0), 1);
		}
	}
	return points;
}
Mat CorrectImg(vector<Point2f> points, Mat img, Mat tempimg) {
	Point centerpoint;
	centerpoint.x = (points[0].x + points[1].x + points[2].x + points[3].x) / 4;
	centerpoint.y = (points[0].y + points[1].y + points[2].y + points[3].y) / 4;
	//circle(img, centerpoint, 3, Scalar(255, 255, 255), 1);
	Mat rotatedImg;
	Mat rotationMatrix;
	rotationMatrix = getRotationMatrix2D(centerpoint, rotationAngle, 1);
	warpAffine(tempimg, rotatedImg, rotationMatrix, rotatedImg.size());
	transform(points, points, rotationMatrix);
	if (tempimg.rows < tempimg.cols) {
		const float scale = 0.75;
		rotationMatrix = getRotationMatrix2D(centerpoint, 90, scale);
		warpAffine(rotatedImg, rotatedImg, rotationMatrix, rotatedImg.size());
		transform(points, points, rotationMatrix);
	}
	sort(points.begin(), points.end(), PointCmp);
	const int lx = 100;
	const int ly = 110;
	const int rx = 500;
	const int ry = 700;
	const int width = rx - lx;
	const int height = ry - ly;
	Point2f TopLeft;
	Point2f TopRight;
	Point2f BottomLeft;
	Point2f BottomRight;
	vector<Point2f> standardPoints;
	TopLeft.x = lx;
	TopLeft.y = ly;
	TopRight.x = rx;
	TopRight.y = ly;
	BottomLeft.x = lx;
	BottomLeft.y = ry;
	BottomRight.x = rx;
	BottomRight.y = ry;
	standardPoints.push_back(TopLeft);
	standardPoints.push_back(TopRight);
	standardPoints.push_back(BottomLeft);
	standardPoints.push_back(BottomRight);
	Mat perspectiveMatrix;
	perspectiveMatrix = getPerspectiveTransform(points, standardPoints);
	Mat perspectiveImg(800, 800, rotatedImg.type());
	warpPerspective(rotatedImg, perspectiveImg, perspectiveMatrix, perspectiveImg.size());
	Rect myROI(lx, ly, width, height);
	Mat CorrectImage = perspectiveImg(myROI);
	Mat ReImg(CorrectImage, Rect(10, 10, CorrectImage.cols - 20, CorrectImage.rows-20));
	//imshow("CorrectImage", CorrectImage);
	return ReImg;
}

Mat segmentation(Mat srcimg) {
	Mat grayimg;
	Mat seimg;
	cvtColor(srcimg, grayimg, CV_BGR2GRAY);
	adaptiveThreshold(grayimg, seimg, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 33, 5);
	//imshow("seimg", seimg);
	return seimg;
}
Mat rotation(Mat srcImg, double angle) {
	Mat tempImg;
	CV_Assert(!srcImg.empty());
	float radian = (float)(angle / 180.0 * CV_PI);
	//Ìî³äͼÏñʹÆä·ûºÏÐýתҪÇó
	int uniSize = (int)(max(srcImg.cols, srcImg.rows)* 1.414);
	int dx = (int)(uniSize - srcImg.cols) / 2;
	int dy = (int)(uniSize - srcImg.rows) / 2;
	copyMakeBorder(srcImg, tempImg, dy, dy, dx, dx, BORDER_CONSTANT);
	//ÐýתÖÐÐÄ
	Point2f center((float)(tempImg.cols / 2), (float)(tempImg.rows / 2));
	Mat affine_matrix = getRotationMatrix2D(center, angle, 1.0);
	//Ðýת
	warpAffine(tempImg, tempImg, affine_matrix, tempImg.size());
	//ÐýתºóµÄͼÏñ´óС
	float sinVal = fabs(sin(radian));
	float cosVal = fabs(cos(radian));
	Size targetSize((int)(srcImg.cols * cosVal + srcImg.rows * sinVal),
		(int)(srcImg.cols * sinVal + srcImg.rows * cosVal));

	//¼ôµôËÄÖܱ߿ò
	int x = (tempImg.cols - targetSize.width) / 2;
	int y = (tempImg.rows - targetSize.height) / 2;
	Rect rect(x, y, targetSize.width, targetSize.height);
	tempImg = Mat(tempImg, rect);
	//imshow("Show", tempImg);
	return tempImg;
}
Mat Erosion(Mat srcimg,int size) {
	Mat erodeimg;
	Mat element = getStructuringElement(MORPH_RECT, Size(size, size));
	/// ¸¯Ê´²Ù×÷
	erode(srcimg, erodeimg, element);
	//imshow("Erosion Demo", erodeimg);
	return erodeimg;
}
Mat Dilation(Mat srcimg,int size)
{
	Mat dilatimg;
	Mat element = getStructuringElement(MORPH_RECT, Size(size, size));
	/// ÅòÕͲÙ×÷
	dilate(srcimg, dilatimg, element);
	//imshow("Dilation Demo", dilatimg);
	return dilatimg;
}
Mat Slicimg(Mat srcimg,int cmin,int cmax) {
	Mat threshold_output = srcimg.clone();
	//fp = fopen("img2.csv", "w");
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
	vector<vector<Point>>::const_iterator itc = contours.begin();
	while (itc != contours.end()) {

		if (itc->size() < cmin || itc->size() > cmax)
			itc = contours.erase(itc);
		else
			++itc;
	}


	vector<vector<Point> > contours_poly(contours.size());
	vector<Rect> boundRect(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
		boundRect[i] = boundingRect(Mat(contours_poly[i]));
	}


	/// »­¶à±ßÐÎÂÖÀª + °üΧµÄ¾ØÐοò
	//Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);
	Mat drawing = srcimg.clone();
	Mat src = srcimg.clone();
	vector<Mat> roi(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		stringstream stream;
		string str;
		stream << i;
		stream >> str;
		Scalar color = Scalar(255, 255, 255);
		drawContours(drawing, contours_poly, i, color, 1, 8, vector<Vec4i>(), 0, Point());
		rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), color, 1, 8, 0);
		Mat temp(src, Rect(boundRect[i]));
		Mat img;
		resize(temp, img, Size(28,28), 0, 0, CV_INTER_LINEAR);
		/*
		for (int k = 0; k < img.rows; k++) {
			for (int f = 0; f < img.cols; f++) {
				fprintf(fp, "%d ", img.at<uchar>(k, f));
			}
		}
		fprintf(fp, "\n");
		imwrite("./result1/"+str+".jpg", img);*/
	}
	//fclose(fp);
	return drawing;
}
int main()
{
	Mat srcImg = imread("3.jpg");
	Mat blurImg, grayImg, dstImg, tempImg, cornerImg;
	int width = srcImg.cols;
	int height = srcImg.rows;
	resize(srcImg, tempImg, Size(width, height), 0, 0, CV_INTER_LINEAR);
	imshow("SrcImg", tempImg);
	dstImg = get_edge(tempImg);
	Mat image = dstImg.clone();
	vector<Lines> lines = Findlines(image);
	vector<Point2f> points = findintersection(lines, image);
	Mat corrimg = CorrectImg(points, image, tempImg);
	Mat seImg = segmentation(corrimg);
	Mat roimg = rotation(seImg, -90);
	Mat dilaimg = Erosion(roimg, 1);
	//imshow("dilaimg", dilaimg);
	Mat silimg = Slicimg(dilaimg, 27, 100);
	imshow("roimg", silimg);
	waitKey(0);
	return 0;
}