答题卡改卷

 当初用C++写的, 高考答题卡 大概原理是先进行模板匹配  得到四个顶点,然后分割出下图这两根线

 

 

读取端点,然后判断目标点上有没有涂黑。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <stack>
using namespace std;
using namespace cv;

vector<char*>  listFiles(const char * dir);
void cuttingX();
void cuttingY();
void HSVthreshold ();//HSV阈值分割
int linex[16]={0};
int liney[22]={0};
//for循环 用%10求余来得到余值加2便可以
/**************请在此处输入正确答案*************************/
int a[60]={15,15,14,14,16,//1-5
           15,14,14,16,15,//6-10
           16,15,16,14,16,//11-15
           15,16,14,15,14,//16-20
           13,11,12,10,12,//21-25
           12,11,10,12,13,//26-30
           11,13,12,10,11,//31-35
           12,10,11,8,7,//36-40
           5,3,6,4,6,//41-45
           6,4,5,4,3,//46-50
           6,5,4,5,3,//51-55
           5,6,6,3,4 //56-60
            };
int main()
{
    /***************拍照***************/
    VideoCapture capture(0);
    waitKey(50);
    capture.set(CV_CAP_PROP_FRAME_WIDTH, 1920);
	capture.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);
	while(1)
    {
    Mat src;
    while (1)
    {
    capture >> src;
    Mat src1=src.clone();

    int x0 = src1.cols / 4;
    int x1 = src1.cols * 9/10;
    int y0 = src1.rows / 4-140;
    int y1 = src1.rows * 9/10;
    //画线的坐标,起始坐标和终止坐标

    cv::Point p0 = cv::Point(x0,y0);
    cv::Point p1 = cv::Point(x1, y0);
    cv::Point p2 = cv::Point(x1, y1);
    cv::line(src1, p0, p1, cv::Scalar(0, 0, 255), 3, 4);
    cv::line(src1, p1, p2, cv::Scalar(0, 0, 255), 3, 4);
    cv::namedWindow("对齐", CV_WINDOW_NORMAL);
    cv::imshow("对齐", src1);
    waitKey(10);
    if(kbhit( ))
    {
        int k1=getch();
        break;
    }}
    imwrite("保存的图像.jpg", src);
    /***************模板匹配***************/
    //Mat src= imread("±£´æ.jpg",1);
    Mat mattmp= imread("3.jpg", 1);
    Mat imagematch;
    Point minLoc;
    Point maxLoc01,maxLoc02,maxLoc03,maxLoc04,judje0;
    Point anchor01,anchor02,anchor03,anchor04;
    double minVal;
    double maxVal2;
    //Mat src = imread("C:/answercard/1.jpg",0);//¶ÁÈëºÚ°×ԭʼͼÏñ
    int srcRows = src.rows;
    int srcCols = src.cols;
    Mat src01 = src(Rect(0,0,srcCols/2,srcRows/2));
    Mat src02 = src(Rect(srcCols/2,0,srcCols/2,srcRows/2));
    Mat src03 = src(Rect(0,srcRows/2,srcCols/2,srcRows/2));
    Mat src04 = src(Rect(srcCols/2,srcRows/2,srcCols/2,srcRows/2));
    //imshow("src01",src01);imshow("src02",src02);imshow("src03",src03);imshow("src04",src04);

    matchTemplate( mattmp, src01, imagematch, 5 );
    normalize( imagematch, imagematch, 0, 1, NORM_MINMAX, -1, Mat() );
    minMaxLoc( imagematch, &minVal, &maxVal2, &minLoc, &maxLoc01, Mat() );
    anchor01 = maxLoc01;
    maxLoc01.x=maxLoc01.x+28;
    maxLoc01.y=maxLoc01.y+25;
    circle(src,maxLoc01,3,Scalar(0,255,0),3);

    matchTemplate( mattmp, src02, imagematch, 5 );
    normalize( imagematch, imagematch, 0, 1, NORM_MINMAX, -1, Mat() );
    minMaxLoc( imagematch, &minVal, &maxVal2, &minLoc, &maxLoc02, Mat() );
    anchor02 = Point(maxLoc02.x+srcCols/2,maxLoc02.y);
    anchor02.x=anchor02.x+28;
    anchor02.y=anchor02.y+25;
    circle(src,anchor02,3,Scalar(0,255,0),3);

    matchTemplate( mattmp, src03, imagematch, 5 );
    normalize( imagematch, imagematch, 0, 1, NORM_MINMAX, -1, Mat() );
    minMaxLoc( imagematch, &minVal, &maxVal2, &minLoc, &maxLoc03, Mat() );
    anchor03 = Point(maxLoc03.x,maxLoc03.y+srcRows/2);
    anchor03.x=anchor03.x+28;
    anchor03.y=anchor03.y+27;
    circle(src,anchor03,3,Scalar(0,255,0),3);

    matchTemplate( mattmp, src04, imagematch, 5 );
    normalize( imagematch, imagematch, 0, 1, NORM_MINMAX, -1, Mat() );
    minMaxLoc( imagematch, &minVal, &maxVal2, &minLoc, &maxLoc04, Mat() );
    anchor04 = Point(maxLoc04.x+srcCols/2,maxLoc04.y+srcRows/2);
    anchor04.x=anchor04.x+28;
    anchor04.y=anchor04.y+27;
    circle(src,anchor04,3,Scalar(0,255,0),3);

    //cv::namedWindow("原图", CV_WINDOW_NORMAL);
    //cv::imshow("原图", src);
    imwrite("保存图像.jpg", src);
    HSVthreshold ();//HSV阈值分割
    src = imread("img.jpg", 0);


    /***************区域切割***************/
    threshold(src, src, 16, 255, THRESH_BINARY);
//    imshow("二值图",src);
    GaussianBlur(src, src, Size(9,9), 0);
    Mat element = getStructuringElement(MORPH_RECT, Size(3,4));
    dilate(src, src, element);
    //element = getStructuringElement(MORPH_RECT, Size(5,4));
    erode(src, src, element);
    GaussianBlur(src, src, Size(7,7), 0);
    GaussianBlur(src, src, Size(7,7), 0);
	//morphologyEx(img, img, MORPH_OPEN, element);
	//morphologyEx(img, img, MORPH_CLOSE, element);
	//morphologyEx(img, img, MORPH_OPEN, element);
	threshold(src, src, 150, 255, THRESH_BINARY);
 //   cv::namedWindow("camera", CV_WINDOW_NORMAL);//CV_WINDOW_NORMAL¾ÍÊÇ0
//    cv::imshow("camera", src);
    IplImage imgTmp = src;
    IplImage* image =  cvCloneImage(&imgTmp);//以上两行为深拷贝
    cvSetImageROI(image,cvRect(maxLoc01.x,anchor02.y-10,anchor02.x-maxLoc01.x,20));//x、y、长、宽
    //cvShowImage("imageROIX",image);//X轴
    cvSaveImage("imageROIX.jpg",image);
    image =  cvCloneImage(&imgTmp);
    cvSetImageROI(image,cvRect(anchor02.x-10,anchor02.y,20,anchor04.y-anchor02.y));//x、y、长、宽
    //cvShowImage("imageROIY",image);//Y轴
    cvSaveImage("imageROIY.jpg",image);
    cuttingX();
    cuttingY();
    /****************答案获取************************/
    //选择题20道 1.5分 1-20
    //21-35       2    36-40是2分一道 7个选项
    //41-60       2
    //用for循环对于某一点的右下角区域进行考察15*15
    //若白色区域大于50 则认为进行了填涂,且为对。且用绿色标注
    //否则为错,并用红色对该点进行标注
    //用for循环开始判断 x位置为linex【a【题号】】 y的位置为题号%liney【10+2】
    cvSetImageROI(image,cvRect(maxLoc01.x,anchor02.y,anchor02.x-maxLoc01.x,anchor04.y-maxLoc02.y));//x、y、长、宽
    cvSaveImage("imageROI.jpg",image);
    Mat srcXY = imread("imageROI.jpg", 1);
    float sum1=0,sum2=0,sum3=0;
    for (int tihao=0;tihao<60;tihao++)//判断每一题的正确与错误
    {
        int whitesum=0;

        for (int x=0;x<16;x++)
        {
            for (int y=0;y<16;y++)
            {
                Vec3b &p = srcXY.at<Vec3b>(liney[tihao%20+2]+y , (linex[a[tihao]-1]+x) );
                //printf(" (%d,%d)处的颜色为(b=%d, g=%d, r=%d) \n",linex[a[tihao]]+x, liney[tihao%10+2]+y,p[0], p[1], p[2]);
                //printf("第%d个的答案是%d\r\n",x+y,a[x+y]);
                if (p[0]>128)
                {
                    whitesum++;
                }
//           p[0] = 255;//p1蓝色 用于判断
//			 p[1] = 255; //P2 绿色
//			 p[2] = 255; //P3 红色
            }
        }
        judje0.x=linex[a[tihao]-1];
        judje0.y=liney[tihao%20+2];
        //printf("第%d道题目位置是(%d,%d)\r\n",tihao,judje0.x,judje0.y);
        if (whitesum>20)
        {
            circle(srcXY,judje0,3,Scalar(0,255,0),3);
            if (0<=tihao&tihao<=19) sum1++;
            if (40<=tihao&tihao<=59) sum3++;
            if (20<=tihao&tihao<=39) sum2++;

        }
        else
        {
            circle(srcXY,judje0,3,Scalar(0,0,255),3);
        }

           // printf("一共有%d个白色像素\n",whitesum);
    }
            imshow("指定点",srcXY);
            imwrite("指定点.jpg",srcXY);
            //cvSaveImage("imageROI.jpg",srcXY);
            printf("该同学1-20得分%.1f\n",(1.5*sum1));
            printf("21-40得分%.1f\n",(sum2*2));
            printf("41-60得分%.1f\n",sum3*1.5);
            printf("总分为%.1f\n",(1.5*sum1+2*sum2+1.5*sum3));

    }
    }



