opencv学习系列:实例练习(含多个实例)

//-----------------------------------(续10月份)------------------------------------- 
//int main(int argc,char* argv[])和int main(int argc, char **argv)的使用方法
int   main(int   argc,   char*   argv[])  
   {  
   int   i;  
   for   (i   =   0;   i<argc;   i++)  
   cout<<argv[i]<<endl;  
   cin>>i;  
   return   0;  
   }  
   在DOS执行时敲入  
   F:\MYDOCU~1\TEMPCODE\D1\DEBUG\D1.EXE   aaaa   bbb   ccc   ddd  
   输出如下:  
   F:\MYDOCU~1\TEMPCODE\D1\DEBUG\D1.EXE  
   aaaa  
   bbb  
   ccc  
   ddd  
//-----------------------------------OpenCV学习------------------------------------- 
//  程序名称:OSTU算法选自适应阈值
//  2016年10月 Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp> 
#include <iostream>
#include <string> 
#include <cassert>

using namespace cv;
using namespace std;
隐藏控制台窗口
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
int otsu(IplImage *image)
{
    assert(NULL != image);//若执行该函数,则终止程序运行

    int width = image->width;
    int height = image->height;
    int x = 0, y = 0;
    int pixelCount[256];
    float pixelPro[256];
    int i, j, pixelSum = width * height, threshold = 0;

    uchar* data = (uchar*)image->imageData;

    //初始化  
    for (i = 0; i < 256; i++)
    {
        pixelCount[i] = 0;
        pixelPro[i] = 0;
    }

    //统计灰度级中每个像素在整幅图像中的个数  
    for (i = y; i < height; i++)
    {
        for (j = x; j<width;j++)
        pixelCount[data[i * image->widthStep + j]]++;
    }


    //计算每个像素在整幅图像中的比例  
    for (i = 0; i < 256; i++)
    {
        pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
    }

    //经典ostu算法,得到前景和背景的分割  
    //遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值  
    float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
    for (i = 0; i < 256; i++)//i为阈值
    {
        w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

        for (j = 0; j < 256; j++)//遍历阈值数组当i=0,1,2,3...255
        {
            if (j <= i) //背景部分  
            {
                //以i为阈值分类,第一类总的概率  
                w0 += pixelPro[j];
                u0tmp += j * pixelPro[j];
            }
            else       //前景部分  
            {
                //以i为阈值分类,第二类总的概率  
                w1 += pixelPro[j];
                u1tmp += j * pixelPro[j];
            }
        }

        u0 = u0tmp / w0;        //第一类的平均灰度  
        u1 = u1tmp / w1;        //第二类的平均灰度  
        u = u0tmp + u1tmp;      //整幅图像的平均灰度  
        //计算类间方差  
        deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
        //找出最大类间方差以及对应的阈值  
        if (deltaTmp > deltaMax)
        {
            deltaMax = deltaTmp;
            threshold = i;
        }
    }
    //返回最佳阈值;  
    return threshold;
}

int main(int argc, char* argv[])
{
    IplImage* srcImage = cvLoadImage("F:\\workplace\\opencv_training\\test2.png", 0);
    assert(NULL != srcImage);

    cvNamedWindow("src");
    cvShowImage("src", srcImage);

    IplImage* biImage = cvCreateImage(cvGetSize(srcImage), 8, 1);

    //计算最佳阈值  
    int threshold = otsu(srcImage);
    //对图像二值化  
    cvThreshold(srcImage, biImage, threshold, 255, CV_THRESH_BINARY);

    cvNamedWindow("binary");
    cvShowImage("binary", biImage);

    cvWaitKey(0);

    cvReleaseImage(&srcImage);
    cvReleaseImage(&biImage);
    cvDestroyWindow("src");
    cvDestroyWindow("binary");

    return 0;
}
//************************************************************************************************
//-----------------------------------OpenCV2---标定焊接图像------------------------------------- 
//  程序名称:OpenCV标定焊接图像,该程序根据DOS提示,一步步实现标定的自动化,求取内参
//  所用IDE版本:        Visual Studio 2013    
//  开发所用OpenCV版本:        2.4.9    
//  2016年10月 Created by 孙立波    

