您的位置:首页 > 运维架构

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

2017-12-25 15:44 417 查看
//-----------------------------------(续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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: