标定板生成
void gencaliboard()
{
//单位转换
int dot_per_inch = 96; //我的电脑是96DPI(dot per inch)
double cm_to_inch = 0.3937; //1cm=0.3937inch
double inch_to_cm = 2.54; //1inch = 2.54cm
double inch_per_dot = 1.0 / 96.0;
//自定义标定板
double blockSize_cm = 2.5; //方格尺寸:边长1.3cm的正方形
int blockNumX = 19; //
int blockNumY = 13; //
int blockSize = (int)(blockSize_cm / inch_to_cm * dot_per_inch);
cout << blockSize << endl;
int imageSizeX = blockSize * blockNumX;
int imageSizeY = blockSize * blockNumY;
cout << imageSizeX << endl;
cout << imageSizeY << endl;
Mat chessBoard(imageSizeY, imageSizeX, CV_8UC3, Scalar::all(0));
unsigned char color = 0;
for (int i = 0; i < imageSizeX; i = i + blockSize) {
//color = ~color;
for (int j = 0; j < imageSizeY; j = j + blockSize) {
Mat ROI = chessBoard(Rect(i, j, blockSize, blockSize));
ROI.setTo(Scalar::all(color));
color = ~color;
}
}
imshow("Chess board", chessBoard);
imwrite("D:\\chessBoard.jpg", chessBoard);
cvWaitKey(3000);
}
获取某一文件夹下的所有文件名
只有32位可以编译
来自网络 https://www.cnblogs.com/wqpkita/p/6849283.html
void getFiles(string path, vector<string>& files)
{
//文件句柄
long hFile = 0;
//文件信息,声明一个存储文件信息的结构体
struct _finddata_t fileinfo;
string p;//字符串,存放路径
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)//若查找成功,则进入
{
do
{
//如果是目录,迭代之(即文件夹内还有文件夹)
if ((fileinfo.attrib & _A_SUBDIR))
{
//文件名不等于"."&&文件名不等于".."
//.表示当前目录
//..表示当前目录的父目录
//判断时,两者都要忽略,不然就无限递归跳不出去了!
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
}
//如果不是,加入列表 ,这里进行了判断,只有是.jpg的文件才加入列表
else
{
string a = ".jpg";
string b = ".jpg.bmp";
string::size_type idx1, idx2;
char* temp = fileinfo.name;
string temp1 = temp;
idx1 = temp1.find(a);
idx2 = temp1.find(b);
if (idx1 != string::npos && idx2 == string::npos)
files.push_back(p.assign(path).append("\\").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
//_findclose函数结束查找
_findclose(hFile);
}
}
opencv按照想要的缩放比例显示Mat
调用后需要使用waitkey。
void imageshow(Mat draw, float scale, string str)
{
Size dsize = Size(draw.cols*scale, draw.rows*scale);
Mat imgshow = Mat(dsize, CV_32S);
resize(draw, imgshow, dsize);
namedWindow(str);
imshow(str, imgshow);
}
opencv读取摄像头并逐帧写入视频文件
bool usecamera()
{
VideoCapture cap(1);
VideoWriter writer;
string outFlie = "test3.avi";
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 960);
cap.set(CV_CAP_PROP_FRAME_WIDTH, 2560);
int w = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_WIDTH));
int h = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_HEIGHT));
Size videoSize(w, h);
int rate = 30;
writer.open(outFlie, CV_FOURCC('M', 'J', 'P', 'G'), rate, videoSize);
obtain the video parameters
//int rate = cap.get(CV_CAP_PROP_FPS); //the rate of video frame
//int frameHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT); // the height of video frame
//int frameWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH); // the width of video frame
//VideoWriter writer("VideoTest.avi", CV_FOURCC('M', 'J', 'P', 'G'), 60, videoSize);
if (!cap.isOpened())
{
return -1;
}
Mat frame;
while (1)
{
cap.read(frame);
cout << frame.type() << endl;
writer.write(frame);
if (frame.empty()) break;
imshow("当前视频", frame);
if (waitKey(10) == 27)
break;
}
return 0;
}
三点确定一个圆
struct CircleData
{
Point2f center;
int radius;
};
CircleData findCircle1(Point2f pt1, Point2f pt2, Point2f pt3)
{
//定义两个点,分别表示两个中点
Point2f midpt1, midpt2;
//求出点1和点2的中点
midpt1.x = (pt2.x + pt1.x) / 2;
midpt1.y = (pt2.y + pt1.y) / 2;
//求出点3和点1的中点
midpt2.x = (pt3.x + pt1.x) / 2;
midpt2.y = (pt3.y + pt1.y) / 2;
//求出分别与直线pt1pt2,pt1pt3垂直的直线的斜率
float k1 = -(pt2.x - pt1.x) / (pt2.y - pt1.y);
float k2 = -(pt3.x - pt1.x) / (pt3.y - pt1.y);
//然后求出过中点midpt1,斜率为k1的直线方程(既pt1pt2的中垂线):y - midPt1.y = k1( x - midPt1.x)
//以及过中点midpt2,斜率为k2的直线方程(既pt1pt3的中垂线):y - midPt2.y = k2( x - midPt2.x)
//定义一个圆的数据的结构体对象CD
CircleData CD;
//连立两条中垂线方程求解交点得到:
CD.center.x = (midpt2.y - midpt1.y - k2 * midpt2.x + k1 * midpt1.x) / (k1 - k2);
CD.center.y = midpt1.y + k1 * (midpt2.y - midpt1.y - k2 * midpt2.x + k2 * midpt1.x) / (k1 - k2);
//用圆心和其中一个点求距离得到半径:
CD.radius = sqrtf((CD.center.x - pt1.x)*(CD.center.x - pt1.x) + (CD.center.y - pt1.y)*(CD.center.y - pt1.y));
return CD;
}
轮廓平滑操作
来自网络 https://blog.csdn.net/qq_16949707/article/details/70340090
int filterRadius = 20;
int filterSize = 2 * filterRadius + 1;
double sigma = 10;
vector<vector<Point>> smooth(vector<vector<Point>> contours)
{
vector<vector<Point> > smoothContours;
for (size_t j = 0; j < contours.size(); j++)
{
// extract x and y coordinates of points. we'll consider these as 1-D signals
// add circular padding to 1-D signals
size_t len = contours[j].size() + 2 * filterRadius;
size_t idx = (contours[j].size() - filterRadius);
vector<float> x, y;
for (size_t i = 0; i < len; i++)
{
x.push_back(contours[j][(idx + i) % contours[j].size()].x);
y.push_back(contours[j][(idx + i) % contours[j].size()].y);
}
// filter 1-D signals
vector<float> xFilt, yFilt;
GaussianBlur(x, xFilt, Size(filterSize, filterSize), sigma, sigma);
GaussianBlur(y, yFilt, Size(filterSize, filterSize), sigma, sigma);
// build smoothed contour
vector<Point> smooth;
for (size_t i = filterRadius; i < contours[j].size() + filterRadius; i++)
{
smooth.push_back(Point(xFilt[i], yFilt[i]));
}
smoothContours.push_back(smooth);
}
return smoothContours;
}
相机标定函数
#define BOARD_SCALE 9.73 /* 实际测量得到的标定板上每个棋盘格的大小,单位是mm*/
#define BOARD_HEIGHT 12
#define BOARD_WIDTH 18
#include <time.h>
void calibration()
{
clock_t start = clock();
vector<string> files;
vector<string> names;
files.clear();
string filePath = "pic/calibration/"; //calibration
getFiles(filePath, files);
cout << "找到的文件有" << endl;
for (int i = 0; i < files.size(); i++)
{
cout << files[i] << endl;
}
//读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
cout << "开始提取角点………………" << endl;
int image_count = 0; /* 图像数量 */
Size image_size; /* 图像的尺寸 */
Size board_size = Size(BOARD_HEIGHT, BOARD_WIDTH); /* 标定板上每行、列的角点数 */
vector<Point2f> image_points_buf; /* 缓存每幅图像上检测到的角点 */
vector<vector<Point2f>> image_points_seq; /* 保存检测到的所有角点 */
for (int i = 0; i < files.size(); i++)
{
cout << files[i] << endl;
Mat imageInput = imread(files[i]);
//cvtColor(imageInput, imageInput, CV_BGR2GRAY);
image_size.width = imageInput.cols;
image_size.height = imageInput.rows;
cout << "image_size.width = " << image_size.width << endl;
cout << "image_size.height = " << image_size.height << endl;
/* 提取角点 */
if (0 == findChessboardCorners(imageInput, board_size, image_points_buf))
{
cout << "can not find chessboard corners!\n"; //找不到角点
cout << "\n";
continue;
}
else
{
//找到一幅有效的图片
image_count++;
//Mat view_gray;
//cvtColor(imageInput, view_gray, CV_RGB2GRAY);
///* 亚像素精确化 */
find4QuadCornerSubpix(view_gray,image_points_buf,Size(5,5)); //对粗提取的角点进行精确化
//cornerSubPix(view_gray, image_points_buf,
// Size(5, 5),
// Size(-1, -1),
// TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS,
// 30, // max number of iterations
// 0.1)); // min accuracy
image_points_seq.push_back(image_points_buf); //保存亚像素角点
/* 在图像上显示角点位置 */
drawChessboardCorners(imageInput, board_size, image_points_buf, true); //用于在图片中标记角点
//写入文件
string filePath = files[i];
filePath += ".bmp";
imwrite(filePath, imageInput);
cout << "\n";
}
}
int total = image_points_seq.size();
cout << "共使用了" << total << "幅图片" << endl;
cout << "角点提取完成!\n";
cout << "开始标定………………\n";
/*棋盘三维信息*/
vector<vector<Point3f>> object_points; /* 保存标定板上角点的三维坐标 */
/*内外参数*/
Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 摄像机内参数矩阵 */
vector<int> point_counts; // 每幅图像中角点的数量
Mat distCoeffs = Mat(1, 8, CV_32FC1, Scalar::all(0)); /* 摄像机的5个畸变系数:k1,k2,p1,p2,k3 */
vector<Mat> tvecsMat; /* 每幅图像的旋转向量 */
vector<Mat> rvecsMat; /* 每幅图像的平移向量 */
/* 初始化标定板上角点的三维坐标 */
int i, j, t;
for (t = 0; t < image_count; t++)
{
vector<Point3f> tempPointSet;
for (i = 0; i < board_size.height; i++)
{
for (j = 0; j < board_size.width; j++)
{
Point3f realPoint;
/* 假设标定板放在世界坐标系中z=0的平面上 */
realPoint.x = j * BOARD_SCALE;
realPoint.y = i * BOARD_SCALE;
realPoint.z = 0;
tempPointSet.push_back(realPoint);
}
}
object_points.push_back(tempPointSet);
}
/* 初始化每幅图像中的角点数量,假定每幅图像中都可以看到完整的标定板 */
for (i = 0; i < image_count; i++)
{
point_counts.push_back(board_size.width*board_size.height);
}
/* 开始标定 */
calibrateCamera(object_points, image_points_seq, image_size, cameraMatrix, distCoeffs, rvecsMat, tvecsMat, CV_CALIB_RATIONAL_MODEL);
cout << "标定完成!\n";
clock_t ends = clock();
cout << "Running Time : " << (double)(ends - start) / CLOCKS_PER_SEC << endl;
//对标定结果进行评价
ofstream fout("caliberation_result.txt"); /* 保存标定结果的文件 */
double total_err = 0.0; /* 所有图像的平均误差的总和 */
double err = 0.0; /* 每幅图像的平均误差 */
vector<Point2f> image_points2; /* 保存重新计算得到的投影点 */
cout << "\t每幅图像的标定误差:\n";
fout << "每幅图像的标定误差:\n";
for (i = 0; i < image_count; i++)
{
vector<Point3f> tempPointSet = object_points[i];
/* 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 */
projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoeffs, image_points2);
/* 计算新的投影点和旧的投影点之间的误差*/
vector<Point2f> tempImagePoint = image_points_seq[i];
Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
for (int j = 0; j < tempImagePoint.size(); j++)
{
image_points2Mat.at<Vec2f>(0, j) = Vec2f(image_points2[j].x, image_points2[j].y);
tempImagePointMat.at<Vec2f>(0, j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
}
err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
total_err += err /= point_counts[i];
cout << "第" << files[i] << "幅图像的平均误差:" << err << "像素" << endl;
fout << "第" << files[i] << "幅图像的平均误差:" << err << "像素" << endl;
}
cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
//保存定标结果
cout << "开始保存定标结果………………" << endl;
Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
fout << "相机内参数矩阵:" << endl;
fout << cameraMatrix << endl << endl;
fout << "畸变系数:\n";
fout << distCoeffs << endl << endl << endl;
for (int i = 0; i < image_count; i++)
{
fout << "第" << files[i] << "幅图像的旋转向量:" << endl;
fout << tvecsMat[i] << endl;
/* 将旋转向量转换为相对应的旋转矩阵 */
Rodrigues(tvecsMat[i], rotation_matrix);
fout << "第" << files[i] << "幅图像的旋转矩阵:" << endl;
fout << rotation_matrix << endl;
fout << "第" << files[i] << "幅图像的平移向量:" << endl;
fout << rvecsMat[i] << endl << endl;
}
cout << "完成保存" << endl;
fout << endl;
//畸变矫正
for (int i = 0; i < image_count; i++)
{
cout << files[i] << endl;
Mat src = imread(files[i]);
Mat dst = src.clone();
undistort(src, dst, cameraMatrix, distCoeffs);
string filePath = files[i];
filePath += "undis.bmp";
imwrite(filePath, dst);
cout << "\n";
}
}