//包含程序所依赖的头文件:为方便起见把经常用的头文件都写在这里(前三必须包含),也可以用#include "opencv.hpp"包含下面所有头文件
#include <opencv2\opencv.hpp>   
#include <iostream>
#include <string> 
#include <vector>
#include <iomanip>
#include <fstream>
using namespace cv;
using namespace std;
//隐藏控制台窗口
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
void main()
{
    /************************************************************************
    读取21张图像,存入内存F:\biaoding文件中
    *************************************************************************/
    cout << "开始提取21张标定板图像………………" << endl;
    int imageCount = 21;
    int key;
    int count1=0;
    for (int i=0; i != imageCount; i++)
    {
        cout << "Frame#" << i + 1 << "..." << endl;
        std::stringstream StrStm;
        //为了将i转化为字符型,用StrStm做中介
        string imageFileName;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += ".jpg";
        key = waitKey();
        cout << "按Enter开始抽取图像,进入后可按q或者ESC键重新抽取图像,若按Enter键表明这帧图像被存入文件夹中" << endl;
        if (key == 13)
        {
            int flag = 1;
            while (flag)
            {
                Mat image0;//抽取到的临时图像数据并显示出来

                imshow("显示抓取图像", image0);//显示是否符合要求
                int key2 = waitKey();
                if (key2 == 13)
                {
                    cout << "提取标定板图像成功!………………" << endl;
                    std::stringstream str;
                    str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
                    std::cout<<"提取的图像保存路径及文件名" << str.str() << endl;
                    imwrite(str.str(), image0);
                    flag = 0;
                    count1 += 1;//已经得到的标定图像计数总数
                }
                else
                   if (key2 == 113 || key2 == 27)
                        cout << "这次提取的标定板图像不成功!重新提取!!!!………………" << endl;
             }
         }
    }   
    if (count1 == 21)
    {
        cout << "***********************………………" << endl;
        cout << "***********************………………" << endl;
        cout << "下面开始标定图像...................." << endl;
        count1 = 0;
    }


    /************************************************************************
    读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    *************************************************************************/
    cout << "开始提取角点………………" << endl;

    double time0 = static_cast<double>(getTickCount());
    ofstream fout("F:\\biaoding\\caliberation_result.txt");  /**    保存定标结果的文件     **/
    Size image_size;                          /****    图像的尺寸      ****/
    Size board_size = Size(9, 6);             /****    定标板上每行、列的角点数       ****/
    vector<Point2f> corners;                  /****    缓存每幅图像上检测到的角点     ****/
    vector<vector<Point2f>>  corners_Seq;     /****    保存检测到的所有角点           ****/
    vector<Mat>  image_Seq;

    int count = 0;
    int image_count = 21;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        std::stringstream str;
        str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
        std::cout << str.str() << std::endl;
        Mat image = cv::imread(str.str());
        image_size = image.size();
        //image_size = Size(image.cols , image.rows);

        /* 提取角点 */
        int channel = 3;
        Mat imageGray;
        if (channel == image.channels() )
            cvtColor(image, imageGray, CV_RGB2GRAY);
        else
            imageGray=image;
        bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
            CALIB_CB_FAST_CHECK);
        if (!patternfound)
        {
            cout << "can not find chessboard corners!\n";
            continue;
            exit(1);
        }
        else
        {
            /*
            亚像素精确化 :迭代过程的终止条件可以是最大迭代次数CV_TERMCRIT_ITER类型,或者是设定的精度CV_TERMCRIT_EPS类型(或者是两
            者的组合)。终止条件的设置在极大程度上影响最终得到的亚像素值的精度。在此,指定为0.10,则求得的亚像素级精度为像素的十分
            之一
            */
            cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
            //Size(11, 11)为搜索窗口的一半尺寸,Size(-1, -1)死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。/
            //它是用来避免自相关矩阵出现的某些可能的奇异性。当值为(-1,-1)表示没有死区。
            //TermCriteria为求角点的迭代过程的终止条件。即角点位置的确定,要么迭代数大于某个设定值,或者是精确懂达到某个设定值。
            //criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
            /* 绘制检测到的角点并保存 */
            Mat imageTemp = image.clone();
            for (int j = 0; j < corners.size(); j++)
            {
                circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);
            }
            string imageFileName1;
            std::stringstream StrStm;
            StrStm << i + 1;
            StrStm >> imageFileName1;
            imageFileName1 += "_corner.jpg";
            //保存提取角点的图像
            imwrite("F:\\biaoding\\imageFileName1", imageTemp);
            cout << "Frame corner#" << i + 1 << "...end" << endl;

            count = count + corners.size();//记录这一副保存到coners容器中的角点总数
            //将该角点压入角点序列堆栈
            corners_Seq.push_back(corners);//将所有图像的coners全部压入一个序列的堆栈,即元素为vector容器的堆栈
        }
        //将处理过的图像压入源图像堆栈
        image_Seq.push_back(image);
    }
    cout << "角点提取完成!下一步摄像机定标\n";

    /************************************************************************
    摄像机定标
    *************************************************************************/
    cout << "开始定标………………" << endl;
    Size square_size = Size(80, 80);                                      /**** 实际测量得到的定标板上每个棋盘格的大小,单位为像素 ****/
    vector<vector<Point3f>>  object_Points;                               /**** 保存定标板上角点的三维坐标   ****/


    Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0));          /***** 保存提取的所有角点1*序列图像的角点总数   *****/
    vector<int>  point_counts;                                           /***** 每幅图像中角点的数量 ****/
    Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));          /***** 摄像机内参数矩阵    ****/
    Mat distortion_coeffs = Mat(1, 4, CV_32FC1, Scalar::all(0));         /* 摄像机的4个畸变系数:k1,k2,p1,p2 */
    vector<cv::Mat> rotation_vectors;                                    /* 图像序列图像的旋转向量,每一行代表一个旋转向量 */
    vector<cv::Mat> translation_vectors;                                 /* 每幅图像的平移向量,每一行代表一个平移向量 */

    /* 初始化定标板上角点的三维坐标,此用的是像素坐标 */
    for (int t = 0; t<image_count; t++)
    {
        vector<Point3f> tempPointSet;//存储每幅图像的像素坐标
        for (int i = 0; i<board_size.height; i++)
        {
            for (int j = 0; j<board_size.width; j++)
            {
                /* 假设定标板放在世界坐标系中z=0的平面上 */
                Point3f tempPoint;
                //在这里,board_size中棋盘格子为单位长度,当square_size存储的像素边长为边长为80,代表width、height为80
                tempPoint.x = i*square_size.width;
                tempPoint.y = j*square_size.height;
                tempPoint.z = 0;
                tempPointSet.push_back(tempPoint);
            }
        }
        object_Points.push_back(tempPointSet);//存储图像序列中每幅图像的像素坐标
    }

    /* 初始化每幅图像中的角点数量,这里我们假设每幅图像中都可以看到完整的定标板 */
    for (int i = 0; i< image_count; i++)
    {
        point_counts.push_back(board_size.width*board_size.height);
    }

    /* 开始定标 */
    calibrateCamera(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, 0);
    cout << "定标完成!\n";

    /************************************************************************
    对定标结果进行评价
    *************************************************************************/
    cout << "开始评价定标结果………………" << endl;
    double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
    double err = 0.0;                        /* 每幅图像的平均误差 */
    vector<Point2f>  image_points2;             /****   保存重新计算得到的投影点    ****/

    cout << "每幅图像的定标误差:" << endl;
    fout << "每幅图像的定标误差:" << endl << endl;
    for (int i = 0; i<image_count; i++)
    {
        vector<Point3f> tempPointSet = object_Points[i];
        /****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
        projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);
        /* 计算新的投影点和旧的投影点之间的误差*/
        vector<Point2f> tempImagePoint = corners_Seq[i];
        Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
        Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
        for (size_t i = 0; i != tempImagePoint.size(); i++)
        {
            image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
            tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
        }
        err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
        total_err += err /= point_counts[i];
        cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
        fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    }
    cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
    fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
    cout << "评价完成!" << endl;

    /************************************************************************
    保存定标结果
    *************************************************************************/
    cout << "开始保存定标结果………………" << endl;
    Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

    fout << "相机内参数矩阵:" << endl;
    cout << "相机内参数矩阵:" << endl;
    fout << intrinsic_matrix << endl;
    cout << intrinsic_matrix << endl;
    fout << "畸变系数:\n";
    cout << "畸变系数:\n";
    fout << distortion_coeffs << endl;
    cout << distortion_coeffs << endl;
    for (int i = 0; i<image_count; i++)
    {
        fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
        fout << rotation_vectors[i] << endl;

        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(rotation_vectors[i], rotation_matrix);
        fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
        fout << rotation_matrix << endl;
        fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
        fout << translation_vectors[i] << endl;
    }
    cout << "完成保存" << endl;
    fout << endl;


    /************************************************************************
    显示定标结果
    *************************************************************************/
    Mat mapx = Mat(image_size, CV_32FC1);
    Mat mapy = Mat(image_size, CV_32FC1);
    Mat R = Mat::eye(3, 3, CV_32F);
    cout << "保存矫正图像" << endl;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
        //矩阵前三列的有用部分作为输入参数)注:!!无校正变换的相机仍用求得内参矩阵
        Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
        //得到映射关系:R——输入的第一和第二相机坐标系之间的旋转矩阵,一般般无校正变换的相机,默认为单位矩阵
        // opencv中,remap与undistortion都是消除畸变的函数,undistortion在设置了一些参数后调用了remap函数,二者的算法实质是一样
        //的。由目标图像的坐标,找到对应的原始图像坐标,然后将其值复制到目标图像。大致思路是如此,由于图像大小和变换,需要插值或
        //近似的方法,如最邻近法、线性插值等
        initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
        Mat t = image_Seq[i].clone();
        cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);
        string imageFileName;
        std::stringstream StrStm;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += "_校正图像.jpg";
        imwrite("F:\\biaoding\\imageFileName", t);//*********************************把每幅校正后的图像保存到内存F:\biaoding文件中
    }
    cout << "保存结束" << endl;

    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "定标及用畸变参数和内参矩阵矫正所有图像总用时:" << time0 << "秒" << endl;
    waitKey(0);
}
***********************************************************************************************
//-----------------------------------OpenCV3标定焊接图像------------------------------------- 
//  程序名称:OpenCV标定焊接图像,该程序根据DOS提示,一步步实现标定的自动化,求取内参,标定请在F盘创建“biaoding”用于储存采集的图像和结果
//  需要设置的参数: 需要提取的的图像数imageCount = 21,每个标定板图像角点数board_size = Size(9, 6),每个格子像素边长Size square_size = Size(80, 80);  
//  过程描述:提取图像并保存,提取各图像序列角点,角点亚像素精确化,摄像机标定畸变参数和内参,定标结果评价(保存结果在F:\\biaoding\\caliberation_result.txt),最后矫正所有图像到F:\\biaoding
//  所用IDE版本:        Visual Studio 2013    
//  开发所用OpenCV版本:        2.4.9    
//  2016年10月 Created by 孙立波    

