C#棋盘格标定工具实现(界面winForm,算法Opencv)

  在项目实施中,需要用到棋盘格标定,获得实际坐标,由于现场情况和棋盘格不统一,造成标定点不统一,进而造成标定文件错误,进而影响计算的情况,本文实现一种简易的棋盘格标定工具,便于该项目调试人员根据现场情况灵活标定。本文分为四个部分,基于C++,OpenCV的算法设计,基于C#,Winform的软件界面设计,C#对C++ Dll文件的调用,以及日志Lib的实现。

  首先打开Visual Studio 新建项目解决方案,命名为CalibrateTools,默认项目作为上位机软件界面面目,然后添加C++空项目CCV,作为标定算法

一、标定算法开发

  在CCV项目中添加类命名为CalibrateCV,标定算法的相关的头文件和算法文件如下。Opencv版本为3.3:

 1 #include"CommonHead.h"
 2 using namespace cv;
 3 using namespace std;
 4 class CalibrateCV
 5 {
 6 public:
 7     CalibrateCV();
 8     virtual ~CalibrateCV();
 9 protected:
10     Mat CAMERAM;//相机内参
11     Mat DISTC;//畸变信息
12     Mat WARPM;//仿射坐标转换,用于将图像坐标转换为世界坐标。
13     int XNum;//棋盘格列数
14     int YNum;//棋盘格行数
15     Size BoardSize;//棋盘格尺寸
16     Mat SRC,BACKMAT;
17     int W,H;
18 
19     Point2f P1, P2, P3,P4;//标定点机器人坐标
20 
21     int I1R, I2R, I3R,I4R;//标定点行列数
22     int I1C, I2C, I3C, I4C;
23 
24     int L1, L2, L3, L4;//标定点索引
25 public:
26     int SetBoardData(char* data);
27     int SetBoardSize(char* data);
28     int SetMatrix(int cam);
29     int SetCalibratePoint(char* data);
30     int DoCalibrate(int cam);
31     void Read_Matrix(int index_camera, Mat &CameraM, Mat &distc, Mat &WarpM);
32     int Calibration(Mat src, int index_camera, Mat &back);
33     int SetCam(char* data, int height, int width);
34     int GetBackMat(char* data);
35 };
CalibrateCV.h
 1 #pragma once
 2 #include "opencv2/opencv.hpp"
 3 #include"opencv2/highgui/highgui.hpp"
 4 #include<direct.h>
 5 #include <sstream>
 6 #include<map>
 7 #include<omp.h>
 8 #include<time.h>
 9 #include<string>
10 #include <iostream>
11 #include<fstream>
12 #include<io.h>
13 #include<stdio.h>
14 #include<stdlib.h>
15 #include<cmath>
CommonHead.h
 1 // stdafx.h : include file for standard system include files,
 2 // or project specific include files that are used frequently, but
 3 // are changed infrequently
 4 //
 5 
 6 #pragma once
 7 #define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
 8 // Windows Header Files:
 9 #include <windows.h>