void HSVthreshold ()//HSV阈值分割
{
Mat img;
Mat bgr;
Mat hsv;
Mat dst;
	//输入图像
	img = imread("保存图像.jpg", IMREAD_COLOR);

	//imshow("原图", img);
	//彩色图像的灰度值归一化
	img.convertTo(bgr, CV_32FC3, 1.0 / 255, 0);
	//颜色空间转换
	cvtColor(bgr, hsv, COLOR_BGR2HSV);

   dst = Mat::zeros(img.size(), CV_32FC3);
	//掩码
	Mat mask;
	inRange(hsv, Scalar(0, 0 / float(255)    ,     0 / float(255))    , Scalar(360 , 255  / float(255)     , 142  / float(255)), mask);
	//               hmin,smin/float(smin_Max), vmin / float(vmin_Max)), Scalar(hmax, smax / float(smax_Max), vmax / float(vmax_Max)
	//只保留
	for (int r = 0; r < bgr.rows; r++)
	{
		for (int c = 0; c < bgr.cols; c++)
		{
			if (mask.at<uchar>(r, c) == 255)
			{
				dst.at<Vec3f>(r, c) = bgr.at<Vec3f>(r, c);
			}
		}
	}
	//输出图像
	//imshow("3HSV阈值计算", dst);
	//保存图像
    dst.convertTo(dst, CV_8UC3, 255.0, 0);
	imwrite("img.jpg", dst);
    dst.release();//释放内存
	//waitKey(0);

}