//包含程序所依赖的头文件:为方便起见把经常用的头文件都写在这里(前三必须包含),也可以用#include "opencv.hpp"包含下面所有头文件
#include <opencv2\opencv.hpp>   
#include <iostream>
#include <string> 
#include <vector>
#include <iomanip>
#include <fstream>
using namespace cv;
using namespace std;
//隐藏控制台窗口
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
void main()
{
    /************************************************************************
    读取21张图像,存入内存F:\biaoding文件中
    *************************************************************************/
    cout << "开始提取21张标定板图像………………" << endl;
    int imageCount = 21;
    int key;
    int count1=0;
    for (int i=0; i != imageCount; i++)
    {
        cout << "Frame#" << i + 1 << "..." << endl;
        std::stringstream StrStm;
        //为了将i转化为字符型,用StrStm做中介
        string imageFileName;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += ".jpg";
        key = waitKey();
        cout << "按Enter开始抽取图像,进入后可按q或者ESC键重新抽取图像,若按Enter键表明这帧图像被存入文件夹中" << endl;
        if (key == 13)
        {
            int flag = 1;
            while (flag)
            {
                Mat image0;//抽取到的临时图像数据并显示出来

                imshow("显示抓取图像", image0);//显示是否符合要求
                int key2 = waitKey();
                if (key2 == 13)
                {
                    cout << "提取标定板图像成功!………………" << endl;
                    std::stringstream str;
                    str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
                    std::cout<<"提取的图像保存路径及文件名" << str.str() << endl;
                    imwrite(str.str(), image0);
                    flag = 0;
                    count1 += 1;//已经得到的标定图像计数总数
                }
                else
                   if (key2 == 113 || key2 == 27)
                        cout << "这次提取的标定板图像不成功!重新提取!!!!………………" << endl;
             }
         }
    }   
    if (count1 == imageCount)
    {
        cout << "***********************………………" << endl;
        cout << "***********************………………" << endl;
        cout << "下面开始标定图像...................." << endl;
        count1 = 0;
    }


    /************************************************************************
    读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    *************************************************************************/
    cout << "开始提取角点………………" << endl;

    double time0 = static_cast<double>(getTickCount());//记录定标参数求取和将所有图像矫正用的总时间
    ofstream fout("F:\\biaoding\\caliberation_result.txt");  /**    保存定标结果的文件     **/
    Size image_size;                          /****    图像的尺寸      ****/
    Size board_size = Size(9, 6);             /****    定标板上每行、列的角点数       ****/
    vector<Point2f> corners;                  /****    缓存每幅图像上检测到的角点     ****/
    vector<vector<Point2f>>  corners_Seq;     /****    保存检测到的所有角点           ****/
    vector<Mat>  image_Seq;

    int count = 0;
    int image_count = imageCount;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        std::stringstream str;
        str << "F:\\biaoding\\img" << std::setw(2) << std::setfill('0') << i + 1 << ".jpg";
        std::cout << str.str() << std::endl;
        Mat image = cv::imread(str.str());
        image_size = image.size();
        //image_size = Size(image.cols , image.rows);

        /* 提取角点 */
        int channel = 3;
        Mat imageGray;
        if (channel == image.channels() )
            cvtColor(image, imageGray, CV_RGB2GRAY);
        else
            imageGray=image;
        bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
            CALIB_CB_FAST_CHECK);
        if (!patternfound)
        {
            cout << "can not find chessboard corners!\n";
            continue;
            exit(1);
        }
        else
        {
            /*
            亚像素精确化 :迭代过程的终止条件可以是最大迭代次数CV_TERMCRIT_ITER类型,或者是设定的精度CV_TERMCRIT_EPS类型(或者是两
            者的组合)。终止条件的设置在极大程度上影响最终得到的亚像素值的精度。在此,指定为0.10,则求得的亚像素级精度为像素的十分
            之一
            */
            cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
            //Size(11, 11)为搜索窗口的一半尺寸,Size(-1, -1)死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。/
            //它是用来避免自相关矩阵出现的某些可能的奇异性。当值为(-1,-1)表示没有死区。
            //TermCriteria为求角点的迭代过程的终止条件。即角点位置的确定,要么迭代数大于某个设定值,或者是精确懂达到某个设定值。
            //criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
            /* 绘制检测到的角点并保存 */
            Mat imageTemp = image.clone();
            for (int j = 0; j < corners.size(); j++)
            {
                circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);
            }
            string imageFileName1;
            std::stringstream StrStm;
            StrStm << i + 1;
            StrStm >> imageFileName1;
            imageFileName1 += "_corner.jpg";
            //保存提取角点的图像
            imwrite("F:\\biaoding\\imageFileName1", imageTemp);
            cout << "Frame corner#" << i + 1 << "...end" << endl;

            count = count + corners.size();//记录这一副保存到coners容器中的角点总数
            //将该角点压入角点序列堆栈
            corners_Seq.push_back(corners);//将所有图像的coners全部压入一个序列的堆栈,即元素为vector容器的堆栈
        }
        //将处理过的图像压入源图像堆栈
        image_Seq.push_back(image);
    }
    cout << "角点提取完成!下一步摄像机定标\n";

    /************************************************************************
    摄像机定标
    *************************************************************************/
    cout << "开始定标………………" << endl;
    Size square_size = Size(80, 80);                                      /**** 实际测量得到的定标板上每个棋盘格的大小,单位为像素 ****/
    vector<vector<Point3f>>  object_Points;                               /**** 保存定标板上角点的三维坐标   ****/


    Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0));          /***** 保存提取的所有角点1*序列图像的角点总数   *****/
    vector<int>  point_counts;                                           /***** 每幅图像中角点的数量 ****/
    Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));          /***** 摄像机内参数矩阵    ****/
    Mat distortion_coeffs = Mat(1, 4, CV_32FC1, Scalar::all(0));         /* 摄像机的4个畸变系数:k1,k2,p1,p2 */
    vector<cv::Mat> rotation_vectors;                                    /* 图像序列图像的旋转向量,每一行代表一个旋转向量 */
    vector<cv::Mat> translation_vectors;                                 /* 每幅图像的平移向量,每一行代表一个平移向量 */

    /* 初始化定标板上角点的三维坐标,此用的是像素坐标 */
    for (int t = 0; t<image_count; t++)
    {
        vector<Point3f> tempPointSet;//存储每幅图像的像素坐标
        for (int i = 0; i<board_size.height; i++)
        {
            for (int j = 0; j<board_size.width; j++)
            {
                /* 假设定标板放在世界坐标系中z=0的平面上 */
                Point3f tempPoint;
                //在这里,board_size中棋盘格子为单位长度,当square_size存储的像素边长为边长为80,代表width、height为80
                tempPoint.x = i*square_size.width;
                tempPoint.y = j*square_size.height;
                tempPoint.z = 0;
                tempPointSet.push_back(tempPoint);
            }
        }
        object_Points.push_back(tempPointSet);//存储图像序列中每幅图像的像素坐标
    }

    /* 初始化每幅图像中的角点数量,这里我们假设每幅图像中都可以看到完整的定标板 */
    for (int i = 0; i< image_count; i++)
    {
        point_counts.push_back(board_size.width*board_size.height);
    }

    /* 开始定标 */
    calibrateCamera(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, 0);
    cout << "定标完成!\n";

    /************************************************************************
    对定标结果进行评价
    *************************************************************************/
    cout << "开始评价定标结果………………" << endl;
    double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
    double err = 0.0;                        /* 每幅图像的平均误差 */
    vector<Point2f>  image_points2;             /****   保存重新计算得到的投影点    ****/

    cout << "每幅图像的定标误差:" << endl;
    fout << "每幅图像的定标误差:" << endl << endl;
    for (int i = 0; i<image_count; i++)
    {
        vector<Point3f> tempPointSet = object_Points[i];
        /****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
        projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);
        /* 计算新的投影点和旧的投影点之间的误差*/
        vector<Point2f> tempImagePoint = corners_Seq[i];
        Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
        Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
        for (size_t i = 0; i != tempImagePoint.size(); i++)
        {
            image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
            tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
        }
        err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
        total_err += err /= point_counts[i];
        cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
        fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    }
    cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
    fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
    cout << "评价完成!" << endl;

    /************************************************************************
    保存定标结果
    *************************************************************************/
    cout << "开始保存定标结果………………" << endl;
    Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

    fout << "相机内参数矩阵:" << endl;
    cout << "相机内参数矩阵:" << endl;
    fout << intrinsic_matrix << endl;
    cout << intrinsic_matrix << endl;
    fout << "畸变系数:\n";
    cout << "畸变系数:\n";
    fout << distortion_coeffs << endl;
    cout << distortion_coeffs << endl;
    for (int i = 0; i<image_count; i++)
    {
        fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
        fout << rotation_vectors[i] << endl;

        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(rotation_vectors[i], rotation_matrix);
        fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
        fout << rotation_matrix << endl;
        fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
        fout << translation_vectors[i] << endl;
    }
    cout << "完成保存" << endl;
    fout << endl;


    /************************************************************************
    显示定标结果
    *************************************************************************/
    Mat mapx = Mat(image_size, CV_32FC1);
    Mat mapy = Mat(image_size, CV_32FC1);
    Mat R = Mat::eye(3, 3, CV_32F);
    cout << "保存矫正图像" << endl;
    for (int i = 0; i != image_count; i++)
    {
        cout << "Frame #" << i + 1 << "..." << endl;
        //newCameraMatrix——输入的校正后的3X3摄像机矩阵(也可用cvStereoRectify()得出的3X4的左或右投影矩阵,其实系统会自动提取该
        //矩阵前三列的有用部分作为输入参数)注:!!无校正变换的相机仍用求得内参矩阵
        Mat newCameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
        //得到映射关系:R——输入的第一和第二相机坐标系之间的旋转矩阵,一般般无校正变换的相机,默认为单位矩阵
        // opencv中,remap与undistortion都是消除畸变的函数,undistortion在设置了一些参数后调用了remap函数,二者的算法实质是一样
        //的。由目标图像的坐标,找到对应的原始图像坐标,然后将其值复制到目标图像。大致思路是如此,由于图像大小和变换,需要插值或
        //近似的方法,如最邻近法、线性插值等
        initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, intrinsic_matrix, image_size, CV_32FC1, mapx, mapy);
        Mat t = image_Seq[i].clone();
        cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);
        string imageFileName;
        std::stringstream StrStm;
        StrStm << i + 1;
        StrStm >> imageFileName;
        imageFileName += "_校正图像.jpg";
        imwrite("F:\\biaoding\\imageFileName", t);//*********************************把每幅校正后的图像保存到内存F:\biaoding文件中
    }
    cout << "保存结束" << endl;

    time0 = ((double)getTickCount() - time0) / getTickFrequency();
    cout << "定标及用畸变参数和内参矩阵矫正所有图像总用时:" << time0 << "秒" << endl;
    waitKey(0);
}



