|
@@ -0,0 +1,292 @@
|
|
1
|
+#ifndef _EXPORTING
|
|
2
|
+#define _EXPORTING
|
|
3
|
+#endif
|
|
4
|
+
|
|
5
|
+#include "WaferRebuild.h"
|
|
6
|
+#include "ArithPmd.h"
|
|
7
|
+
|
|
8
|
+WaferRebuild::WaferRebuild()
|
|
9
|
+{
|
|
10
|
+ arith_pmd = new ArithPmd();
|
|
11
|
+}
|
|
12
|
+
|
|
13
|
+WaferRebuild::~WaferRebuild()
|
|
14
|
+{
|
|
15
|
+ if (arith_pmd != nullptr)
|
|
16
|
+ {
|
|
17
|
+ delete arith_pmd;
|
|
18
|
+ arith_pmd = nullptr;
|
|
19
|
+ }
|
|
20
|
+}
|
|
21
|
+
|
|
22
|
+std::tuple<int, std::string> WaferRebuild::initParam(const nlohmann::json& param)
|
|
23
|
+{
|
|
24
|
+ try
|
|
25
|
+ {
|
|
26
|
+ int retcode = arith_pmd->Initlization(param);
|
|
27
|
+ return std::make_tuple(0, "sucess");
|
|
28
|
+ }
|
|
29
|
+ catch (const std::exception& e)
|
|
30
|
+ {
|
|
31
|
+ return std::make_tuple(-1, e.what());
|
|
32
|
+ }
|
|
33
|
+
|
|
34
|
+}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+std::tuple<int, std::string> WaferRebuild::calcCloud(const std::vector<std::shared_ptr<infra::Image>>& image_list, std::shared_ptr<infra::CloudPoint<double>>& cloud_points, int32_t camera_index)
|
|
38
|
+{
|
|
39
|
+ try
|
|
40
|
+ {
|
|
41
|
+ if (!cloud_points) {
|
|
42
|
+ throw std::runtime_error("Error: cloud_points is nullptr!");
|
|
43
|
+ }
|
|
44
|
+ std::vector<Eigen::MatrixXf> img_pats;
|
|
45
|
+ std::vector<cv::Mat> gray_images;
|
|
46
|
+ img_pats.resize(image_list.size());
|
|
47
|
+ for (int i = 0; i < image_list.size(); ++i) {
|
|
48
|
+ int type = (image_list[i]->type() == -1) ? CV_8UC1 : CV_8UC3; // 假设 -1 是灰度图,其他都是三通道图像
|
|
49
|
+ cv::Mat mat;
|
|
50
|
+ cv::Mat grayMat;
|
|
51
|
+ if (type == CV_8UC1) {
|
|
52
|
+ grayMat = cv::Mat(arith_pmd->img_size.height, arith_pmd->img_size.width, type, image_list[i]->data());
|
|
53
|
+ gray_images.push_back(grayMat);
|
|
54
|
+ }
|
|
55
|
+ else {
|
|
56
|
+ mat = cv::Mat(arith_pmd->img_size.height, arith_pmd->img_size.width, type, image_list[i]->data());
|
|
57
|
+ cv::cvtColor(mat, grayMat, cv::COLOR_BGR2GRAY);
|
|
58
|
+ gray_images.push_back(grayMat);
|
|
59
|
+ }
|
|
60
|
+ // cv::cv2eigen(grayMat, img_pats[i]);
|
|
61
|
+ }
|
|
62
|
+ std::vector<cv::Mat> gray_temp{ gray_images[gray_images.size() - 4], gray_images[gray_images.size() - 3], gray_images[gray_images.size() - 2], gray_images[gray_images.size() - 1] };
|
|
63
|
+ for (int i = 0; i < gray_images.size(); ++i)
|
|
64
|
+ {
|
|
65
|
+ cv::Mat temp;
|
|
66
|
+ if (camera_index == 0)
|
|
67
|
+ {
|
|
68
|
+ cv::bitwise_and(gray_images[i], gray_images[i], temp, arith_pmd->mask0);
|
|
69
|
+ }
|
|
70
|
+ else if (camera_index == 1)
|
|
71
|
+ {
|
|
72
|
+ cv::bitwise_and(gray_images[i], gray_images[i], temp, arith_pmd->mask1);
|
|
73
|
+ }
|
|
74
|
+ else if (camera_index == 2)
|
|
75
|
+ {
|
|
76
|
+ cv::bitwise_and(gray_images[i], gray_images[i], temp, arith_pmd->mask2);
|
|
77
|
+ }
|
|
78
|
+ else if (camera_index == 3)
|
|
79
|
+ {
|
|
80
|
+ cv::bitwise_and(gray_images[i], gray_images[i], temp, arith_pmd->mask3);
|
|
81
|
+ }
|
|
82
|
+ // cv::bitwise_and(gray_images[i], gray_images[i], temp, arith_pmd->mask);
|
|
83
|
+ cv::imwrite("temp.bmp", temp);
|
|
84
|
+ cv::cv2eigen(temp, img_pats[i]);
|
|
85
|
+ }
|
|
86
|
+ int retcode0 = arith_pmd->Preprocess(gray_temp, 500, camera_index);
|
|
87
|
+ MatrixXfR pcl;
|
|
88
|
+ int retcode = arith_pmd->Predict(img_pats, pcl, camera_index);
|
|
89
|
+
|
|
90
|
+ // std::vector<infra::Point3d<float>> points;
|
|
91
|
+
|
|
92
|
+ // 预留足够空间
|
|
93
|
+ int numPoints = pcl.cols();
|
|
94
|
+ cloud_points->cloud_point.resize(numPoints);
|
|
95
|
+ // cloud_points->cloud_point.reserve(numPoints);
|
|
96
|
+ // cloud_points.reserve(numPoints);
|
|
97
|
+ // 遍历每一个点
|
|
98
|
+ for (int i = 0; i < numPoints; ++i) {
|
|
99
|
+ // 创建一个新的 Point3d 对象并添加到 vector
|
|
100
|
+ infra::Point3d<double> point = infra::Point3d<double>(
|
|
101
|
+ pcl(0, i), // X 坐标
|
|
102
|
+ pcl(1, i), // Y 坐标 m
|
|
103
|
+ pcl(2, i) // Z 坐标
|
|
104
|
+ );
|
|
105
|
+ cloud_points->cloud_point[i] = point;
|
|
106
|
+ }
|
|
107
|
+ save_matrix_as_ply(pcl, "surface.ply");
|
|
108
|
+ return std::make_tuple(0, "sucess");
|
|
109
|
+ }
|
|
110
|
+ catch (const std::exception& e) {
|
|
111
|
+ return std::make_tuple(-1, e.what());
|
|
112
|
+ }
|
|
113
|
+
|
|
114
|
+}
|
|
115
|
+
|
|
116
|
+pcl::PointCloud<pcl::PointXYZ> convertToPCLPointCloud(const std::shared_ptr<infra::CloudPoint<double>>& cloud_points) {
|
|
117
|
+ pcl::PointCloud<pcl::PointXYZ> cloud;
|
|
118
|
+
|
|
119
|
+ if (!cloud_points) {
|
|
120
|
+ std::cerr << "Error: Input cloud_points is nullptr." << std::endl;
|
|
121
|
+ return cloud;
|
|
122
|
+ }
|
|
123
|
+
|
|
124
|
+ // Resize the PCL PointCloud to the size of cloud_points
|
|
125
|
+ cloud.points.resize(cloud_points->size());
|
|
126
|
+
|
|
127
|
+ // Convert each point from infra::CloudPoint<double> to pcl::PointXYZ
|
|
128
|
+ for (size_t i = 0; i < cloud_points->size(); ++i) {
|
|
129
|
+ const infra::Point3d<double>& point = cloud_points->cloud_point[i];
|
|
130
|
+ cloud.points[i].x = static_cast<float>(point.x);
|
|
131
|
+ cloud.points[i].y = static_cast<float>(point.y);
|
|
132
|
+ cloud.points[i].z = static_cast<float>(point.z);
|
|
133
|
+ }
|
|
134
|
+
|
|
135
|
+ return cloud;
|
|
136
|
+}
|
|
137
|
+
|
|
138
|
+static std::shared_ptr<infra::CloudPoint<double>> convertToInfraCloudPoint(const pcl::PointCloud<pcl::PointXYZ>& cloud) {
|
|
139
|
+ // Create a new infra::CloudPoint<double> object
|
|
140
|
+ auto cloud_points = std::make_shared<infra::CloudPoint<double>>();
|
|
141
|
+
|
|
142
|
+ // Resize the cloud_points->cloud_point vector to the size of cloud
|
|
143
|
+ cloud_points->cloud_point.resize(cloud.points.size());
|
|
144
|
+
|
|
145
|
+ // Convert each pcl::PointXYZ point to infra::Point3d<double> and store in cloud_points
|
|
146
|
+ for (size_t i = 0; i < cloud.points.size(); ++i) {
|
|
147
|
+ cloud_points->cloud_point[i].x = static_cast<double>(cloud.points[i].x);
|
|
148
|
+ cloud_points->cloud_point[i].y = static_cast<double>(cloud.points[i].y);
|
|
149
|
+ cloud_points->cloud_point[i].z = static_cast<double>(cloud.points[i].z);
|
|
150
|
+ }
|
|
151
|
+
|
|
152
|
+ return cloud_points;
|
|
153
|
+}
|
|
154
|
+
|
|
155
|
+std::tuple<int, std::string> WaferRebuild::mergeCloud(const std::map<int32_t, std::shared_ptr<infra::CloudPoint<double>>>& cloud_points_list,
|
|
156
|
+ std::shared_ptr<infra::CloudPoint<double>>& cloud_points)
|
|
157
|
+{
|
|
158
|
+ try
|
|
159
|
+ {
|
|
160
|
+ int error_code = 0;
|
|
161
|
+ std::string error_message = "Success";
|
|
162
|
+ pcl::PointCloud<pcl::PointXYZ> cloud_output;
|
|
163
|
+ auto it = cloud_points_list.begin();
|
|
164
|
+ if (it == cloud_points_list.end()) {
|
|
165
|
+ error_code = -1;
|
|
166
|
+ error_message = "Error: Input cloud_points_list is empty.";
|
|
167
|
+ return std::make_tuple(error_code, error_message);
|
|
168
|
+ }
|
|
169
|
+ cloud_output = convertToPCLPointCloud(it->second);
|
|
170
|
+ ++it;
|
|
171
|
+ // Merge each subsequent cloud in the list
|
|
172
|
+ while (it != cloud_points_list.end()) {
|
|
173
|
+ pcl::PointCloud<pcl::PointXYZ> cloud_to_merge = convertToPCLPointCloud(it->second);
|
|
174
|
+
|
|
175
|
+ // Call Stitch function to merge cloud_output and cloud_to_merge
|
|
176
|
+ int stitch_result = arith_pmd->Stitch(cloud_output, cloud_to_merge, cloud_output, it->first);
|
|
177
|
+ if (stitch_result != 0) {
|
|
178
|
+ error_code = stitch_result;
|
|
179
|
+ error_message = "Error: Stitching failed for camera index " + std::to_string(it->first);
|
|
180
|
+ break;
|
|
181
|
+ }
|
|
182
|
+ ++it;
|
|
183
|
+ }
|
|
184
|
+ cloud_points = convertToInfraCloudPoint(cloud_output);
|
|
185
|
+
|
|
186
|
+ return std::make_tuple(error_code, error_message);
|
|
187
|
+ }
|
|
188
|
+ catch (const std::exception& e) {
|
|
189
|
+ return std::make_tuple(-1, e.what());
|
|
190
|
+ }
|
|
191
|
+}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+static infra::Point3d<double> calculateCentroid(const pcl::PointCloud<pcl::PointXYZ>& pcl_cloud) {
|
|
195
|
+ infra::Point3d<double> centroid;
|
|
196
|
+
|
|
197
|
+ // Create an Eigen vector to store the centroid
|
|
198
|
+ Eigen::Vector4f pcl_centroid;
|
|
199
|
+
|
|
200
|
+ // Compute centroid using PCL function
|
|
201
|
+ pcl::compute3DCentroid(pcl_cloud, pcl_centroid);
|
|
202
|
+
|
|
203
|
+ // Convert the centroid from Eigen vector to infra::Point3d<double>
|
|
204
|
+ centroid.x = pcl_centroid[0];
|
|
205
|
+ centroid.y = pcl_centroid[1];
|
|
206
|
+ centroid.z = pcl_centroid[2];
|
|
207
|
+
|
|
208
|
+ return centroid;
|
|
209
|
+}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+std::tuple<int, std::string> WaferRebuild::warpage(const std::shared_ptr<infra::CloudPoint<double>>& cloud_points, int32_t filterMM, nlohmann::json& result)
|
|
213
|
+{
|
|
214
|
+ try {
|
|
215
|
+ if (!cloud_points) {
|
|
216
|
+ throw std::runtime_error("Input cloud_points is nullptr.");
|
|
217
|
+ }
|
|
218
|
+
|
|
219
|
+ // Convert infra::CloudPoint<double> to pcl::PointCloud<pcl::PointXYZ>
|
|
220
|
+ pcl::PointCloud<pcl::PointXYZ> pcl_cloud = convertToPCLPointCloud(cloud_points);
|
|
221
|
+
|
|
222
|
+ // Calculate centroid (assuming centroid calculation is implemented in math_tool.h)
|
|
223
|
+ infra::Point3d<double> centroid = calculateCentroid(pcl_cloud); // Example function, replace with actual implementation
|
|
224
|
+
|
|
225
|
+ // Define x and y axes
|
|
226
|
+ infra::Point3d<double> axis_x(1.0, 0.0, 0.0); // Assuming x-axis direction
|
|
227
|
+ infra::Point3d<double> axis_y(0.0, 1.0, 0.0); // Assuming y-axis direction
|
|
228
|
+
|
|
229
|
+ // Calculate heights and populate result JSON
|
|
230
|
+ for (auto& axis : { "x", "y" }) {
|
|
231
|
+ std::vector<double> heights;
|
|
232
|
+ double bow = 0.0;
|
|
233
|
+ double warpage = 0.0;
|
|
234
|
+
|
|
235
|
+ infra::Point3d<double> axis_vector = (axis == "x") ? axis_x : axis_y;
|
|
236
|
+
|
|
237
|
+ // Calculate heights and populate heights vector
|
|
238
|
+ for (size_t i = 0; i < pcl_cloud.points.size(); ++i) {
|
|
239
|
+ infra::Point3d<double>& point = cloud_points->cloud_point[i];
|
|
240
|
+ double height = point.x * axis_vector.x + point.y * axis_vector.y + point.z * axis_vector.z;
|
|
241
|
+ heights.push_back(height);
|
|
242
|
+ }
|
|
243
|
+
|
|
244
|
+ // Calculate bow (average height)
|
|
245
|
+ if (!heights.empty()) {
|
|
246
|
+ bow = std::accumulate(heights.begin(), heights.end(), 0.0) / heights.size();
|
|
247
|
+ }
|
|
248
|
+
|
|
249
|
+ // Calculate warpage (standard deviation of heights)
|
|
250
|
+ if (heights.size() > 1) {
|
|
251
|
+ double sum_sq_diff = std::inner_product(heights.begin(), heights.end(), heights.begin(), 0.0);
|
|
252
|
+ double mean = bow;
|
|
253
|
+ double variance = sum_sq_diff / heights.size() - mean * mean;
|
|
254
|
+ warpage = std::sqrt(variance);
|
|
255
|
+ }
|
|
256
|
+
|
|
257
|
+ // Fill JSON result
|
|
258
|
+ result[axis]["height"] = heights;
|
|
259
|
+ result[axis]["bow"] = bow;
|
|
260
|
+ result[axis]["warpage"] = warpage;
|
|
261
|
+ }
|
|
262
|
+
|
|
263
|
+ /*
|
|
264
|
+ // Calculate max bow and max warpage
|
|
265
|
+ double max_bow = 0.0;
|
|
266
|
+ double max_warpage = 0.0;
|
|
267
|
+ double angle_max_bow = 0.0;
|
|
268
|
+ double angle_max_warpage = 0.0;
|
|
269
|
+
|
|
270
|
+ // Calculate max_bow and max_warpage values
|
|
271
|
+ // (example calculation, replace with actual implementation)
|
|
272
|
+ // Assume you have functions to find maximum bow and warpage and their angles
|
|
273
|
+ max_bow = calculateMaxBow(result);
|
|
274
|
+ max_warpage = calculateMaxWarpage(result);
|
|
275
|
+ angle_max_bow = calculateAngleMaxBow(result);
|
|
276
|
+ angle_max_warpage = calculateAngleMaxWarpage(result);
|
|
277
|
+
|
|
278
|
+ // Fill max bow and max warpage in JSON result
|
|
279
|
+ result["max_bow"]["angle"] = angle_max_bow;
|
|
280
|
+ result["max_bow"]["height"] = result[angle_max_bow]["height"];
|
|
281
|
+ result["max_bow"]["max_bow"] = max_bow;
|
|
282
|
+
|
|
283
|
+ result["max_warpage"]["angle"] = angle_max_warpage;
|
|
284
|
+ result["max_warpage"]["height"] = result[angle_max_warpage]["height"];
|
|
285
|
+ result["max_warpage"]["max_warpage"] = max_warpage;
|
|
286
|
+ */
|
|
287
|
+ return std::make_tuple(0, "Success");
|
|
288
|
+ }
|
|
289
|
+ catch (const std::exception& e) {
|
|
290
|
+ return std::make_tuple(-1, e.what());
|
|
291
|
+ }
|
|
292
|
+}
|