void cuttingX( )
{

    //一共有15个点 后期进行位置排序 并且去掉第一个和最后一个
    Mat matSrc = imread("imageROIX.jpg", 0);
    //threshold(matSrc, matSrc, 135, 254, THRESH_BINARY_INV);

	GaussianBlur(matSrc, matSrc, Size(7,7), 0);
	vector<vector<Point> > contours;//contours的类型,双重的vector
	vector<Vec4i> hierarchy;//Vec4i是指每一个vector元素中有四个int型数据。
	//阈值
	threshold(matSrc, matSrc, 70, 255, THRESH_BINARY);
	//imshow("阈值",matSrc);
	//寻找轮廓,这里注意,findContours的输入参数要求是二值图像,二值图像的来源大致有两种,第一种用threshold,第二种用canny
	findContours(matSrc.clone(), contours, hierarchy,CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
	/// 计算矩
	vector<Moments> mu(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		mu[i] = moments(contours[i], false);
	}
	///  计算中心矩:
	vector<Point2f> mc(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
		linex[i]=int (mu[i].m10 / mu[i].m00);
		//printf("第 %d 个的位置是 %d\r\n",i,linex[i]);
	}
	/// 绘制轮廓
	Mat drawing = Mat::zeros(matSrc.size(), CV_8UC1);
	for (int i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(255);
		//drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
		circle(drawing, mc[i], 4, color, -1, 8, 0);
	}
	int i,j,temp;
    for(j=0;j<=17;j++)//外围循环 循环10次
    {
        for (i=0;i<16-j;i++)//内层循环 循环 10减去外围的循环的第几次
        if (linex[i]>linex[i+1])//比较 比较 a[i]是不是大于a[i+1]是的话
    {
        temp=linex[i]; //就吧a[i]和a[i+1]互相交换了 这样 大的数就 随着循环
        linex[i]=linex[i+1]; //排到 后面了
        linex[i+1]=temp;}
    }
    //for(i=0;i<16;i++)
 //   printf("%d=%d,",i,linex[i] );//去掉前后两个
//    printf("\r\n");
//	imshow("outImageX",drawing);

}
void cuttingY( )
{
    Mat matSrc = imread("imageROIY.jpg", 0);
    //threshold(matSrc, matSrc, 120, 254, THRESH_BINARY_INV);

	GaussianBlur(matSrc, matSrc, Size(7, 7), 0);
	vector<vector<Point> > contours;//contours的类型,双重的vector
	vector<Vec4i> hierarchy;//Vec4i是指每一个vector元素中有四个int型数据。
	//阈值
	threshold(matSrc, matSrc, 70, 255, THRESH_BINARY);
	//寻找轮廓,这里注意,findContours的输入参数要求是二值图像,二值图像的来源大致有两种,第一种用threshold,第二种用canny
	findContours(matSrc.clone(), contours, hierarchy,CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));
	/// 计算矩
	vector<Moments> mu(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		mu[i] = moments(contours[i], false);
	}
	///  计算中心矩:
	vector<Point2f> mc(contours.size());
	for (int i = 0; i < contours.size(); i++)
	{
		mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
		liney[i]=int (mu[i].m01 / mu[i].m00);
		//printf("第%d个的位置是%d\r\n",i,liney[i]);
	}
	/// 绘制轮廓
	Mat drawing = Mat::zeros(matSrc.size(), CV_8UC1);
	for (int i = 0; i < contours.size(); i++)
	{
		Scalar color = Scalar(255);
		//drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
		circle(drawing, mc[i], 4, color, -1, 8, 0);
	}
	int i,j,temp;
    for(j=0;j<=23;j++)//外围循环 循环10次
    { for (i=0;i<22-j;i++)//内层循环 循环 10减去外围的循环的第几次
    if (liney[i]>liney[i+1])//比较 比较 a[i]是不是大于a[i+1]是的话
    { temp=liney[i]; //就吧a[i]和a[i+1]互相交换了 这样 大的数就 随着循环
    liney[i]=liney[i+1]; //排到 后面了
    liney[i+1]=temp;}
    }
 //   for(i=0;i<22;i++)
 //   printf("%d=%d,",i,liney[i] );//去掉前后两个
//    printf("\r\n");
//	imshow("outImageY",drawing);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值