//-----------------------------------(车牌识别之主要代码)------------------------------------- 
//**********主要测试程序
#include "include/plate_recognize.h"
#include "include/util.h"
#include "include/features.h"

using namespace easypr;

int svmMain();
int acurayTestMain();//用general数据集测试模型系统模型效果

namespace easypr {

    int svmTrain(bool dividePrepared = true, bool trainPrepared = true,
    svmCallback getFeatures = getHistogramFeatures);

}

extern const string GENERAL_TEST_PATH = "image/general_test";
extern const string NATIVE_TEST_PATH = "image/native_test";




const string option[] = 
    {
        "1. 测试;"    ,
        "2. 批量测试;"      ,
        "3. SVM训练;"     ,
        "4. ANN训练;"     ,
        "5. GDTS生成;"        ,
        "6. 退出;"            ,  
    };

const int optionCount = 6;

int main()
{
    bool isExit = false;
    while (isExit != true)
    {
        stringstream selectOption(stringstream::in | stringstream::out);
        selectOption << "EasyPR Option:"<< endl;
        for(int i = 0; i < optionCount; i++)
        {
            selectOption << option[i] << endl;
        }

        cout << ""<< endl;
        cout << selectOption.str();
        cout << ""<< endl;
        cout << "请选择一项操作:";

        int select = -1;
        bool isRepeat = true;
        while (isRepeat)
        {
            cin >> select;
            isRepeat = false;
            switch (select)
            {
            case 1:
                testMain();
                break;
            case 2:
                acurayTestMain();
                break;
            case 3:
                svmMain();
                break;
            case 4:
                // TODO
                //annMain();还未实现
                break;
            case 5:
                generate_gdts();
                break;
            case 6:
                isExit = true;
                break;
            default:
                cout << "输入错误,请重新输入:";
                isRepeat = true;
                break;
            }
        }
    }
    return 0;
}
//****************************************************************************************
// 通用正确率测试文件
// AcurayTest对应到main控制命令中的选项2