10 #include <opencv2/opencv.hpp>
11 // TODO: reference additional headers your program requires here
stdafx.h
  1 #include "CalibrateCV.h"
  2 
  3 CalibrateCV::CalibrateCV() {}
  4 CalibrateCV::~CalibrateCV() {}
  5 /***************1、设置函数,设置源图像,长宽**************/
  6 int CalibrateCV::SetCam(char* data, int height, int width)
  7 {
  8     Mat temp(height, width, CV_8UC3, (void*)data);
  9     SRC = temp;
 10     return 0;
 11 }
 12 int CalibrateCV::GetBackMat(char* data)
 13 {
 14     int w = BACKMAT.cols * BACKMAT.channels();
 15     if (false)
 16     {
 17         w += 3;
 18         w = (w >> 2) << 2;
 19     }
 20     int c = BACKMAT.cols * BACKMAT.channels();
 21     for (int i = 0; i < BACKMAT.rows; i++)
 22     {
 23         memcpy(data + i * w, BACKMAT.data + i * c, c);
 24     }
 25     return 0;
 26 }
 27 int CalibrateCV::SetBoardData(char* data)
 28 {
 29     int* idata = (int*)(data);
 30     XNum = idata[0];
 31     YNum = idata[1];
 32 
 33     I1R = idata[2];
 34     I1C= idata[3];
 35     I2R = idata[4];
 36     I2C = idata[5];
 37     I3R = idata[6];
 38     I3C = idata[7];
 39     I4R = idata[8];
 40     I4C = idata[9];
 41 
 42     //点数组索引=(行-1)*36+(列-1)
 43     L1 = (I1R - 1) * XNum + (I1C - 1);
 44     L2 = (I2R - 1) * XNum + (I2C - 1);
 45     L3 = (I3R - 1) * XNum + (I3C - 1);
 46     L4 = (I4R - 1) * XNum + (I4C - 1);
 47 
 48     return 0;
 49 }
 50 int CalibrateCV::SetBoardSize(char* data)
 51 {
 52     float* idata = (float*)(data);
 53     BoardSize = Size(idata[0], idata[1]);
 54     return 0;
 55 }
 56 int CalibrateCV::SetMatrix(int cam)
 57 {
 58     CAMERAM = Mat(3, 3, CV_32FC1, Scalar::all(0));
 59     DISTC = Mat(1, 5, CV_32FC1, Scalar::all(0));
 60     WARPM = Mat(3, 3, CV_32FC1, Scalar::all(0));
 61     Read_Matrix(cam, CAMERAM, DISTC, WARPM);
 62     return 0;
 63 }
 64 int CalibrateCV::SetCalibratePoint(char* data)
 65 {
 66 
 67     float* idata = (float*)(data);
 68     P1.x = idata[0];
 69     P1.y = idata[1];
 70 
 71     P2.x = idata[2];
 72     P2.y = idata[3];
 73 
 74     P3.x = idata[4];
 75     P3.y = idata[5];
 76 
 77     P4.x = idata[6];
 78     P4.y = idata[7];
 79 
 80     
 81 
 82     return 0;
 83 }
 84 void CalibrateCV::Read_Matrix(int index_camera, Mat &CameraM, Mat &distc, Mat &WarpM)
 85 {
 86     vector<float> m1;
 87     vector<string> strs;
 88     ifstream inf;
 89     inf.open("Calibrat" + std::to_string(index_camera) + ".txt", ios_base::in);
 90     if (!inf)
 91         return;
 92     //("打开相机参数文件失败");
 93     //std::cout << "error" << endl;
 94     string str;
 95     //int times = 0;
 96     while (getline(inf, str))
 97     {
 98         size_t s = str.find("#");
 99         if (s != str.npos)
100             continue;
101         //times = 1;
102         size_t s1 = str.find("[");
103         size_t s2 = str.find(";");
104         size_t s3 = str.find("]");
105         if (s1 != str.npos)
106         {
107             if (s2 != str.npos)//有[ 并且有 ;
108             {
109                 str = str.substr(s1 + 1, s2 - 1);
110                 size_t s = str.find(",");
111                 for (; s != str.npos;)
112                 {
113                     strs.push_back(str.substr(0, s));
114                     str = str.substr(s + 1);
115                     s = str.find(",");
116                 }
117                 strs.push_back(str);
118             }
119             else
120             {
121                 if (s3 != str.npos)
122                 {
123                     str = str.substr(s1 + 1, s3 - 1);
124                     size_t s = str.find(",");
125                     for (; s != str.npos;)
126                     {
127                         strs.push_back(str.substr(0, s));
128                         str = str.substr(s + 1);
129                         s = str.find(",");
130                     }
131                     strs.push_back(str);
132                 }
133             }
134 
135         }
136         else
137         {
138             if (s2 != str.npos)//没有[ 有 ;
139             {
140                 str = str.substr(0, s2 - 1);
141                 size_t s = str.find(",");
142                 for (; s != str.npos;)
143                 {
144                     strs.push_back(str.substr(0, s));
145                     str = str.substr(s + 1);
146                     s = str.find(",");
147                 }
148                 strs.push_back(str);
149             }
150             else
151             {
152                 if (s3 != str.npos)//没有[ 有 ]
153                 {
154                     str = str.substr(0, s3);
155                     size_t s = str.find(",");
156                     for (; s != str.npos;)
157                     {
158                         strs.push_back(str.substr(0, s));
159                         str = str.substr(s + 1);
160                         s = str.find(",");
161                     }
162                     strs.push_back(str);
163                 }
164             }
165         }
166     }
167 
168     for (int i = 0; i < strs.size(); i++)
169     {
170         istringstream iss(strs[i]);
171         float t;
172         iss >> t;
173         m1.push_back(t);
174     }
175 
176     //获取相机内参
177     if (m1.size() == 0)
178         return;
179     int index = 0;
180     for (int i = 0; i < CameraM.cols; i++)
181     {
182         for (int j = 0; j < CameraM.rows; j++)
183         {
184             CameraM.at<float>(i, j) = m1[index];
185             index++;
186         }
187     }
188 
189     //获取相机畸变参数
190     for (int i = 0; i < distc.cols; i++)
191     {
192         for (int j = 0; j < distc.rows; j++)
193         {
194             distc.at<float>(j, i) = m1[index];
195             index++;
196         }
197     }
198     //获取透视变换
199     for (int i = 0; i < WarpM.cols; i++)
200     {
201         for (int j = 0; j < WarpM.rows; j++)
202         {
203             WarpM.at<float>(i, j) = m1[index];
204             index++;
205         }
206     }
207     inf.close();
208 }
209 int CalibrateCV::Calibration(Mat src, int index_camera, Mat &back)
210 {
211     Mat color_src, gray;
212 
213     if (src.channels() > 1)
214     {
215         color_src = src.clone();
216         cvtColor(src, gray, CV_RGB2GRAY);
217     }
218     else
219     {
220         gray = src.clone();
221         cvtColor(src, color_src, CV_GRAY2RGB);
222     }
223     vector<Point2f> corners;//保存检测到的角点坐标信息,像素坐标
224     Size board_size = Size(XNum, YNum);
225     bool patter = findChessboardCorners(gray, board_size, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);//CV_CALIB_CB_ADAPTIVE_THRESH
226     if (!patter)
227     {
228         back = color_src.clone();
229         return -1;
230     }
231     //对像素坐标进行亚精度操作,提高精度
232     cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
233     // 把找到的角点描绘出来
234     drawChessboardCorners(color_src, board_size, corners, patter);
235 
236     //单个棋盘格大小 mm
237     Size square_size = Size(5, 5);
238     //保存各角点的物理坐标     世界坐标系
239     //std::vector<cv::Point3f> object_points;
240     //创建 3*3 全零的 float 矩阵,用来保存相机内参
241     Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
242     //创建 1行5列的全零 float 矩阵,用来保存畸变参数
243     Mat distcoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));
244     // 创建图像旋转向量
245     vector<Mat> tvecsMat;
246     //创建图像平移向量
247     vector<Mat> rvecsMat;
248     //保存各角点的物理坐标     世界坐标系
249     vector<Point3f> realPoints;
250 
251     //按照从左到右,从上到下的顺序排列角点坐标
252     for (int i = 0; i < board_size.height; i++)
253     {
254         for (int j = 0; j < board_size.width; j++)
255         {
256             Point3f tempPoint;
257             tempPoint.x = i * square_size.width;
258             tempPoint.y = j * square_size.height;
259             tempPoint.z = 0;
260             realPoints.push_back(tempPoint);
261         }
262     }
263 
264     vector<vector<Point2f>> image_points;
265     image_points.push_back(corners);
266     vector<vector<Point3f>> object_points;
267     object_points.push_back(realPoints);
268 
269     double eps = calibrateCamera(object_points, image_points, src.size(), cameraMatrix, distcoeffs, rvecsMat,
270         tvecsMat, CV_CALIB_FIX_K3);
271     Mat dst1;
272     undistort(src, dst1, cameraMatrix, distcoeffs);
273     vector<Point2f> corner;
274     bool patters = findChessboardCorners(dst1, board_size, corner, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);
275     if (!patters)
276     {
277         cvtColor(dst1, dst1, COLOR_GRAY2BGR);
278         back = dst1.clone();
279         return -2;
280     }
281 
282     //点数组索引=(行-1)*36+(列-1)
283     vector<cv::Point2f> image_point;
284 
285     image_point.push_back(corner[L1]);
286     image_point.push_back(corner[L2]);
287     image_point.push_back(corner[L3]);
288     image_point.push_back(corner[L4]);
289 
290     vector<Point2f>CalibratePoints;
291     CalibratePoints.push_back(P1);
292     CalibratePoints.push_back(P2);
293     CalibratePoints.push_back(P3);
294     CalibratePoints.push_back(P4);
295     Mat M = cv::getPerspectiveTransform(image_point, CalibratePoints);//透视变换矩阵
296     ofstream fout;
297     fout.open("calibrat" + std::to_string(index_camera) + ".txt");
298     fout << "#cameraMatrix:\n" << cameraMatrix << endl;
299     fout << "#distcoeffs:\n" << distcoeffs << endl;
300     fout << "#M\n" << M << endl;
301     fout << endl;
302     fout.close();
303     back = color_src.clone();
304     return 0;
305 }
306 int CalibrateCV::DoCalibrate(int cam)
307 {
308     int rtn = Calibration(SRC, cam, BACKMAT);
309     return rtn;
310 }
CalibrateCV.cpp

  生成dll文件,添加类CCV

 1 #pragma once
 2 #ifdef CCV_EXPORTS
 3 #define CCV_API __declspec(dllexport)
 4 #else
 5 #define CCV_API __declspec(dllimport)
 6 #endif
 7 EXTERN_C CCV_API int SetCam(char* data, int height, int width);
 8 EXTERN_C CCV_API int SetBoardData(char* data);
 9 EXTERN_C CCV_API int SetCalibratePoint(char* data);
