#include <opencv2/opencv.hpp>
#include <iostream>
#include "math.h"
using namespace cv;
using namespace std;
#if 0
const bool X_Axis = true;
const bool Y_Axis = false;
void FindAnchorPoint(const Mat& src, const Mat& matchMask, vector<Point2f>& anchorPoint);
void projectionAlgorithm(Mat src, vector<int>& UpJumpWave, vector<int>& DownJumpWave, bool Axis, int maxInterval);
void checkKeypoint( Mat& _src, vector<Point2f>& allPoint, vector<Point2f>& testkeyPoint);
int main1(int argc,char** argv)
{
//变量
//读取图片
Mat standImage = imread("D:\\workspace\\OpenCVApplication1\\OpenCVApplication1\\Debug\\1.jpg");
Mat perImage = imread("D:\\workspace\\OpenCVApplication1\\OpenCVApplication1\\Debug\\2.jpg");
//Mat perImage = imread("perspective.jpg");
//Mat matchMask = imread("Circle.jpg");
//-----------生成模板图片R = 11
Mat matchMask;
matchMask.create(Size(24, 24), CV_8UC3);
matchMask.setTo(255);
circle(matchMask, Point(11, 11), 11, Scalar(0), -1);
resize(perImage, perImage, Size(600, 600));
vector<Point2f> stdAncherPoint(4);
vector<Point2f> perAncherPoint(4);
FindAnchorPoint(standImage, matchMask, stdAncherPoint);
FindAnchorPoint(perImage, matchMask, perAncherPoint);
Mat change = getPerspectiveTransform(perAncherPoint, stdAncherPoint);
Mat resultPerImage;
warpPerspective(perImage, resultPerImage, change, resultPerImage.size());
FindAnchorPoint(resultPerImage, matchMask, perAncherPoint);
Mat grayImage = resultPerImage;//.clone();
Mat show = resultPerImage.clone();
cvtColor(grayImage, grayImage, CV_BGR2GRAY);
threshold(grayImage, grayImage,90,255, THRESH_BINARY_INV);
vector<Mat> vectorGrayImage(4);
vectorGrayImage[0] = grayImage(Rect(perAncherPoint[0].x+4, 0, 15, standImage.rows));//LEFT
vectorGrayImage[1] = grayImage(Rect(perAncherPoint[1].x+4 , 0, 15, standImage.rows));//RIGHT
vectorGrayImage[2] = grayImage(Rect(0,perAncherPoint[0].y+4, standImage.cols, 15));//TOP
vectorGrayImage[3] = grayImage(Rect(0,perAncherPoint[2].y+4, standImage.cols, 15));//BOTTOM
vector<vector<int>> upJumpWave(4);
vector<vector<int>> downJumpWave(4);
for (size_t i = 0; i < 4; i++)
{
if (i<2) projectionAlgorithm(vectorGrayImage[i], upJumpWave[i], downJumpWave[i], Y_Axis, 2);
else projectionAlgorithm(vectorGrayImage[i], upJumpWave[i], downJumpWave[i], X_Axis, 2);
}
//-----------------------绘制检测的跳变线-------------------------//
for (size_t i = 0; i < upJumpWave[0].size(); i++)
{
line(grayImage, Point(perAncherPoint[0].x + 11, upJumpWave[0][i]), Point(perAncherPoint[0].x + 22, upJumpWave[0][i]), Scalar(255, 255, 255));
}
for (size_t i = 0; i < upJumpWave[3].size(); i++)
{
line(grayImage, Point(upJumpWave[3][i], perAncherPoint[3].y), Point(upJumpWave[3][i], perAncherPoint[3].y + 11), Scalar(255, 255, 255));
}
for (size_t i = 0; i < upJumpWave[1].size(); i++)
{
line(grayImage, Point(perAncherPoint[1].x, upJumpWave[1][i]), Point(perAncherPoint[1].x + 11, upJumpWave[1][i]), Scalar(255, 255, 255));
}
for (size_t i = 0; i < upJumpWave[2].size(); i++)
{
line(grayImage, Point(upJumpWave[2][i], perAncherPoint[0].y + 11), Point(upJumpWave[2][i], perAncherPoint[0].y + 22), Scalar(255, 255, 255));
}
//-------------把所有的点存储在容器里,以供下面的函数调用--------------//
vector<Point2f> allPoint;
for (size_t i = 1; i < upJumpWave[2].size(); i++)//存储上半部分图卡点(准考证号区+旁边那个看不清的区域)
{
for (size_t j = 0; j < 10; j++)
{
allPoint.push_back(Point(upJumpWave[2][i], upJumpWave[1][j]));
}
}
for (size_t i = 0; i < upJumpWave[3].size(); i++)//存储下半部分图卡点(答题区)
{
for (size_t j = 10; j < upJumpWave[1].size(); j++)
{
allPoint.push_back(Point(upJumpWave[3][i], upJumpWave[1][j]));
}
}
//--------------检测涂上铅笔的区域--------------//
vector<Point2f> testKeyPoint;
checkKeypoint(grayImage, allPoint, testKeyPoint);
for (size_t i = 0; i < testKeyPoint.size(); i++)
{
rectangle(show, Rect(testKeyPoint.at(i), Point(testKeyPoint.at(i).x + 12, testKeyPoint.at(i).y + 5)), Scalar(0, 0, 255));
}
waitKey();
return 0;
}
//--------------------------------注释代码部分为未用掩码操作--------------------------//
void FindAnchorPoint(const Mat& src,const Mat& matchMask,vector<Point2f>& anchorPoint)
{
Mat matchResult;
matchResult.create(Size(src.cols - matchMask.cols, src.rows - matchMask.rows), CV_16SC1);
//----模板匹配找四个定位点,同时得归一化(初始数据范围太大,自己通过image watch 查看)
matchTemplate(src, matchMask, matchResult, TM_CCOEFF_NORMED, Mat());
normalize(matchResult, matchResult, 0, 1, NORM_MINMAX);
//----查找匹配的四个点,分成四个区域查找,因为一个区域没办法查找四个值
/*Mat topleft = matchResult(Rect(Point(0, 0), Point(matchResult.cols / 2, matchResult.rows / 2)));
Mat topright = matchResult(Rect(Point(matchResult.cols / 2, 0), Point(matchResult.cols, matchResult.rows / 2)));
Mat botleft = matchResult(Rect(Point(0, matchResult.rows / 2), Point(matchResult.cols / 2, matchResult.rows)));
Mat botright = matchResult(Rect(Point(matchResult.cols / 2, matchResult.rows / 2), Point(matchResult.cols , matchResult.rows)));*/
double maxValue[4] = { 0 }, minValue[4] = {0};
vector<Point2i> maxPoint(4), minPoint(4);
Mat topleftMask = Mat::zeros(matchResult.size(), CV_8UC1);
Mat toprightMask = Mat::zeros(matchResult.size(), CV_8UC1);
Mat botleftMask = Mat::zeros(matchResult.size(), CV_8UC1);
Mat botrightMask = Mat::zeros(matchResult.size(), CV_8UC1);
topleftMask(Rect(Point(0, 0), Point(matchResult.cols / 2, matchResult.rows / 2))).setTo(255);
toprightMask(Rect(Point(matchResult.cols / 2, 0), Point(matchResult.cols, matchResult.rows / 2))).setTo(255);
botleftMask(Rect(Point(0, matchResult.rows / 2), Point(matchResult.cols / 2, matchResult.rows))).setTo(255);
botrightMask(Rect(Point(matchResult.cols / 2, matchResult.rows / 2), Point(matchResult.cols, matchResult.rows))).setTo(255);
vector<Mat> vectorMask;//注意此处如果用vector<Mat> vectorMask(4);对应的下面写法是vectorMask[0]=topleftMask;
vectorMask.push_back(topleftMask);
vectorMask.push_back(toprightMask);
vectorMask.push_back(botleftMask);
vectorMask.push_back(botrightMask);
for (size_t i = 0; i < vectorMask.size(); i++)
{
minMaxLoc(matchResult, &minValue[i], &maxValue[i], &minPoint[i], &maxPoint[i], vectorMask[i]);
}
anchorPoint.assign(maxPoint.begin(), maxPoint.end());
//minMaxLoc(topleft, &minValue[0], &maxValue[0], &minPoint[0], &maxPoint[0]);
//minMaxLoc(topright, &minValue[1], &maxValue[1], &minPoint[1], &maxPoint[1]);
//maxPoint[1].x = maxPoint[1].x + matchResult.cols / 2;
//minMaxLoc(botleft, &minValue[2], &maxValue[2], &minPoint[2], &maxPoint[2]);
//maxPoint[2].y = maxPoint[2].y + matchResult.rows / 2;
//minMaxLoc(botright, &minValue[3], &maxValue[3], &minPoint[3], &maxPoint[3]);
//maxPoint[3].x = maxPoint[3].x + matchResult.cols / 2;
//maxPoint[3].x = maxPoint[3].y + matchResult.rows / 2;
}
//------------------------------------图像投影算法-----------------------------------------------//
//*************@src------------------输入矩阵为单通道********************************************//
//*************@leftUpJumpWave-------上升跳变沿存储**********************************************//
//*************@rightDownJumpWave----下降跳变沿存储**********************************************//
//*************@maxInterval----------允许高电平(像素)最大间隔,也可以说是允许的最大误差********//
//-----------------------------------------------------------------------------------------------//
void projectionAlgorithm(Mat src,vector<int>& UpJumpWave,vector<int>& DownJumpWave,bool Axis,int maxInterval)
{
vector<int> pixNum(src.rows > src.cols ? src.rows : src.cols);
//------对X、Y做直方图类似的投影,统计一行或者一列的非零个数--------//
if (Axis)
{
for (size_t i = 0; i < src.cols; i++)
{
Mat col = src.col(i);//一列数据
pixNum[i] = countNonZe