#include "../include/plate_recognize.h"
#include "../include/util.h"
#include "../include/features.h"

using namespace easypr;

int acurayTest(const string& test_path)
{
    获取该路径下的所有文件
    vector<string> files;
    getFiles(test_path, files);

    CPlateLocate lo;
    CPlateJudge ju;
    CPlateRecognize pr;

    pr.LoadANN("model/ann.xml");
    pr.LoadSVM("model/svm.xml");
    pr.setLifemode(true);

    int size = files.size();
    //int size = 200;

    if (0 == size)
    {
        cout << "No File Found in general_test/native_test!" << endl;
        return 0;
    }

    cout << "Begin to test the easypr accuracy!" << endl;

    // 总的测试图片数量
    int count_all = 0;
    // 错误的图片数量
    int count_err = 0;
    // 未识别的图片数量:即无车牌图片数量
    int count_norecogin = 0;

    // 总的字符差距
    float diff_all = 0;
    // 平均字符差距
    float diff_avg = 0;
    // 完全匹配的识别次数
    float match_count = 0;
    // 完全匹配的识别次数所占识别图片中的比例
    float match_rate = 0;

    for (int i = 0; i < size; i++)
    {
        string filepath = files[i].c_str();
        cout << "------------------" << endl;

        // 获取真实的车牌
        string plateLicense = "";
        getFileName(filepath, plateLicense);

        cout << "原牌:" << plateLicense << endl;

        // EasyPR开始判断车牌
        Mat src = imread(filepath);
        vector<string> plateVec;
        int result = pr.plateRecognize(src, plateVec);
        if (result == 0)
        {
            int num = plateVec.size();

            if (num == 0)
            {
                cout << ""<< "无车牌" <<endl;
                if (plateLicense != "无车牌")
                    count_norecogin++;
            } 
            else if ( num > 1)
            {
                // 多车牌使用diff最小的那个记录
                int mindiff = 10000;
                for (int j = 0; j < num; j++)
                {
                    cout << plateVec[j] << " (" << j+1 << ")"<<endl;
                    string colorplate = plateVec[j];

                    // 计算"蓝牌:苏E7KU22"中冒号后面的车牌大小"
                    vector<string> spilt_plate;
                    SplitString(colorplate, spilt_plate, ":");

                    int size = spilt_plate.size();
                    if (size == 2)
                    {
                        int diff = levenshtein_distance(plateLicense, spilt_plate[size-1]);
                        if (diff < mindiff)
                            mindiff = diff;
                    }
                }

                //cout << "差距:" << mindiff << "个字符" << endl;
                if(mindiff == 0)
                {
                    // 完全匹配
                    match_count++;
                }
                diff_all = diff_all + mindiff;
            }
            else
            {
                // 单车牌只计算一次diff
                for (int j = 0; j < num; j++)
                {
                    cout << plateVec[j] <<endl;
                    string colorplate = plateVec[j];

                    // 计算"蓝牌:苏E7KU22"中冒号后面的车牌大小"
                    vector<string> spilt_plate;
                    SplitString(colorplate, spilt_plate, ":");

                    int size = spilt_plate.size();
                    if (size == 2)
                    {
                        int diff = levenshtein_distance(plateLicense, spilt_plate[size-1]);
                        //cout << "差距:" << diff << "个字符" << endl;

                        if(diff == 0)
                        {
                            // 完全匹配
                            match_count++;
                        }
                        diff_all = diff_all + diff;
                    }
                }

            }
        } 
        else
        {
            cout << "错误码:" << result << endl;
            count_err++;
        }
        count_all++;
    }

    cout << "------------------" << endl;
    cout << "系统批量测试 end!" << endl;
    cout << "------------------" << endl;
    cout << endl;
    cout << "统计数据如下:"  << endl;
    cout << "总图片数:" << count_all << "张,  ";
    //cout << "未识别图片:" << count_norecogin << "张,  ";

    float count_recogin = count_all - (count_err + count_norecogin);
    float count_rate  = count_recogin / count_all * 100;
    //cout << "识别率:" << count_rate << "%  " << endl;

    diff_avg = diff_all / count_recogin;
    match_rate = match_count/ count_recogin * 100;

    //cout << "平均字距:" << diff_avg << "个,  ";
    cout << "完全匹配数:" << match_count << "张,  ";
    cout << "完全匹配率:" << match_rate << "%  " << endl;
    cout << endl;

    cout << "------------------" << endl;

    return 0;
}