10 EXTERN_C CCV_API int GetImage(char* data);
11 EXTERN_C CCV_API int DoCalibrate(int cam);
CCV.h
 1 #include "stdafx.h"
 2 #include "CCV.h"
 3 #include"CalibrateCV.h"
 4 
 5 //摆串
 6 CalibrateCV CalMV;
 7 CCV_API int SetCam(char* data, int height, int width)
 8 {
 9     return CalMV.SetCam(data, height, width);
10 }
11 CCV_API int SetBoardData(char* data)
12 {
13     return CalMV.SetBoardData(data);
14 }
15 CCV_API int GetImage(char* data)
16 {
17     return CalMV.GetBackMat(data);
18 }
19 CCV_API int DoCalibrate(int cam)
20 {
21     return CalMV.DoCalibrate(cam);
22 }
23 CCV_API int SetCalibratePoint(char* data)
24 {
25     return CalMV.SetCalibratePoint(data);
26 }
CCV.cpp

  添加导出cpp文件

 1 #include "stdafx.h"
 2 BOOL APIENTRY DllMain(HMODULE hModule,
 3     DWORD  ul_reason_for_call,
 4     LPVOID lpReserved
 5 )
 6 {
 7     switch (ul_reason_for_call)
 8     {
 9     case DLL_PROCESS_ATTACH:
10     case DLL_THREAD_ATTACH:
11     case DLL_THREAD_DETACH:
12     case DLL_PROCESS_DETACH:
13         break;
14     }
15     return TRUE;
16 }
dllmain

