29 #include <opencv2/core/version.hpp>
31 #if CV_MAJOR_VERSION >= 3
32 # include <opencv2/imgcodecs.hpp>
34 # include <opencv2/highgui/highgui.hpp>
38 #if CV_VERSION_MAJOR * 100 + CV_VERSION_MINOR >= 410
39 # error "OpenCV >= 4.10 isn't supported"
42 #include <opencv2/calib3d/calib3d.hpp>
43 #include <opencv2/imgproc/imgproc.hpp>
56 #define CHECK_STATUS(STMT) \
59 VPIStatus status = (STMT); \
60 if (status != VPI_SUCCESS) \
62 char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
63 vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
64 std::ostringstream ss; \
65 ss << vpiStatusGetName(status) << ": " << buffer; \
66 throw std::runtime_error(ss.str()); \
70 static void PrintUsage(
const char *progname, std::ostream &out)
72 out <<
"Usage: " << progname <<
" <-c W,H> [-s win] <image1> [image2] [image3] ...\n"
74 <<
" W,H\tcheckerboard with WxH squares\n"
75 <<
" win\tsearch window width around checkerboard vertex used\n"
76 <<
"\tin refinement, default is 0 (disable refinement)\n"
77 <<
" imageN\tinput images taken with a fisheye lens camera" << std::endl;
80 static char *my_basename(
char *path)
83 char *name = strrchr(path,
'\\');
85 char *name = strrchr(path,
'/');
101 std::vector<const char *> images;
104 static Params ParseParameters(
int argc,
char *argv[])
110 for (
int i = 1; i < argc; ++i)
112 if (argv[i][0] ==
'-')
114 if (strlen(argv[i] + 1) == 1)
119 PrintUsage(my_basename(argv[0]), std::cout);
125 throw std::invalid_argument(
"Option -c must be followed by checkerboard width and height");
128 if (sscanf(argv[++i],
"%d,%d", &cbSize.width, &cbSize.height) != 2)
130 throw std::invalid_argument(
"Error parsing checkerboard information");
135 params.vtxCount.width = cbSize.width - 1;
136 params.vtxCount.height = cbSize.height - 1;
142 throw std::invalid_argument(
"Option -s must be followed by search window size");
144 if (sscanf(argv[++i],
"%d", ¶ms.searchWinSize) != 1)
146 throw std::invalid_argument(
"Error parsing search window size");
148 if (params.searchWinSize < 0)
150 throw std::invalid_argument(
"Search window size must be >= 0");
155 throw std::invalid_argument(std::string(
"Option -") + (argv[i] + 1) +
" not recognized");
160 throw std::invalid_argument(std::string(
"Option -") + (argv[i] + 1) +
" not recognized");
165 params.images.push_back(argv[i]);
169 if (params.images.empty())
171 throw std::invalid_argument(
"At least one image must be defined");
174 if (cbSize.width <= 3 || cbSize.height <= 3)
176 throw std::invalid_argument(
"Checkerboard size must have at least 3x3 squares");
179 if (params.searchWinSize == 1)
181 throw std::invalid_argument(
"Search window size must be 0 (default) or >= 2");
187 int main(
int argc,
char *argv[])
196 VPIImage tmpIn = NULL, tmpOut = NULL;
204 Params params = ParseParameters(argc, argv);
205 if (params.images.empty())
211 std::vector<std::vector<cv::Point2f>> corners2D;
214 cv::Size imgSize = {};
216 for (
unsigned i = 0; i < params.images.size(); ++i)
219 cv::Mat img = cv::imread(params.images[i]);
222 throw std::runtime_error(
"Can't read " + std::string(params.images[i]));
225 if (imgSize == cv::Size{})
227 imgSize = img.size();
229 else if (imgSize != img.size())
231 throw std::runtime_error(
"All images must have same size");
237 std::vector<cv::Point2f> cbVertices;
239 if (findChessboardCorners(img, params.vtxCount, cbVertices,
240 cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE))
243 if (params.searchWinSize >= 2)
246 cvtColor(img, gray, cv::COLOR_BGR2GRAY);
248 cornerSubPix(gray, cbVertices, cv::Size(params.searchWinSize / 2, params.searchWinSize / 2),
250 cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 30, 0.0001));
254 corners2D.push_back(std::move(cbVertices));
258 std::cerr <<
"Warning: checkerboard pattern not found in image " << params.images[i] << std::endl;
265 std::vector<cv::Point3f> initialCheckerboard3DVertices;
266 for (
int i = 0; i < params.vtxCount.height; ++i)
268 for (
int j = 0; j < params.vtxCount.width; ++j)
272 initialCheckerboard3DVertices.emplace_back(
static_cast<float>(j),
static_cast<float>(i), 0.0f);
277 std::vector<std::vector<cv::Point3f>> corners3D(corners2D.size(), initialCheckerboard3DVertices);
280 using Mat3 = cv::Matx<double, 3, 3>;
281 Mat3 camMatrix = Mat3::eye();
284 std::vector<double> coeffs(4);
288 int flags = cv::fisheye::CALIB_FIX_SKEW;
292 cv::Mat rvecs, tvecs;
293 double rms = cv::fisheye::calibrate(corners3D, corners2D, imgSize, camMatrix, coeffs, rvecs, tvecs, flags);
294 printf(
"rms 误差: %lf\n", rms);
298 printf(
"鱼眼系数: %lf %lf %lf %lf\n", coeffs[0], coeffs[1], coeffs[2], coeffs[3]);
301 printf(
"[%lf %lf %lf; %lf %lf %lf; %lf %lf %lf]\n", camMatrix(0, 0), camMatrix(0, 1), camMatrix(0, 2),
302 camMatrix(1, 0), camMatrix(1, 1), camMatrix(1, 2), camMatrix(2, 0), camMatrix(2, 1), camMatrix(2, 2));
319 distModel.
k1 = coeffs[0];
320 distModel.
k2 = coeffs[1];
321 distModel.
k3 = coeffs[2];
322 distModel.
k4 = coeffs[3];
326 for (
int i = 0; i < 2; ++i)
328 for (
int j = 0; j < 3; ++j)
330 K[i][j] = camMatrix(i, j);
336 X[0][0] = X[1][1] = X[2][2] = 1;
357 for (
unsigned i = 0; i < params.images.size(); ++i)
360 cvImage = cv::imread(params.images[i]);
361 assert(!cvImage.empty());
390 snprintf(buf,
sizeof(buf),
"undistort_%03d.jpg", i);
391 imwrite(buf, cvImage);
394 catch (std::exception &e)
396 std::cerr <<
"Error: " << e.what() << std::endl;
397 PrintUsage(my_basename(argv[0]), std::cerr);
用于处理 OpenCV 与 VPI 的互操作性的函数。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
struct VPIImageImpl * VPIImage
图像的句柄。
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用指定的标志创建空的图像实例。
VPIFisheyeMapping mapping
像素角度与到图像中心的像素距离之间的映射。
VPIStatus vpiWarpMapGenerateFromFisheyeLensDistortionModel(const VPICameraIntrinsic Kin, const VPICameraExtrinsic X, const VPICameraIntrinsic Kout, const VPIFisheyeLensDistortionModel *distModel, VPIWarpMap *warpMap)
生成校正由鱼眼镜头引起的图像失真的映射。
float VPICameraExtrinsic[3][4]
相机外参矩阵。
float VPICameraIntrinsic[2][3]
相机内参矩阵。
@ VPI_FISHEYE_EQUIDISTANT
指定等距鱼眼映射。
VPIStatus vpiImageCreateWrapperOpenCVMat(const cv::Mat &mat, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用给定的图像格式将 cv::Mat 包装在 VPIImage 中。
VPIStatus vpiImageSetWrappedOpenCVMat(VPIImage img, const cv::Mat &mat)
重新定义现有 VPIImage 包装器的包装 cv::Mat。
struct VPIPayloadImpl * VPIPayload
算法有效负载的句柄。
void vpiPayloadDestroy(VPIPayload payload)
释放有效负载对象和所有关联的资源。
VPIStatus vpiSubmitRemap(VPIStream stream, uint64_t backend, VPIPayload payload, VPIImage input, VPIImage output, VPIInterpolationType interp, VPIBorderExtension border, uint64_t flags)
将 Remap 操作提交到流。
VPIStatus vpiCreateRemap(uint64_t backends, const VPIWarpMap *warpMap, VPIPayload *payload)
为 Remap 算法创建有效负载。
struct VPIStreamImpl * VPIStream
流的句柄。
VPIStatus vpiStreamSync(VPIStream stream)
阻止调用线程,直到此流队列中的所有提交命令完成(队列为空)...
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
@ VPI_BACKEND_CUDA
CUDA 后端。
@ VPI_BORDER_ZERO
图像外部的所有像素都被视为零。
@ VPI_INTERP_CATMULL_ROM
Catmull-Rom 立方插值。
int8_t numHorizRegions
水平区域数。
VPIWarpGrid grid
扭曲网格控制点结构定义。
int16_t horizInterval[VPI_WARPGRID_MAX_HORIZ_REGIONS_COUNT]
给定区域内控制点之间的水平间距。
int8_t numVertRegions
垂直区域数。
int16_t vertInterval[VPI_WARPGRID_MAX_VERT_REGIONS_COUNT]
给定区域内控制点之间的垂直间距。
int16_t regionWidth[VPI_WARPGRID_MAX_HORIZ_REGIONS_COUNT]
每个区域的宽度。
int16_t regionHeight[VPI_WARPGRID_MAX_VERT_REGIONS_COUNT]
每个区域的高度。
void vpiWarpMapFreeData(VPIWarpMap *warpMap)
释放 vpiWarpMapAllocData 分配的扭曲映射控制点。
VPIStatus vpiWarpMapAllocData(VPIWarpMap *warpMap)
为给定的扭曲网格分配扭曲映射的控制点数组。