//***********************************************************************************************
单张图片测试程序
#include "../include/plate_locate.h"
#include "../include/plate_judge.h"
#include "../include/chars_segment.h"
#include "../include/chars_identify.h"

#include "../include/plate_detect.h"
#include "../include/chars_recognise.h"

#include "../include/plate_recognize.h"

using namespace easypr;

int test_plate_locate();
int test_plate_judge();
int test_chars_segment();
int test_chars_identify();
int test_plate_detect();
int test_chars_recognise();
int test_plate_recognize();
int testMain();


//把你要测试的图片地址写在下面
const string test_img = "";


const string testOption[] = 
    {
        "1. test plate_locate(车牌定位);"       /* 车牌定位 */,
        "2. test plate_judge(车牌判断);"        /* 车牌判断 */,  
        "3. test plate_detect(车牌检测);"       /* 车牌检测(包含车牌定位与车牌判断) */, 
        "4. test chars_segment(字符分隔);"      /* 字符分隔 */, 
        "5. test chars_identify(字符鉴别);"     /* 字符鉴别 */,  
        "6. test chars_recognise(字符识别);"        /* 字符识别(包含字符分隔与字符鉴别) */,
        "7. test plate_recognize(车牌识别);"        /* 车牌识别 */, 
        "8. test all(测试全部);"        /* 以上全部 */,
        "9. 返回;"        /* 退出 */,
    };