二、CCV项目配置,修改配置类型为动态库。然后测试生成

  

 三、软件界面设计

  软件界面具体如下:

  

  四、C#调用C++算法文件设计

 1 public class Detection
 2     {
 3         #region sys dll
 4         [DllImport("kernel32.dll")]
 5         static private extern IntPtr LoadLibrary(string lpFileName);
 6         [DllImport("kernel32.dll")]
 7         static private extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
 8         [DllImport("kernel32.dll")]
 9         static private extern int GetLastError();
10         [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)]
11         static private extern bool FreeLibrary(IntPtr hModule);
12         static private Delegate GetFunctionAddress(IntPtr dllModule, string functionName, Type t)
13         {
14             IntPtr address = GetProcAddress(dllModule, functionName);
15             if (address == IntPtr.Zero)
16                 return null;
17             else
18                 return Marshal.GetDelegateForFunctionPointer(address, t);
19         }
20         #endregion sys dll
21 
22         #region 算法导出函数
23         public static IntPtr hSdkDll;
24 
25         #region 标定
26 
27         [DllImport("CCV.dll", EntryPoint = "SetCalibratePoint", CallingConvention = CallingConvention.StdCall)]
28         public static extern int SetCalibratePoint(float[] points, int cam);
29         [DllImport("CCV.dll", EntryPoint = "DoCalibrate", CallingConvention = CallingConvention.StdCall)]
30         public static extern int DoCalibrate(int cam);
31         [DllImport("CCV.dll", EntryPoint = "SetCam", CallingConvention = CallingConvention.StdCall)]
32         public static extern int SetCam(byte[] srcValues, int h, int w,int cam);
33         [DllImport("CCV.dll", EntryPoint = "GetImage", CallingConvention = CallingConvention.StdCall)]
34         public static extern int GetImage(byte[] dstValues,int cam);
35         [DllImport("CCV.dll", EntryPoint = "SetBoardData", CallingConvention = CallingConvention.StdCall)]
36         public static extern int SetBoardData(int[] values);
37 
38         
39         #endregion
40         #endregion
41 
42         #region 初始化与释放
43         public static bool Initial()
44         {
45             try
46             {
47                 hSdkDll = LoadLibrary("CCV.dll");
48                 int a = GetLastError();
49                 if (hSdkDll == IntPtr.Zero)
50                 {
51                     MyLogHelper.Instance.Error("算法加载异常:" + a.ToString());
52                     return false;
53                 }
54                 else
55                 {
56                     return true;
57                 }
58             }
59             catch (Exception ex)
60             {
61                 MyLogHelper.Instance.Error("算法初始化失败:"+ex.ToString());
62                 return false;
63             }
64         }
65         public static void Uninitial()
66         {
67             if (hSdkDll != IntPtr.Zero)
68                 FreeLibrary(hSdkDll);
69             hSdkDll = IntPtr.Zero;
70         }
71         #endregion
72     }
Detection.cs

 五、解决方案,项目目录

  

   整个项目代码:链接: https://pan.baidu.com/s/1x8SAg92Rpfht0kvVQKorqQ 提取码: rwt2 

   

posted @ 2020-08-25 14:35  WarrenHome  阅读(1942)  评论(3编辑  收藏  举报