const int testOptionCount = 9;

int testMain()
{
    bool isExit = false;
    while (isExit != true)
    {
        stringstream selectOption(stringstream::in | stringstream::out);
        selectOption << "EasyPR Test:"<< endl;
        for(int i = 0; i < testOptionCount; i++)
        {
            selectOption << testOption[i] << endl;
        }

        cout << ""<< endl;
        cout << selectOption.str();
        cout << ""<< endl;
        cout << "请选择一项操作:";

        int select = -1;
        bool isRepeat = true;
        while (isRepeat)
        {
            cin >> select;
            isRepeat = false;
            switch (select)
            {
            case 1:
                assert (test_plate_locate() == 0);
                break;
            case 2:
                assert (test_plate_judge() == 0);
                break;
            case 3:
                assert (test_plate_detect() == 0);
                break;
            case 4:
                assert (test_chars_segment() == 0);
                break;
            case 5:
                assert (test_chars_identify() == 0);
                break;
            case 6:
                assert (test_chars_recognise() == 0);
                break;
            case 7:
                assert (test_plate_recognize() == 0);
                break;
            case 8:
                assert (test_plate_locate() == 0);
                assert (test_plate_judge() == 0);
                assert (test_plate_detect() == 0);

                assert (test_chars_segment() == 0);
                assert (test_chars_identify() == 0);
                assert (test_chars_recognise() == 0);

                assert (test_plate_recognize() == 0);
                break;
            case 9:
                isExit = true;
                break;
            default:
                cout << "输入错误,请重新输入:";
                isRepeat = true;
                break;
            }
        }
    }

    return 0;
}


int test_plate_locate()
{
    cout << "test_plate_locate" << endl;

    Mat src = imread("image/plate_locate.jpg");

    vector<Mat> resultVec;
    CPlateLocate plate;
    plate.setDebug(1);
    plate.setLifemode(true);

    int result = plate.plateLocate(src, resultVec);
    if (result == 0)
    {
        int num = resultVec.size();
        for (int j = 0; j < num; j++)
        {
            Mat resultMat = resultVec[j];
            imshow("plate_locate", resultMat);
            waitKey(0);
        }
    }

    return result;
}

int test_plate_judge()
{
    cout << "test_plate_judge" << endl;

    Mat src = imread("image/plate_judge.jpg");

    //可能是车牌的图块集合
    vector<Mat> matVec;

    //经过SVM判断后得到的图块集合
    vector<Mat> resultVec;

    CPlateLocate lo;
    lo.setDebug(1);
    lo.setLifemode(true);

    int resultLo = lo.plateLocate(src, matVec);

    if (0 != resultLo)
        return -1;

    cout << "plate_locate_img" << endl;
    if (resultLo == 0)
    {
        int num = matVec.size();
        for (int j = 0; j < num; j++)
        {
            Mat resultMat = matVec[j];
            imshow("plate_judge", resultMat);
            waitKey(0);
        }
    }

    CPlateJudge ju;
    int resultJu = ju.plateJudge(matVec, resultVec);

    if (0 != resultJu)
        return -1;

    cout << "plate_judge_img" << endl;
    if (resultJu == 0)
    {
        int num = resultVec.size();
        for (int j = 0; j < num; j++)
        {
            Mat resultMat = resultVec[j];
            imshow("plate_judge", resultMat);
            waitKey(0);
        }
    }

    return resultJu;
}

int test_chars_segment()
{
    cout << "test_chars_segment" << endl;

    Mat src = imread("image/chars_segment.jpg");

    vector<Mat> resultVec;
    CCharsSegment plate;

    int result = plate.charsSegment(src, resultVec);
    if (result == 0)
    {
        int num = resultVec.size();
        for (int j = 0; j < num; j++)
        {
            Mat resultMat = resultVec[j];
            imshow("chars_segment", resultMat);
            waitKey(0);
        }
    }

    return result;
}

int test_chars_identify()
{
    cout << "test_chars_identify" << endl;

    Mat src = imread("image/chars_identify.jpg");

    vector<Mat> resultVec;
    CCharsSegment cs;
    CCharsIdentify ci;

    string plateIdentify = "";

    int result = cs.charsSegment(src, resultVec);
    if (result == 0)
    {
        int num = resultVec.size();
        for (int j = 0; j < num; j++)
        {
            Mat resultMat = resultVec[j];
            bool isChinses = false;

            //默认首个字符块是中文字符
            if (j == 0)
                isChinses = true;

            string charcater = ci.charsIdentify(resultMat, isChinses);
            plateIdentify = plateIdentify + charcater;
        }
    }

    const string plateLicense = "苏E771H6";

    cout << "plateLicense: " << plateLicense << endl;
    cout << "plateIdentify: " << plateIdentify << endl;

    if (plateLicense != plateIdentify)
    {
        cout << "Identify Not Correct!" << endl;
        return -1;
    }
    cout << "Identify Correct!" << endl;

    cout << "Enter 1 for coninue:";
    int a = 0;
    cin >> a;

    return result;
}


int test_plate_detect()
{
    cout << "test_plate_detect" << endl;

    //Mat src = imread("image/plate_detect.jpg");
    Mat src = imread("image/baidu_image/test1.jpg");

    vector<Mat> resultVec;
    CPlateDetect pd;
    pd.setPDLifemode(true);

    int result = pd.plateDetect(src, resultVec);
    if (result == 0)
    {
        int num = resultVec.size();
        for (int j = 0; j < num; j++)
        {
            Mat resultMat = resultVec[j];
            imshow("plate_detect", resultMat);
            waitKey(0);
        }
    }

    return result;
}


int test_chars_recognise()
{
    cout << "test_chars_recognise" << endl;

    Mat src = imread("image/chars_recognise.jpg");

    CCharsRecognise cr;
    string charsRecognise = "";

    int result = cr.charsRecognise(src, charsRecognise);
    if (result == 0)
    {
        cout << "charsRecognise: " << charsRecognise << endl;
    }

    cout << "Enter 1 for coninue:";
    int a = 0;
    cin >> a;

    return result;
}

int test_plate_recognize()
{
    cout << "test_plate_recognize" << endl;

    //Mat src = imread("image/plate_locate.jpg");
    Mat src = imread("image/test.jpg");

    CPlateRecognize pr;
    pr.LoadANN("model/ann.xml");
    pr.LoadSVM("model/svm.xml");

    pr.setLifemode(true);
    pr.setDebug(true);

    vector<string> plateVec;

    int result = pr.plateRecognize(src, plateVec);
    if (result == 0)
    {
        int num = plateVec.size();
        for (int j = 0; j < num; j++)
        {
            cout << "plateRecognize: " << plateVec[j] << endl;          
        }
    }

    if (result != 0)
        cout << "result:" << result << endl;

    cout << "Enter 1 for coninue:";
    int a = 0;
    cin >> a;

    return result;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值