Commit 5e69f8fca9d5597af539904e4b67bae1f9c2bfc8

Authored by Hu Chunming
1 parent 81e8a405

补充字段;

优化逆行处理
jni/VehicleNativeInterface.cpp
... ... @@ -452,7 +452,7 @@ JNIEXPORT jint JNICALL Java_com_objecteye_nativeinterface_vehicle_VehicleNativeI
452 452 jobject vehicle_pendant_det_res_vpd_res_syRect_rect = env->NewObject(cls_SyRect, mid_SyRect, one_pendant_res.rect.left_,
453 453 one_pendant_res.rect.top_, one_pendant_res.rect.width_, one_pendant_res.rect.height_);
454 454  
455   - jobject vehiclePendantDetInfo = env->NewObject(cls_VehiclePendantDetInfo, mid_VehiclePendantDetInfo, vehicle_pendant_det_res_vpd_res_syRect_rect, one_pendant_res.index, one_pendant_res.confidence, one_pendant_res.driver_copilot_info);
  455 + jobject vehiclePendantDetInfo = env->NewObject(cls_VehiclePendantDetInfo, mid_VehiclePendantDetInfo, vehicle_pendant_det_res_vpd_res_syRect_rect, one_pendant_res.index, one_pendant_res.confidence, one_pendant_res.driver_copilot_info, one_pendant_res.iColor);
456 456  
457 457 env->SetObjectArrayElement(vehiclePendantDetInfoArray, m, vehiclePendantDetInfo);
458 458 }
... ... @@ -530,7 +530,18 @@ JNIEXPORT jint JNICALL Java_com_objecteye_nativeinterface_vehicle_VehicleNativeI
530 530 }
531 531  
532 532 jint type = vehicle_info.type;
533   - jobject vehicleInfo = env->NewObject(cls_VehicleInfo, mid_VehicleInfo, vehicleDetectResult, vehicleWinDetectResult, vehicleBodyDetectResult, vehicleColorResult, vehicleRecgResult, vplateResult, vehiclePendantDetResult, vehicleIllegalDetResult, vehicleFeaResult,mtaResult, MannedResult, type );
  533 + jint vpt_type = vehicle_info.vpt_type;
  534 + jint rainshed = vehicle_info.rainshed; //是否安装雨棚, 0 有雨棚 1 无雨棚
  535 + jint truck_manned = vehicle_info.truck_manned;
  536 + jint motor_manned = vehicle_info.motor_manned;
  537 + jint human_upper_color = vehicle_info.human_upper_color;
  538 + jint human_lower_color = vehicle_info.human_lower_color;
  539 + jint reverse_driving = vehicle_info.reverse_driving; // 0 正常行驶 1 逆行 -1 未知
  540 + jint phoning = vehicle_info.phoning; // 骑车打电话
  541 + jint cross_line = vehicle_info.cross_line; // 压实线, 1 黄实线 2 白实线 -1 其他
  542 + jint cross_diversion_line = vehicle_info.cross_diversion_line; // 压导流线 1 压了 -1 未压
  543 +
  544 + jobject vehicleInfo = env->NewObject(cls_VehicleInfo, mid_VehicleInfo, vehicleDetectResult, vehicleWinDetectResult, vehicleBodyDetectResult, vehicleColorResult, vehicleRecgResult, vplateResult, vehiclePendantDetResult, vehicleIllegalDetResult, vehicleFeaResult,mtaResult, MannedResult, type, vpt_type, rainshed, truck_manned, motor_manned, human_upper_color, reverse_driving, phoning, cross_line, cross_diversion_line);
534 545  
535 546 env->SetObjectArrayElement(vehicleInfoArray, j, vehicleInfo);
536 547 }
... ... @@ -566,12 +577,12 @@ JNIEXPORT void JNICALL Java_com_objecteye_nativeinterface_vehicle_VehicleNativeI
566 577  
567 578 /*
568 579 * Class: com_objecteye_nativeinterface_vehicle_VehicleNativeInterface
569   - * Method: va_get_version
  580 + * Method: get_village_pic_version
570 581 * Signature: ()Ljava/lang/String;
571 582 */
572 583 JNIEXPORT jstring JNICALL Java_com_objecteye_nativeinterface_vehicle_VehicleNativeInterface_getVersion(JNIEnv *env, jobject obj)
573 584 {
574   - const char *version = va_get_version();
  585 + const char *version = get_village_pic_version();
575 586 return env->NewStringUTF(version);
576 587 }
577 588  
... ...
src/PicAnalysis.cpp
... ... @@ -222,8 +222,8 @@ vector<AnalysisResult> PicAnalysis::analysis_img(vector<sy_img> vec_img){
222 222  
223 223 sy_rect vehicle_rect = result_info.vehicle_body_detect_res.rect;
224 224  
225   - if (road_info.direct_mask.cols > 0 && (1 == shot_type || 0 == shot_type)) {
226   - result_info.reverse_driving = m_road_seg_algorithm.check_reverse_driving(road_info.direct_mask, vehicle_rect, src.width, src.height, shot_type);
  225 + if (road_info.vec_direct.size() > 0 && (1 == shot_type || 0 == shot_type)) {
  226 + result_info.reverse_driving = m_road_seg_algorithm.check_reverse_driving(road_info.vec_direct, vehicle_rect, src.width, src.height, shot_type);
227 227 }
228 228  
229 229 // 行人
... ... @@ -250,14 +250,14 @@ vector<AnalysisResult> PicAnalysis::analysis_img(vector<sy_img> vec_img){
250 250 // 车尾,判断是否 货车尾部货厢载人
251 251 if(result_info.vpt_type == 6 || result_info.vpt_type == 7){
252 252 if(result_info.manned_res.hs_count > 0){
253   - result_info.manned = 1;
  253 + result_info.truck_manned = 1;
254 254 }
255 255 }
256 256 } else {
257 257 if(result_info.vpt_type == 1 || result_info.vpt_type == 2 || result_info.vpt_type == 3){
258 258 if(result_info.manned_res.hs_count >= 3){
259 259 // 摩托车、三轮车载人
260   - result_info.manned = 1;
  260 + result_info.motor_manned = 1;
261 261 }
262 262 }
263 263 }
... ... @@ -329,9 +329,10 @@ vector<AnalysisResult> PicAnalysis::analysis_img(vector<sy_img> vec_img){
329 329 }
330 330  
331 331 std::vector<HumanCarResult> vec_hcp_result = m_human_car_algorithm.detect(vec_motor_img);
332   - if (vec_hcp_result.size() > 0) {
333   - if (vec_hcp_result[11] == 0 || vec_hcp_result[11] == 1) {
334   - result_info.reverse_driving = m_road_seg_algorithm.check_reverse_driving(road_info.direct_mask, vehicle_rect, src.width, src.height, vec_hcp_result[11]);
  332 + if (vec_hcp_result.size() > 0 && road_info.vec_direct.size() > 0) {
  333 + int head_or_tail = vec_hcp_result[11].type;
  334 + if (head_or_tail == 0 || head_or_tail == 1) {
  335 + result_info.reverse_driving = m_road_seg_algorithm.check_reverse_driving(road_info.vec_direct, vehicle_rect, src.width, src.height, head_or_tail);
335 336 }
336 337 }
337 338  
... ...
src/ai_engine_module/RoadSegAnalysis.cpp
... ... @@ -3,518 +3,6 @@
3 3 uint8_t seg_colors[][3] = { {0, 0, 0}, {0, 255, 255}, {128, 255, 0}, {255, 128, 0}, {128, 0, 255}, {255, 0, 128}, {0, 128, 255}, {0, 255, 128}, {128, 255, 255}};
4 4 uint8_t lane_colors[][3] = { {0, 0, 0}, {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0}, {255, 0, 255}, {0, 255, 255}, {128, 255, 0}, {255, 128, 0}};
5 5  
6   -void lanes_process(const rs_lane* lanes, int lane_count, std::vector<std::pair<std::vector<cv::Point>, int>>& combined, float scale_w = 1.0, float scale_h = 1.0) {
7   - std::vector<std::vector<cv::Point> > lanes_xys;
8   - std::vector<int> lanes_cls;
9   - for (int i = 0; i < lane_count; i++) {
10   - std::vector<cv::Point> xys;
11   - for (int j = 0; j < lanes[i].num_points; j++) {
12   - int x = static_cast<int>(lanes[i].points[j].x_ * scale_w);
13   - int y = static_cast<int>(lanes[i].points[j].y_ * scale_h);
14   - if (x > 0 && y > 0) {
15   - xys.emplace_back(x, y);
16   - }
17   - }
18   - if (!xys.empty()) {
19   - lanes_xys.push_back(xys);
20   - lanes_cls.push_back(lanes[i].cls);
21   - }
22   - }
23   -
24   - for (size_t i = 0; i < lanes_xys.size(); ++i) {
25   - combined.push_back(std::make_pair(lanes_xys[i], lanes_cls[i]));
26   - }
27   - if (!combined.empty()) {
28   - //按车道线起点坐标排序,相应的类别顺序也会变化以保证标签对齐
29   - std::sort(combined.begin(), combined.end(), [](const std::pair<std::vector<cv::Point>, int>& a, const std::pair<std::vector<cv::Point>, int>& b) {
30   - return a.first[0].x < b.first[0].x;
31   - });
32   - }
33   -}
34   -
35   -cv::Mat mask_to_rgb(cv::Mat img, cv::Mat mask) {
36   - cv::Mat rgb = img.clone();
37   - int reg_cls = 9;
38   - for (int i = 0; i < rgb.rows; i++) {
39   - for (int j = 0; j < rgb.cols; j++) {
40   - for (int k = 1; k < reg_cls; k++) {
41   - if (mask.at<int>(i,j) == k) {
42   - rgb.at<cv::Vec3b>(i,j)[0] = seg_colors[k][0];
43   - rgb.at<cv::Vec3b>(i,j)[1] = seg_colors[k][1];
44   - rgb.at<cv::Vec3b>(i,j)[2] = seg_colors[k][2];
45   - }
46   - }
47   - }
48   - }
49   - return rgb;
50   -}
51   -
52   -float contourArea(std::vector<cv::Point> contour, cv::Point2f& center) {
53   - cv::RotatedRect rect = cv::minAreaRect(contour); // 最小外接矩形 rect[0]中心点 rect[1]宽 高 rect[2]旋转角度
54   - center = rect.center;
55   - return cv::contourArea(contour);
56   -}
57   -
58   -int Mask2LanePoints(const cv::Mat& pred, std::vector<std::vector<cv::Point>>&lanes, std::vector<int>& cats) {
59   - std::vector<int> labels = {9, 10, 11, 12, 13};
60   - for(auto cat: labels) {
61   - cv::Mat b_masks, measure_labels, stats, centroids;
62   - cv::compare(pred, cat, b_masks, cv::CMP_EQ); //将pred元素逐个和cat比较,相同255,不同0
63   - // cv::threshold(pred, b_masks, 126, 255, cv::THRESH_OTSU); //生成二值图
64   - // 连通域计算 b_masks:闭操作后的二值图像 measure_labels:和原图一样大的标记图 centroids:nccomps×2的矩阵,表示每个连通域的质心(x, y)
65   - // stats:nccomps×5的矩阵 表示每个连通区域的外接矩形和面积(x, y, w, h, area),索引0是背景信息
66   - int nccomps = cv::connectedComponentsWithStats (b_masks, measure_labels, stats, centroids, 4); //8
67   - for(int cv_measure_id = 1; cv_measure_id < nccomps; cv_measure_id++ ) { //跳过背景信息0
68   - cv::Mat cv_measure_mask;
69   - cv::compare(measure_labels, cv_measure_id, cv_measure_mask, cv::CMP_EQ);
70   - std::vector< std::vector< cv::Point> > contours;
71   - cv::findContours(cv_measure_mask,contours,cv::noArray(),cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
72   - std::vector<cv::Point> contours_poly;
73   - for (int j = 0; j < contours.size();j++) {
74   - // float area = cv::contourArea(contours[j]); if (area < 60) continue; //30
75   - float area = cv::contourArea(contours[j]); if (area < 30) continue; //30
76   - cv::approxPolyDP(cv::Mat(contours[j]), contours_poly, 6, true); //减小epsilon提高拟合精度(需要调试,epsilon过小会使多边形不够简化,单条线变多条)
77   - if (contours_poly.size() == 1) continue;
78   - lanes.push_back(contours_poly);
79   - cats.push_back(cat);
80   - }
81   - }
82   - }
83   - return 0;
84   -}
85   -
86   -int findMainMaskV2(bool large_resolution, const cv::Mat& solve_masks, const std::vector<int>& labels, std::vector<std::vector<cv::Point>> &poly_masks, std::vector<int> &region_classes, std::vector<std::vector<cv::Point>> &main_masks, cv::Mat& new_mask, cv::Mat& new_mask_forlane) {
87   - int h = 360, w = 640;
88   - int seg_num_cls = 8;
89   - int seg_num_seg = 4;
90   - int seg_min_region_area = 512; //10
91   - // mask部分区域
92   - if (large_resolution) solve_masks(cv::Rect(0, 0, w, int(h * 0.14))) = 0;
93   - else solve_masks(cv::Rect(0, 0, w, int(h * 0.22))) = 0;
94   - solve_masks(cv::Rect(0, int(h * 0.95), w, int(h * 0.05))) = 0;
95   - solve_masks(cv::Rect(0, 0, int(w * 0.02), h)) = 0;
96   - solve_masks(cv::Rect(int(w * 0.95), 0, int(w * 0.05), h)) = 0;
97   -
98   - float hf_w = w*0.5;
99   - std::vector<std::vector<cv::Point>> all_emerg_contours, all_com_contours, mid_com_contours, mid_zd_contours;
100   - std::vector<cv::Point> emerg_contours, mid_contours, com_contours, zd_contours;
101   - float emerg_max_area = 0, max_area = 0, zd_max_area = 0;
102   -
103   - for(auto cat: labels) {
104   - if (cat == 0 || cat > seg_num_seg)
105   - continue;
106   -
107   - // std::cout << cat << std::endl;
108   - cv::Mat b_masks, measure_labels, stats, centroids;
109   - cv::Mat n_masks = cv::Mat_<int>(h,w);
110   - n_masks = cv::Scalar(255);
111   - cv::compare(solve_masks, cat, b_masks, cv::CMP_EQ); //将solve_masks元素逐个和cat比较,相同255,不同0
112   - //连通域计算
113   - int nccomps = cv::connectedComponentsWithStats (b_masks, measure_labels, stats, centroids, 8);
114   - for(int i = 1; i < nccomps; i++ ) { //跳过背景信息0
115   - //移除过小的区域,并将对应位置置为0
116   - if (stats.at<int>(i, cv::CC_STAT_AREA) < seg_min_region_area) {
117   - cv::Mat comparison_result;
118   - cv::compare(measure_labels, cv::Scalar(i), comparison_result, cv::CMP_EQ); //相等为255不等为0
119   - n_masks.setTo(0, comparison_result); // 将comparison_result中非零区域置为0
120   - cv::bitwise_and(solve_masks,n_masks,solve_masks);
121   - continue;
122   - }
123   -
124   - double centr_x = centroids.at<double>(i, 0);
125   - double centr_y = centroids.at<double>(i, 1);
126   -
127   - int region_class = cat;
128   - cv::Mat region_mask;
129   - cv::bitwise_and(measure_labels,n_masks,measure_labels);/////
130   - cv::compare(measure_labels, i, region_mask, cv::CMP_EQ);
131   -
132   - // 闭运算,先膨胀再腐蚀,去除较暗部分
133   - cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(17, 5));
134   - cv::morphologyEx(region_mask, region_mask, cv::MORPH_CLOSE, kernel);
135   -
136   - std::vector< std::vector< cv::Point> > contours;
137   - cv::findContours(region_mask,contours,cv::noArray(),cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
138   - std::vector<cv::Point> contours_poly;
139   -
140   - // 应急车道
141   - if(region_class == 2) {
142   - for (auto contour : contours) {
143   - cv::Point2f center;
144   - float area_ = contourArea(contour, center);
145   - if (area_ > emerg_max_area) {
146   - emerg_max_area = area_;
147   - emerg_contours = contour;
148   - }
149   - all_emerg_contours.push_back(contour);
150   - }
151   - }
152   -
153   - // 普通行车道
154   - if(region_class == 1) {
155   - for (auto contour : contours) {
156   - cv::Point2f center;
157   - float area_ = contourArea(contour, center);
158   - if (area_ > max_area) {
159   - max_area = area_;
160   - com_contours = contour;
161   - }
162   - // 取中点所在的连通域
163   - cv::Point2f point(int(w*0.5),int(h*0.95)-1);
164   - double distance = cv::pointPolygonTest(contour, point, false);
165   - if (distance >= 0) {
166   - mid_contours = contour;
167   - hf_w = center.x;
168   - continue;
169   - }
170   - if (abs(center.x - hf_w) < 90) // 取中点所在区域左右90像素内的连通域 230307
171   - mid_com_contours.push_back(contour);
172   - }
173   - }
174   -
175   - // 导流线
176   - if(region_class == 3) {
177   - for (auto contour : contours) {
178   - cv::Point2f center;
179   - float area_ = contourArea(contour, center);
180   - if (area_ > zd_max_area) {
181   - zd_max_area = area_;
182   - zd_contours = contour;
183   - }
184   - // if (abs(center.x - w*0.5) < 200) // 取中点左右200像素内的连通域
185   - if (abs(center.x - w*0.5) < 250) // 取中点左右250像素内的连通域
186   - mid_zd_contours.push_back(contour);
187   - }
188   - }
189   -
190   - // 拟合各行驶区域
191   - for (int j = 0; j < contours.size();j++) {
192   - cv::approxPolyDP(cv::Mat(contours[j]), contours_poly, 10, true);
193   - if (contours_poly.size() <= 2) continue;
194   - poly_masks.push_back(contours_poly);
195   - region_classes.push_back(cat);
196   - }
197   - }
198   - }
199   -
200   - // cv::Mat new_mask(h, w, CV_8UC3, cv::Scalar(0,0,0));
201   - if (!mid_contours.empty()) {
202   - // cv::fillConvexPoly(new_mask, mid_contours, cv::Scalar(255,255,255)); //填充255
203   - cv::fillConvexPoly(new_mask, mid_contours, cv::Scalar(255)); //填充255
204   - cv::fillConvexPoly(new_mask_forlane, mid_contours, cv::Scalar(255)); //填充255
205   - std::vector<cv::Point> contours_poly;
206   - cv::approxPolyDP(cv::Mat(mid_contours), contours_poly, 10, true);
207   - if (contours_poly.size() > 2) main_masks.push_back(contours_poly);
208   - all_com_contours.push_back(mid_contours);
209   - }
210   - else {
211   - // cv::fillConvexPoly(new_mask, com_contours, cv::Scalar(255,255,255)); //填充255
212   - cv::fillConvexPoly(new_mask, com_contours, cv::Scalar(255)); //填充255
213   - cv::fillConvexPoly(new_mask_forlane, com_contours, cv::Scalar(255)); //填充255
214   - std::vector<cv::Point> contours_poly;
215   - cv::approxPolyDP(cv::Mat(com_contours), contours_poly, 10, true);
216   - if (contours_poly.size() > 2) main_masks.push_back(contours_poly);
217   - all_com_contours.push_back(com_contours);
218   - }
219   -
220   - for (auto contour_ : mid_com_contours) {
221   - // cv::fillConvexPoly(new_mask, contour_, cv::Scalar(255,255,255)); //填充255
222   - cv::fillConvexPoly(new_mask, contour_, cv::Scalar(255)); //填充255
223   - cv::fillConvexPoly(new_mask_forlane, contour_, cv::Scalar(255)); //填充255
224   - std::vector<cv::Point> contours_poly;
225   - cv::approxPolyDP(cv::Mat(contour_), contours_poly, 10, true);
226   - if (contours_poly.size() > 2) main_masks.push_back(contours_poly);
227   - all_com_contours.push_back(contour_);
228   - }
229   -
230   - if (!emerg_contours.empty() && !all_emerg_contours.empty()) {
231   - if (all_emerg_contours.size() == 1)
232   - // cv::fillConvexPoly(new_mask, emerg_contours, cv::Scalar(255,255,255));
233   - cv::fillConvexPoly(new_mask, emerg_contours, cv::Scalar(255)); //填充255
234   - else {
235   - float sum_centerx = 0, sum_centery = 0;
236   - float length_emerg_com = 9999999;
237   - // 计算选中行车道的平均中心点
238   - for (auto contour_ : all_com_contours) {
239   - cv::Point2f center;
240   - float area_ = contourArea(contour_, center);
241   - sum_centerx += center.x;
242   - sum_centery += center.y;
243   - }
244   - float ave_centerx = sum_centerx / all_com_contours.size();
245   - float ave_centery = sum_centery / all_com_contours.size();
246   - // 选择距离最近的应急车道且面积不小于最大应急车道的一半
247   - for (auto econtour_ : all_emerg_contours) {
248   - cv::Point2f center;
249   - float area_ = contourArea(econtour_, center);
250   - float tmp_length = sqrt(pow((ave_centerx-center.x),2.0) + pow((ave_centery-center.y),2.0));
251   - if (tmp_length < length_emerg_com and area_ > 0.7*emerg_max_area) {
252   - length_emerg_com = tmp_length;
253   - emerg_contours = econtour_;
254   - }
255   - }
256   - // cv::fillConvexPoly(new_mask, emerg_contours, cv::Scalar(255,255,255));
257   - cv::fillConvexPoly(new_mask, emerg_contours, cv::Scalar(255)); //填充255
258   - }
259   - }
260   -
261   - if (!mid_zd_contours.empty()) {
262   - for (auto contour_ : mid_zd_contours)
263   - // cv::fillConvexPoly(new_mask, contour_, cv::Scalar(255,255,255)); //填充255
264   - cv::fillConvexPoly(new_mask, contour_, cv::Scalar(255)); //填充255
265   - }
266   -
267   - // 膨胀腐蚀,去除行车道和应急车道间的空洞
268   - cv::Mat kernel_ = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(17, 5));
269   - cv::morphologyEx(new_mask, new_mask, cv::MORPH_CLOSE, kernel_);
270   - cv::morphologyEx(new_mask_forlane, new_mask_forlane, cv::MORPH_CLOSE, kernel_);
271   -
272   - return 0;
273   -}
274   -
275   -
276   -cv::Mat seg_post_process(bool large_resolution, unsigned char *seg_array, std::vector<std::pair<std::vector<cv::Point>, int>> combined, std::vector<std::vector<cv::Point>> &poly_masks, std::vector<int> &region_classes, std::vector<std::vector<cv::Point>> &lanes, std::vector<int> &cats, std::map<double, int> &x_sort, cv::Mat &background_mask) {
277   - std::vector<int> pred_cls;
278   - int h = 360, w = 640;
279   - cv::Mat lanes_masks = cv::Mat_<int>(h,w); //正常分割结果
280   - cv::Mat mask_rmlane = cv::Mat_<int>(h,w); //车道线区域置为背景
281   - cv::Mat solve_masks = cv::Mat_<int>(h,w); //计算主行驶区域用(虚线及减速标线归入行车道)
282   - int step_size = h*w;
283   - int seg_min_region_area = 512; //1024
284   -
285   - for (int i = 0; i < h; ++i) {
286   - for (int j = 0; j < w; ++j) {
287   - int max_cls = seg_array[(i * w + j)];
288   - lanes_masks.ptr<int>(i)[j] = max_cls;
289   - pred_cls.push_back(max_cls);
290   - mask_rmlane.ptr<int>(i)[j] = max_cls;
291   - solve_masks.ptr<int>(i)[j] = max_cls;
292   - }
293   - }
294   -
295   - for (const auto& lane_info : combined) {
296   - const auto& xys = lane_info.first;
297   - int cls = lane_info.second;
298   - if (cls == 1) cls = 9; /*黄实线*/ if (cls == 2) cls = 10; /*白实线*/
299   - if (cls == 3) cls = 11; /*虚线*/ if (cls == 4) cls = 12; /*黄虚线*/
300   - if (cls == 5) cls = 13; /*车道中线*/
301   - for (size_t i = 1; i < xys.size(); ++i) {
302   - cv::line(lanes_masks, xys[i - 1], xys[i], cls, 4); //绘制车道线用于求连通域
303   - if (cls == 11 || cls == 12) cls = 1; //求主行驶区域时将虚线归入行车道
304   - cv::line(solve_masks, xys[i - 1], xys[i], cls, 4);
305   -
306   - }
307   - }
308   -
309   - // 求背景区域--mask车道区域,场景变化用
310   - cv::compare(lanes_masks, 0, background_mask, cv::CMP_EQ); //将lanes_masks元素逐个和0比较,相同255,不同0
311   -#if 0
312   - //--mask远处区域------------------------------------------------
313   - cv::Mat mask_black = mask_rmlane.clone();
314   - if (large_resolution) mask_black(cv::Rect(0, 0, w, int(h * 0.14))) = 0;
315   - else mask_black(cv::Rect(0, 0, w, int(h * 0.22))) = 0;
316   - mask_black(cv::Rect(0, int(h * 0.95), w, int(h * 0.05))) = 0;
317   - mask_black(cv::Rect(0, 0, int(w * 0.02), h)) = 0;
318   - mask_black(cv::Rect(int(w * 0.95), 0, int(w * 0.05), h)) = 0;
319   - mask_rmlane = mask_black;
320   - //-------------------------------------------------------------------------
321   -#endif
322   - //2.去重获取预测到的类别
323   - std::vector<int> labels(pred_cls);
324   - std::sort(labels.begin(),labels.end());
325   - labels.erase(std::unique(labels.begin(),labels.end()),labels.end());
326   -
327   - //4.求车道线区域
328   - int flag = Mask2LanePoints(lanes_masks, lanes, cats); ///////////////////////// 车道线如何与mask结合
329   -
330   - //5.求道路区域
331   - int count = 0;
332   - for(auto cat: labels) {
333   - // std::cout << cat << std::endl;
334   - cv::Mat b_masks, measure_labels, stats, centroids;
335   - cv::Mat n_masks = cv::Mat_<int>(h,w);
336   - n_masks = cv::Scalar(255);
337   - cv::compare(mask_rmlane, cat, b_masks, cv::CMP_EQ); //将mask_rmlane元素逐个和cat比较,相同255,不同0
338   - //连通域计算
339   - int nccomps = cv::connectedComponentsWithStats (b_masks, measure_labels, stats, centroids, 8);
340   - for(int i = 1; i < nccomps; i++ ) { //跳过背景信息0
341   - //移除过小的区域,并将对应位置置为0
342   - if (stats.at<int>(i, cv::CC_STAT_AREA) < seg_min_region_area) {
343   - cv::Mat comparison_result;
344   - cv::compare(measure_labels, cv::Scalar(i), comparison_result, cv::CMP_EQ); //相等为255不等为0
345   - n_masks.setTo(0, comparison_result); // 将comparison_result中非零区域置为0
346   -
347   - cv::bitwise_and(mask_rmlane,n_masks,mask_rmlane);
348   - continue;
349   - }
350   -
351   - double centr_x = centroids.at<double>(i, 0);
352   - double centr_y = centroids.at<double>(i, 1);
353   -
354   - int region_class = cat;
355   - // printf("region_class: %d\n", region_class);
356   - cv::Mat region_mask;
357   - cv::bitwise_and(measure_labels,n_masks,measure_labels);/////
358   - cv::compare(measure_labels, i, region_mask, cv::CMP_EQ);
359   -
360   - std::vector< std::vector< cv::Point> > contours;
361   - cv::findContours(region_mask,contours,cv::noArray(),cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
362   - std::vector<cv::Point> contours_poly;
363   - for (int j = 0; j < contours.size();j++) {
364   - cv::approxPolyDP(cv::Mat(contours[j]), contours_poly, 10, true);
365   - if (contours_poly.size() <= 2) continue;
366   - poly_masks.push_back(contours_poly);
367   - region_classes.push_back(cat);
368   - if (x_sort.count(centr_x)) centr_x += 0.0001;
369   - x_sort.insert(std::make_pair(centr_x, count));
370   - ++ count;
371   - // for (auto iter: contours_poly) {
372   - // std::cout << "contour " << iter << " " << cat << std::endl;
373   - // }
374   -
375   - }
376   - }
377   - }
378   -
379   -#if 0
380   - //6.draw lanes
381   - for (int i = 0; i < lanes.size(); ++i) {
382   - int thickness = 4;
383   - for (int j = 0; j < lanes[i].size()-1; ++j) {
384   - cv::line(mask_rmlane, lanes[i][j], lanes[i][j+1], cats[i], thickness);
385   - // std::cout << lanes[i][j] << " " << lanes[i][j+1] << " " << cats[i] << std::endl;
386   - }
387   - }
388   -#endif
389   - return mask_rmlane;
390   -}
391   -
392   -
393   -
394   -cv::Mat direct_post_process(bool large_resolution, unsigned char *direct_array, std::vector<std::vector<cv::Point>> &poly_masks, std::vector<int> &region_classes) {
395   - std::vector<int> pred_cls;
396   - int h = 360, w = 640, step_size = h*w, seg_min_region_area = 512;
397   - cv::Mat mask_rmlane = cv::Mat_<int>(h,w); //车道线区域置为背景
398   - for (int i = 0; i < h; ++i) {
399   - for (int j = 0; j < w; ++j) {
400   - int max_cls = direct_array[(i * w + j)];
401   - pred_cls.push_back(max_cls);
402   - mask_rmlane.ptr<int>(i)[j] = max_cls;
403   - }
404   - }
405   -
406   -#if 1 /*mask远处区域*/
407   - cv::Mat mask_black = mask_rmlane.clone();
408   - if (large_resolution) mask_black(cv::Rect(0, 0, w, int(h * 0.14))) = 0;
409   - else mask_black(cv::Rect(0, 0, w, int(h * 0.22))) = 0;
410   - mask_black(cv::Rect(0, int(h * 0.95), w, int(h * 0.05))) = 0;
411   - mask_black(cv::Rect(0, 0, int(w * 0.02), h)) = 0;
412   - mask_black(cv::Rect(int(w * 0.95), 0, int(w * 0.05), h)) = 0;
413   - mask_rmlane = mask_black;
414   -#endif
415   - //去重获取预测到的类别
416   - std::vector<int> labels(pred_cls);
417   - std::sort(labels.begin(),labels.end());
418   - labels.erase(std::unique(labels.begin(),labels.end()),labels.end());
419   -
420   - //求道路区域
421   - for(auto cat: labels) {
422   - cv::Mat b_masks, measure_labels, stats, centroids;
423   - cv::Mat n_masks = cv::Mat_<int>(h,w); n_masks = cv::Scalar(255);
424   - cv::compare(mask_rmlane, cat, b_masks, cv::CMP_EQ); //将mask_rmlane元素逐个和cat比较,相同255,不同0
425   - //连通域计算
426   - int nccomps = cv::connectedComponentsWithStats (b_masks, measure_labels, stats, centroids, 8);
427   - for(int i = 1; i < nccomps; i++ ) { //跳过背景信息0
428   - if (stats.at<int>(i, cv::CC_STAT_AREA) < seg_min_region_area) { //移除过小的区域,并将对应位置置为0
429   - cv::Mat comparison_result;
430   - cv::compare(measure_labels, cv::Scalar(i), comparison_result, cv::CMP_EQ); //相等为255不等为0
431   - n_masks.setTo(0, comparison_result); // 将comparison_result中非零区域置为0
432   - cv::bitwise_and(mask_rmlane,n_masks,mask_rmlane);
433   - continue;
434   - }
435   -
436   - cv::Mat region_mask;
437   - cv::bitwise_and(measure_labels,n_masks,measure_labels);/////
438   - cv::compare(measure_labels, i, region_mask, cv::CMP_EQ);
439   -
440   - std::vector<std::vector<cv::Point>> contours;
441   - cv::findContours(region_mask,contours,cv::noArray(),cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
442   - std::vector<cv::Point> contours_poly;
443   - for (int j = 0; j < contours.size();j++) {
444   - cv::approxPolyDP(cv::Mat(contours[j]), contours_poly, 10, true);
445   - if (contours_poly.size() <= 2) continue;
446   - poly_masks.push_back(contours_poly);
447   - region_classes.push_back(cat);
448   - }
449   - }
450   - }
451   - return mask_rmlane;
452   -}
453   -
454   -
455   -// 合并来去区域
456   -cv::Mat merge_direct_process(bool large_resolution, unsigned char *direct_array, std::vector<std::vector<cv::Point>> &poly_masks, std::vector<int> &region_classes) {
457   - std::vector<int> pred_cls;
458   - int h = 360, w = 640, step_size = h*w, seg_min_region_area = 512;
459   - cv::Mat mask_rmlane = cv::Mat_<int>(h,w); //车道线区域置为背景
460   - for (int i = 0; i < h; ++i) {
461   - for (int j = 0; j < w; ++j) {
462   - int max_cls = direct_array[(i * w + j)];
463   - if (max_cls == 1 || max_cls == 2) max_cls = 5; // 来去区域合并的类别为5
464   - if (max_cls == 3 || max_cls == 4) max_cls = 6; // 近远区域合并的类别为6
465   - pred_cls.push_back(max_cls);
466   - mask_rmlane.ptr<int>(i)[j] = max_cls;
467   - }
468   - }
469   -
470   -#if 0 /*mask远处区域*/
471   - cv::Mat mask_black = mask_rmlane.clone();
472   - if (large_resolution) mask_black(cv::Rect(0, 0, w, int(h * 0.14))) = 0;
473   - else mask_black(cv::Rect(0, 0, w, int(h * 0.22))) = 0;
474   - mask_black(cv::Rect(0, int(h * 0.95), w, int(h * 0.05))) = 0;
475   - mask_black(cv::Rect(0, 0, int(w * 0.02), h)) = 0;
476   - mask_black(cv::Rect(int(w * 0.95), 0, int(w * 0.05), h)) = 0;
477   - mask_rmlane = mask_black;
478   -#endif
479   - //去重获取预测到的类别
480   - std::vector<int> labels(pred_cls);
481   - std::sort(labels.begin(),labels.end());
482   - labels.erase(std::unique(labels.begin(),labels.end()),labels.end());
483   -
484   - //求道路区域
485   - for(auto cat: labels) {
486   - cv::Mat b_masks, measure_labels, stats, centroids;
487   - cv::Mat n_masks = cv::Mat_<int>(h,w); n_masks = cv::Scalar(255);
488   - cv::compare(mask_rmlane, cat, b_masks, cv::CMP_EQ); //将mask_rmlane元素逐个和cat比较,相同255,不同0
489   - //连通域计算
490   - int nccomps = cv::connectedComponentsWithStats (b_masks, measure_labels, stats, centroids, 8);
491   - for(int i = 1; i < nccomps; i++ ) { //跳过背景信息0
492   - if (stats.at<int>(i, cv::CC_STAT_AREA) < seg_min_region_area) { //移除过小的区域,并将对应位置置为0
493   - cv::Mat comparison_result;
494   - cv::compare(measure_labels, cv::Scalar(i), comparison_result, cv::CMP_EQ); //相等为255不等为0
495   - n_masks.setTo(0, comparison_result); // 将comparison_result中非零区域置为0
496   - cv::bitwise_and(mask_rmlane,n_masks,mask_rmlane);
497   - continue;
498   - }
499   -
500   - cv::Mat region_mask;
501   - cv::bitwise_and(measure_labels,n_masks,measure_labels);/////
502   - cv::compare(measure_labels, i, region_mask, cv::CMP_EQ);
503   -
504   - std::vector<std::vector<cv::Point>> contours;
505   - cv::findContours(region_mask,contours,cv::noArray(),cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
506   - std::vector<cv::Point> contours_poly;
507   - for (int j = 0; j < contours.size();j++) {
508   - cv::approxPolyDP(cv::Mat(contours[j]), contours_poly, 10, true);
509   - if (contours_poly.size() <= 2) continue;
510   - poly_masks.push_back(contours_poly);
511   - region_classes.push_back(cat);
512   - }
513   - }
514   - }
515   - return mask_rmlane;
516   -}
517   -
518 6 RoadSegAnalysis::RoadSegAnalysis(/* args */)
519 7 {
520 8 }
... ... @@ -573,34 +61,91 @@ std::vector&lt;RoadInfo&gt; RoadSegAnalysis::detect(vector&lt;sy_img&gt; vec_img){
573 61  
574 62 for (int b = 0; b < batchsize; b++) {
575 63 auto one_result = results[b];
576   - RoadInfo one_road;
577   - for (size_t i = 0; i < one_result.lane_count; i++)
578   - {
579   - auto one_lane = one_result.reg_array[i];
580   - LineInfo info;
581   - for (size_t j = 0; j < one_lane.num_points; j++)
582   - {
583   - info.vec_pt.push_back(one_lane.points[j]);
584   - }
585   - info.line_type = one_lane.cls;
586   - one_road.vec_line.push_back(info);
587   - }
  64 + RoadInfo one_road = parse_road(one_result, vec_img[b]);
  65 + one_road.vec_direct = parse_direct(one_result, vec_img[b]);
  66 + vec_road.push_back(one_road);
  67 + }
  68 +
  69 + } while (0);
  70 +
  71 + for (int b = 0; b < batchsize; b++) {
  72 + delete[] results[b].seg_array;
  73 + results[b].seg_array = NULL;
  74 + delete[] results[b].direct_seg;
  75 + results[b].direct_seg = NULL;
  76 + }
  77 +
  78 + return vec_road;
  79 +}
  80 +
  81 +RoadInfo RoadSegAnalysis::parse_road(rs_result one_result, sy_img src)
  82 +{
  83 + RoadInfo one_road;
  84 +
  85 + std::vector<std::pair<std::vector<cv::Point>, int>> combined;
  86 + lanes_process(one_result.reg_array, one_result.lane_count, combined);
  87 + std::vector<std::vector<cv::Point>> poly_masks, lanes;
  88 + std::vector<int> region_classes, cats;
  89 + std::map<double, int> x_sort;
  90 + bool large_resolution = false;
  91 + if (src.w_ > 1920) large_resolution = true;
  92 +
  93 + cv::Mat seg_output = seg_post_process(large_resolution, one_result.seg_array, combined, poly_masks, region_classes, lanes, cats, x_sort); //m_masks:mask前的结果 poly_masks后的结果
588 94  
589   - one_road.vec_road = parse_seg(one_result, vec_img[b]);
590   - one_road.direct_mask = parse_direct(one_result, vec_img[b]);
  95 + for (int i = 0; i < lanes.size(); ++i) {
  96 + std::vector<cv::Point> points = lanes[i];
  97 + LineInfo info;
  98 + for (size_t j = 0; j < points.size(); j++)
  99 + {
  100 + sy_point pt;
  101 + pt.x_ = points[j].x;
  102 + pt.y_ = points[j].y;
591 103  
592   - post_direct(one_result, vec_img[b]);
593   -
594   - vec_road.push_back(one_road);
  104 + info.vec_pt.push_back(pt);
595 105 }
  106 + info.line_type = cats[i];
  107 + one_road.vec_line.push_back(info);
  108 + }
  109 +
  110 + for (int i = 0; i < poly_masks.size(); ++i) {
  111 + std::vector<cv::Point> points = poly_masks[i];
  112 + SegInfo seg_info;
  113 + for (int j = 0; j < points.size(); ++j) {
  114 + sy_point pt;
  115 + pt.x_ = points[j].x;
  116 + pt.y_ = points[j].y;
596 117  
597   - } while (0);
  118 + seg_info.vec_pt.push_back(pt);
  119 + }
  120 + seg_info.seg_type = region_classes[i];
  121 + one_road.vec_road.push_back(seg_info);
  122 + }
  123 +}
598 124  
599   - for (int b = 0; b < batchsize; b++) {
600   - delete[] results[b].seg_array;
601   - results[b].seg_array = NULL;
602   - delete[] results[b].direct_seg;
603   - results[b].direct_seg = NULL;
  125 +std::vector<SegInfo> RoadSegAnalysis::parse_direct(rs_result one_result, sy_img src) {
  126 + std::vector<std::pair<std::vector<cv::Point>, int>> combined;
  127 + lanes_process(one_result.reg_array, one_result.lane_count, combined);
  128 + std::vector<std::vector<cv::Point>> poly_masks, lanes;
  129 + std::vector<int> region_classes, cats;
  130 + std::map<double, int> x_sort;
  131 + bool large_resolution = false;
  132 + if (src.w_ > 1920) large_resolution = true;
  133 +
  134 + cv::Mat seg_output = seg_post_process(large_resolution, one_result.direct_seg, combined, poly_masks, region_classes, lanes, cats, x_sort); //m_masks:mask前的结果 poly_masks后的结果
  135 +
  136 + std::vector<SegInfo> vec_road;
  137 + for (int i = 0; i < poly_masks.size(); ++i) {
  138 + std::vector<cv::Point> points = poly_masks[i];
  139 + SegInfo seg_info;
  140 + for (int j = 0; j < points.size(); ++j) {
  141 + sy_point pt;
  142 + pt.x_ = points[j].x;
  143 + pt.y_ = points[j].y;
  144 +
  145 + seg_info.vec_pt.push_back(pt);
  146 + }
  147 + seg_info.seg_type = region_classes[i];
  148 + vec_road.push_back(seg_info);
604 149 }
605 150  
606 151 return vec_road;
... ... @@ -622,95 +167,81 @@ int RoadSegAnalysis::release() {
622 167 return SY_SUCCESS;
623 168 }
624 169  
625   -std::vector<SegInfo> RoadSegAnalysis::parse_seg(rs_result one_result, sy_img src) {
626   - int w = 640;
627   - int h = 360;
628   - float alpha = 0.75;
629   - cv::Mat overlayed_img(cv::Size(w,h), CV_8UC3, cv::Scalar(0, 0, 0));
630   - // 将车道线标签转换为彩色图像
631   - for (int i = 0; i < h; ++i) {
632   - for (int j = 0; j < w; ++j) {
633   - int idx = one_result.seg_array[(i * w + j)];
634   - overlayed_img.at<cv::Vec3b>(i, j)[0] = seg_colors[idx][0]; // R通道;
635   - overlayed_img.at<cv::Vec3b>(i, j)[1] = seg_colors[idx][1]; // G通道
636   - overlayed_img.at<cv::Vec3b>(i, j)[2] = seg_colors[idx][2]; // B通道
637   - }
638   - }
  170 +// head_or_tail 0:车头 1:车尾
  171 +int RoadSegAnalysis::check_reverse_driving(std::vector<SegInfo>& vec_direct, sy_rect src_rc, int src_width, int src_height, int head_or_tail) {
639 172  
640   - cv::resize(overlayed_img, overlayed_img, cv::Size(src.w_,src.h_), 0, 0, cv::INTER_LINEAR);
641   - // 将原始图像和彩色车道线图进行混合
642   - // cv::addWeighted(cvImg, alpha, overlayed_img, 1 - alpha, 0, overlayed_img);
  173 + float scale_w = 640.0 / src_width;
  174 + float scale_h = 360.0 / src_height;
643 175  
644   - float scale_w = src.w_ / 640.0;
645   - float scale_h = src.h_ / 360.0;
646   - std::vector<std::pair<std::vector<cv::Point>, int>> combined;
647   - lanes_process(one_result.reg_array, one_result.lane_count, combined, scale_w, scale_h);
  176 + sy_rect rc;
  177 + rc.left_ = src_rc.left_ * scale_w;
  178 + rc.width_ = src_rc.width_ * scale_w;
  179 + rc.top_ = src_rc.top_ * scale_h;
  180 + rc.height_ = src_rc.height_ * scale_h;
648 181  
649   - std::vector<SegInfo> vec_seg;
650   - for (const auto& lane_info : combined) {
651   - const auto& xys = lane_info.first;
652   - int cls = lane_info.second;
653   - SegInfo info;
654   - info.seg_type = cls;
655   - // cv::Scalar color(lane_colors[cls][0],lane_colors[cls][1],lane_colors[cls][2]);
656   - for (size_t i = 0; i < xys.size(); ++i) {
657   - // cv::line(overlayed_img, xys[i - 1], xys[i], color, 4);
658   - sy_point pt;
659   - pt.x_ = xys[i].x;
660   - pt.y_ = xys[i].y;
661   - info.vec_pt.push_back(pt);
  182 + std::vector<cv::Point> polygon_pts;
  183 + cv::Point pt_lt;
  184 + pt_lt.x = rc.left_;
  185 + pt_lt.y = rc.top_;
  186 + polygon_pts.push_back(pt_lt);
  187 + cv::Point pt_rt;
  188 + pt_rt.x = rc.left_ + rc.width_;
  189 + pt_rt.y = rc.top_;
  190 + polygon_pts.push_back(pt_rt);
  191 + cv::Point pt_rb;
  192 + pt_rb.x = rc.left_ + rc.width_;
  193 + pt_rb.y = rc.top_ + rc.height_;
  194 + polygon_pts.push_back(pt_rb);
  195 + cv::Point pt_lb;
  196 + pt_lb.x = rc.left_;
  197 + pt_lb.y = rc.top_ + rc.height_;
  198 + polygon_pts.push_back(pt_lb);
  199 +
  200 + int coming_count = 0;
  201 + int leaving_count = 0;
  202 + for (size_t i = 0; i < vec_direct.size(); i++) {
  203 + SegInfo& region = vec_direct[i];
  204 + if (region.seg_type == 1) {
  205 + std::vector<cv::Point> vec_pt;
  206 + for (size_t j = 0; j < region.vec_pt.size(); j++) {
  207 + double dist = pointPolygonTest(polygon_pts, cv::Point2f(region.vec_pt[j].x_, region.vec_pt[j].y_), false);
  208 + if (dist > 0) {
  209 + coming_count ++;
  210 + }
  211 + }
  212 + } else if (region.seg_type == 2) {
  213 + std::vector<cv::Point> vec_pt;
  214 + for (size_t j = 0; j < region.vec_pt.size(); j++) {
  215 + double dist = pointPolygonTest(polygon_pts, cv::Point2f(region.vec_pt[j].x_, region.vec_pt[j].y_), false);
  216 + if (dist > 0) {
  217 + leaving_count ++;
  218 + }
  219 + }
662 220 }
663   - vec_seg.push_back(info);
664 221 }
665 222  
666   - return vec_seg;
667   -}
668   -
669   -cv::Mat RoadSegAnalysis::parse_direct(rs_result one_result, sy_img src){
670   - int src_width = src.w_;
671   -
672   - std::vector<std::pair<std::vector<cv::Point>, int>> combined;
673   - lanes_process(one_result.reg_array, one_result.lane_count, combined);
674   - std::vector<std::vector<cv::Point>> poly_masks, lanes, direct_masks, merge_masks;
675   - std::vector<int> region_classes, cats, direct_classes, merge_classes;
676   - cv::Mat background_mask;
677   - std::map<double, int> x_sort;
678   - bool large_resolution = false;
679   - if (src_width > 1920) large_resolution = true;
680   - cv::Mat seg_output = seg_post_process(large_resolution, one_result.seg_array, combined, poly_masks, region_classes, lanes, cats, x_sort, background_mask); //m_masks:mask前的结果 poly_masks后的结果
681   - cv::Mat direct_output = direct_post_process(large_resolution, one_result.direct_seg, direct_masks, direct_classes);
682   -
683   -
684   - // std::vector<std::vector<cv::Point>> direct_masks;
685   - // std::vector<int> direct_classes;
686   - // bool large_resolution = false;
687   - // if (src_width > 1920) large_resolution = true;
688   - // cv::Mat direct_output = direct_post_process(large_resolution, one_result.direct_seg, direct_masks, direct_classes);
689   -
690   - // cv::Mat image(cv::Size(640, 360), CV_8UC3, cv::Scalar(0, 0, 0));
691   - // cv::Mat merge_image = mask_to_rgb(image, direct_output);
692   - // cv::imwrite("direct.jpg", merge_image);
693   -
694   - int direct = direct_output.at<int>(455, 146);
  223 + int direct = 0;
  224 + if(coming_count > 0 && leaving_count > 0) {
  225 + if (coming_count > leaving_count) {
  226 + direct = 1;
  227 + } else {
  228 + direct = 2;
  229 + }
  230 + } else if(coming_count > 0 && leaving_count <= 0) {
  231 + direct = 1;
  232 + } else if(coming_count <= 0 && leaving_count > 0) {
  233 + direct = 2;
  234 + }
695 235  
696   - return direct_output;
697   -}
698 236  
699   -// head_or_tail 0:车头 1:车尾
700   -int RoadSegAnalysis::check_reverse_driving(cv::Mat direct_mask, sy_rect rc, int src_width, int src_height, int head_or_tail) {
701   - // cv::Mat image(cv::Size(640, 360), CV_8UC3, cv::Scalar(0, 0, 0));
702   - // cv::Mat merge_image = mask_to_rgb(image, direct_mask);
703   - // cv::imwrite("direct_mask.jpg", merge_image);
  237 + // int center_x = (rc.left_ + rc.width_ / 2) * scale_w;
  238 + // int center_y = (rc.top_ + rc.height_ / 2) * scale_h;
  239 + // if(center_x < 0 ||center_x >= direct_mask.cols || center_y < 0 || center_y >= direct_mask.rows){
  240 + // return -1;
  241 + // }
704 242  
705   - float scale_w = 640.0 / src_width;
706   - float scale_h = 360.0 / src_height;
707   - int center_x = (rc.left_ + rc.width_ / 2) * scale_w;
708   - int center_y = (rc.top_ + rc.height_ / 2) * scale_h;
709   - if(center_x < 0 ||center_x >= direct_mask.cols || center_y < 0 || center_y >= direct_mask.rows){
710   - return -1;
711   - }
712 243 // '来': 1, '去': 2, '近': 3, '远': 4
713   - int direct = direct_mask.at<int>(center_x, center_y);
  244 + // int direct = direct_mask.at<int>(center_x, center_y);
714 245 if (direct == 1 && head_or_tail == 0) {
715 246 // 来车道,车头,正常行驶
716 247 return 0;
... ... @@ -728,7 +259,16 @@ int RoadSegAnalysis::check_reverse_driving(cv::Mat direct_mask, sy_rect rc, int
728 259 return -1;
729 260 }
730 261  
731   -int RoadSegAnalysis::check_cross_line(std::vector<LineInfo>& vec_line, sy_rect rc) {
  262 +int RoadSegAnalysis::check_cross_line(std::vector<LineInfo>& vec_line, sy_rect src_rc) {
  263 +
  264 + float scale_w = 640.0 / src_rc.width_;
  265 + float scale_h = 360.0 / src_rc.height_;
  266 +
  267 + sy_rect rc;
  268 + rc.left_ = src_rc.left_ * scale_w;
  269 + rc.width_ = src_rc.width_ * scale_w;
  270 + rc.top_ = src_rc.top_ * scale_h;
  271 + rc.height_ = src_rc.height_ * scale_h;
732 272  
733 273 std::vector<cv::Point> polygon_pts;
734 274 cv::Point pt_lt;
... ... @@ -816,7 +356,123 @@ int RoadSegAnalysis::check_cross_region(std::vector&lt;SegInfo&gt;&amp; vec_reg, sy_rect r
816 356 return -1;
817 357 }
818 358  
819   -cv::Mat imshow_lanes(cv::Mat img, const rs_lane* lanes, int lane_count) {
  359 +// cv::Mat imshow_lanes(cv::Mat img, const rs_lane* lanes, int lane_count) {
  360 +// float scale_w = img.cols / 640.0;
  361 +// float scale_h = img.rows / 360.0;
  362 +// std::vector<std::pair<std::vector<cv::Point>, int>> combined;
  363 +// lanes_process(lanes, lane_count, combined, scale_w, scale_h);
  364 +
  365 +// for (const auto& lane_info : combined) {
  366 +// const auto& xys = lane_info.first;
  367 +// int cls = lane_info.second;
  368 +// cv::Scalar color(lane_colors[cls][0],lane_colors[cls][1],lane_colors[cls][2]);
  369 +// for (size_t i = 1; i < xys.size(); ++i) {
  370 +// cv::line(img, xys[i - 1], xys[i], color, 4);
  371 +// }
  372 +// }
  373 +
  374 +// return img;
  375 +// }
  376 +
  377 +// void RoadSegAnalysis::post_direct(rs_result one_result, sy_img src){
  378 +// int src_width = src.w_;
  379 +// int src_height = src.h_;
  380 +// int w = 640;
  381 +// int h = 360;
  382 +// float alpha = 0.75;
  383 +// cv::Mat overlayed_direct_img(cv::Size(w,h), CV_8UC3, cv::Scalar(0, 0, 0));
  384 +// // 将车道线标签转换为彩色图像
  385 +// for (int i = 0; i < h; ++i) {
  386 +// for (int j = 0; j < w; ++j) {
  387 +// int idx = one_result.direct_seg[(i * w + j)];
  388 +// overlayed_direct_img.at<cv::Vec3b>(i, j)[0] = seg_colors[idx][0]; // R通道;
  389 +// overlayed_direct_img.at<cv::Vec3b>(i, j)[1] = seg_colors[idx][1]; // G通道
  390 +// overlayed_direct_img.at<cv::Vec3b>(i, j)[2] = seg_colors[idx][2]; // B通道
  391 +// }
  392 +// }
  393 +// cv::resize(overlayed_direct_img, overlayed_direct_img, cv::Size(src_width,src_height), 0, 0, cv::INTER_LINEAR);
  394 +// // 将原始图像和彩色车道线图进行混合
  395 +// // cv::addWeighted(cvImg, alpha, overlayed_direct_img, 1 - alpha, 0, overlayed_direct_img);
  396 +// cv::Mat img_direct_lane = imshow_lanes(overlayed_direct_img, one_result.reg_array, one_result.lane_count);
  397 +// cv::imwrite("img_direct_lane.jpg", img_direct_lane);
  398 +
  399 +
  400 +// std::vector<std::pair<std::vector<cv::Point>, int>> combined;
  401 +// lanes_process(one_result.reg_array, one_result.lane_count, combined);
  402 +// std::vector<std::vector<cv::Point>> poly_masks, lanes, direct_masks, merge_masks;
  403 +// std::vector<int> region_classes, cats, direct_classes, merge_classes;
  404 +// cv::Mat background_mask;
  405 +// std::map<double, int> x_sort;
  406 +// bool large_resolution = false;
  407 +// if (src_height > 1920) large_resolution = true;
  408 +// cv::Mat seg_output = seg_post_process(large_resolution, one_result.seg_array, combined, poly_masks, region_classes, lanes, cats, x_sort, background_mask); //m_masks:mask前的结果 poly_masks后的结果
  409 +// cv::Mat direct_output = direct_post_process(large_resolution, one_result.direct_seg, direct_masks, direct_classes);
  410 +// cv::Mat merge_output = merge_direct_process(large_resolution, one_result.direct_seg, merge_masks, merge_classes);
  411 +
  412 +// cv::Mat image(cv::Size(w,h), CV_8UC3, cv::Scalar(0, 0, 0));
  413 +// cv::Mat vis_image = mask_to_rgb(image, seg_output);
  414 +// cv::Mat direct_image = mask_to_rgb(image, direct_output);
  415 +// cv::Mat merge_image = mask_to_rgb(image, merge_output);
  416 +// cv::imwrite("vis_image.jpg", vis_image);
  417 +// cv::imwrite("direct_image.jpg", direct_image);
  418 +// cv::imwrite("merge_image.jpg", merge_image);
  419 +// cv::imwrite("background_mask.jpg", background_mask);
  420 +// }
  421 +
  422 +
  423 +cv::Mat RoadSegAnalysis::mask_to_rgb(cv::Mat img, cv::Mat mask) {
  424 + cv::Mat masks = img.clone();
  425 + int reg_cls = 8;
  426 + for (int i = 0; i < masks.rows; i++) {
  427 + for (int j = 0; j < masks.cols; j++) {
  428 + for (int k = 1; k < reg_cls; k++) {
  429 + if (mask.at<int>(i,j) == k) {
  430 + masks.at<cv::Vec3b>(i,j)[0] = seg_colors[k][0];
  431 + masks.at<cv::Vec3b>(i,j)[1] = seg_colors[k][1];
  432 + masks.at<cv::Vec3b>(i,j)[2] = seg_colors[k][2];
  433 + }
  434 + }
  435 + }
  436 + }
  437 + return masks;
  438 +}
  439 +
  440 +float RoadSegAnalysis::contourArea(std::vector<cv::Point> contour, cv::Point2f& center) {
  441 + cv::RotatedRect rect = cv::minAreaRect(contour); // 最小外接矩形 rect[0]中心点 rect[1]宽 高 rect[2]旋转角度
  442 + center = rect.center;
  443 + return cv::contourArea(contour);
  444 +}
  445 +
  446 +void RoadSegAnalysis::lanes_process(const rs_lane* lanes, int lane_count, std::vector<std::pair<std::vector<cv::Point>, int>>& combined, float scale_w, float scale_h) {
  447 + std::vector<std::vector<cv::Point> > lanes_xys;
  448 + std::vector<int> lanes_cls;
  449 + for (int i = 0; i < lane_count; i++) {
  450 + std::vector<cv::Point> xys;
  451 + for (int j = 0; j < lanes[i].num_points; j++) {
  452 + int x = static_cast<int>(lanes[i].points[j].x_ * scale_w);
  453 + int y = static_cast<int>(lanes[i].points[j].y_ * scale_h);
  454 + if (x > 0 && y > 0) {
  455 + xys.emplace_back(x, y);
  456 + }
  457 + }
  458 + if (!xys.empty()) {
  459 + lanes_xys.push_back(xys);
  460 + lanes_cls.push_back(lanes[i].cls);
  461 + }
  462 + }
  463 +
  464 + for (size_t i = 0; i < lanes_xys.size(); ++i) {
  465 + combined.push_back(std::make_pair(lanes_xys[i], lanes_cls[i]));
  466 + }
  467 + if (!combined.empty()) {
  468 + //按车道线起点坐标排序,相应的类别顺序也会变化以保证标签对齐
  469 + std::sort(combined.begin(), combined.end(), [](const std::pair<std::vector<cv::Point>, int>& a, const std::pair<std::vector<cv::Point>, int>& b) {
  470 + return a.first[0].x < b.first[0].x;
  471 + });
  472 + }
  473 +}
  474 +
  475 +cv::Mat RoadSegAnalysis::imshow_lanes(cv::Mat img, const rs_lane* lanes, int lane_count) {
820 476 float scale_w = img.cols / 640.0;
821 477 float scale_h = img.rows / 360.0;
822 478 std::vector<std::pair<std::vector<cv::Point>, int>> combined;
... ... @@ -834,47 +490,145 @@ cv::Mat imshow_lanes(cv::Mat img, const rs_lane* lanes, int lane_count) {
834 490 return img;
835 491 }
836 492  
837   -void RoadSegAnalysis::post_direct(rs_result one_result, sy_img src){
838   - int src_width = src.w_;
839   - int src_height = src.h_;
840   - int w = 640;
841   - int h = 360;
842   - float alpha = 0.75;
843   - cv::Mat overlayed_direct_img(cv::Size(w,h), CV_8UC3, cv::Scalar(0, 0, 0));
844   - // 将车道线标签转换为彩色图像
845   - for (int i = 0; i < h; ++i) {
846   - for (int j = 0; j < w; ++j) {
847   - int idx = one_result.direct_seg[(i * w + j)];
848   - overlayed_direct_img.at<cv::Vec3b>(i, j)[0] = seg_colors[idx][0]; // R通道;
849   - overlayed_direct_img.at<cv::Vec3b>(i, j)[1] = seg_colors[idx][1]; // G通道
850   - overlayed_direct_img.at<cv::Vec3b>(i, j)[2] = seg_colors[idx][2]; // B通道
  493 +int RoadSegAnalysis::Mask2LanePoints(const cv::Mat& pred, std::vector<std::vector<cv::Point>>&lanes, std::vector<int>& cats) {
  494 + std::vector<int> labels = {8, 9, 10, 11};
  495 + for(auto cat: labels) {
  496 + cv::Mat b_masks, measure_labels, stats, centroids;
  497 + cv::compare(pred, cat, b_masks, cv::CMP_EQ); //将pred元素逐个和cat比较,相同255,不同0
  498 + // cv::threshold(pred, b_masks, 126, 255, cv::THRESH_OTSU); //生成二值图
  499 + // 连通域计算 b_masks:闭操作后的二值图像 measure_labels:和原图一样大的标记图 centroids:nccomps×2的矩阵,表示每个连通域的质心(x, y)
  500 + // stats:nccomps×5的矩阵 表示每个连通区域的外接矩形和面积(x, y, w, h, area),索引0是背景信息
  501 + int nccomps = cv::connectedComponentsWithStats (b_masks, measure_labels, stats, centroids, 4); //8
  502 + for(int cv_measure_id = 1; cv_measure_id < nccomps; cv_measure_id++ ) { //跳过背景信息0
  503 + cv::Mat cv_measure_mask;
  504 + cv::compare(measure_labels, cv_measure_id, cv_measure_mask, cv::CMP_EQ);
  505 + std::vector< std::vector< cv::Point> > contours;
  506 + cv::findContours(cv_measure_mask,contours,cv::noArray(),cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
  507 + std::vector<cv::Point> contours_poly;
  508 + for (int j = 0; j < contours.size();j++) {
  509 + float area = cv::contourArea(contours[j]); if (area < 60) continue; //30
  510 + cv::approxPolyDP(cv::Mat(contours[j]), contours_poly, 6, true); //减小epsilon提高拟合精度(需要调试,epsilon过小会使多边形不够简化,单条线变多条)
  511 + if (contours_poly.size() == 1) continue;
  512 + lanes.push_back(contours_poly);
  513 + cats.push_back(cat);
  514 + }
  515 + }
  516 + }
  517 + return 0;
  518 +}
  519 +
  520 +
  521 +cv::Mat RoadSegAnalysis::seg_post_process(bool large_resolution, unsigned char *seg_array, std::vector<std::pair<std::vector<cv::Point>, int>> combined, std::vector<std::vector<cv::Point>> &poly_masks, std::vector<int> &region_classes, std::vector<std::vector<cv::Point>> &lanes, std::vector<int> &cats, std::map<double, int> &x_sort) {
  522 + std::vector<int> pred_cls;
  523 + int h = 360, w = 640;
  524 + cv::Mat lanes_masks = cv::Mat_<int>(h,w); //正常分割结果
  525 + cv::Mat mask_rmlane = cv::Mat_<int>(h,w); //车道线区域置为背景
  526 + cv::Mat solve_masks = cv::Mat_<int>(h,w); //计算主行驶区域用(虚线及减速标线归入行车道)
  527 + int step_size = h*w;
  528 + int seg_min_region_area = 512; //1024
  529 +
  530 + for (int i = 0; i < h; ++i) {
  531 + for (int j = 0; j < w; ++j) {
  532 + int max_cls = seg_array[(i * w + j)];
  533 + lanes_masks.ptr<int>(i)[j] = max_cls;
  534 + pred_cls.push_back(max_cls);
  535 + mask_rmlane.ptr<int>(i)[j] = max_cls;
  536 + solve_masks.ptr<int>(i)[j] = max_cls;
  537 + }
  538 + }
  539 +
  540 + for (const auto& lane_info : combined) {
  541 + const auto& xys = lane_info.first;
  542 + int cls = lane_info.second;
  543 + if (cls == 1) cls = 8; /*黄实线*/ if (cls == 2) cls = 9; /*白实线*/
  544 + if (cls == 3) cls = 10; /*虚线*/ if (cls == 4) cls = 11; /*黄虚线*/
  545 + for (size_t i = 1; i < xys.size(); ++i) {
  546 + cv::line(lanes_masks, xys[i - 1], xys[i], cls, 4); //绘制车道线用于求连通域
  547 + if (cls == 10 || cls == 11) cls = 1; //求主行驶区域时将虚线归入行车道
  548 + cv::line(solve_masks, xys[i - 1], xys[i], cls, 4);
  549 +
851 550 }
852 551 }
853   - cv::resize(overlayed_direct_img, overlayed_direct_img, cv::Size(src_width,src_height), 0, 0, cv::INTER_LINEAR);
854   - // 将原始图像和彩色车道线图进行混合
855   - // cv::addWeighted(cvImg, alpha, overlayed_direct_img, 1 - alpha, 0, overlayed_direct_img);
856   - cv::Mat img_direct_lane = imshow_lanes(overlayed_direct_img, one_result.reg_array, one_result.lane_count);
857   - cv::imwrite("img_direct_lane.jpg", img_direct_lane);
858 552  
  553 + /* 求背景区域--mask车道区域,场景变化用
  554 + cv::compare(lanes_masks, 0, background_mask, cv::CMP_EQ); //将lanes_masks元素逐个和0比较,相同255,不同0*/
  555 +#if 1
  556 + //--mask远处区域------------------------------------------------
  557 + cv::Mat mask_black = mask_rmlane.clone();
  558 + if (large_resolution) mask_black(cv::Rect(0, 0, w, int(h * 0.14))) = 0;
  559 + else mask_black(cv::Rect(0, 0, w, int(h * 0.22))) = 0;
  560 + mask_black(cv::Rect(0, int(h * 0.95), w, int(h * 0.05))) = 0;
  561 + mask_black(cv::Rect(0, 0, int(w * 0.02), h)) = 0;
  562 + mask_black(cv::Rect(int(w * 0.95), 0, int(w * 0.05), h)) = 0;
  563 + mask_rmlane = mask_black;
  564 + //-------------------------------------------------------------------------
  565 +#endif
  566 + //2.去重获取预测到的类别
  567 + std::vector<int> labels(pred_cls);
  568 + std::sort(labels.begin(),labels.end());
  569 + labels.erase(std::unique(labels.begin(),labels.end()),labels.end());
  570 +
  571 + //4.求车道线区域
  572 + int flag = Mask2LanePoints(lanes_masks, lanes, cats); ///////////////////////// 车道线如何与mask结合
  573 +
  574 + //5.求道路区域
  575 + int count = 0;
  576 + for(auto cat: labels) {
  577 + // std::cout << cat << std::endl;
  578 + cv::Mat b_masks, measure_labels, stats, centroids;
  579 + cv::Mat n_masks = cv::Mat_<int>(h,w);
  580 + n_masks = cv::Scalar(255);
  581 + cv::compare(mask_rmlane, cat, b_masks, cv::CMP_EQ); //将mask_rmlane元素逐个和cat比较,相同255,不同0
  582 + //连通域计算
  583 + int nccomps = cv::connectedComponentsWithStats (b_masks, measure_labels, stats, centroids, 8);
  584 + for(int i = 1; i < nccomps; i++ ) { //跳过背景信息0
  585 + //移除过小的区域,并将对应位置置为0
  586 + if (stats.at<int>(i, cv::CC_STAT_AREA) < seg_min_region_area) {
  587 + cv::Mat comparison_result;
  588 + cv::compare(measure_labels, cv::Scalar(i), comparison_result, cv::CMP_EQ); //相等为255不等为0
  589 + n_masks.setTo(0, comparison_result); // 将comparison_result中非零区域置为0
  590 +
  591 + cv::bitwise_and(mask_rmlane,n_masks,mask_rmlane);
  592 + continue;
  593 + }
859 594  
860   - std::vector<std::pair<std::vector<cv::Point>, int>> combined;
861   - lanes_process(one_result.reg_array, one_result.lane_count, combined);
862   - std::vector<std::vector<cv::Point>> poly_masks, lanes, direct_masks, merge_masks;
863   - std::vector<int> region_classes, cats, direct_classes, merge_classes;
864   - cv::Mat background_mask;
865   - std::map<double, int> x_sort;
866   - bool large_resolution = false;
867   - if (src_height > 1920) large_resolution = true;
868   - cv::Mat seg_output = seg_post_process(large_resolution, one_result.seg_array, combined, poly_masks, region_classes, lanes, cats, x_sort, background_mask); //m_masks:mask前的结果 poly_masks后的结果
869   - cv::Mat direct_output = direct_post_process(large_resolution, one_result.direct_seg, direct_masks, direct_classes);
870   - cv::Mat merge_output = merge_direct_process(large_resolution, one_result.direct_seg, merge_masks, merge_classes);
871   -
872   - cv::Mat image(cv::Size(w,h), CV_8UC3, cv::Scalar(0, 0, 0));
873   - cv::Mat vis_image = mask_to_rgb(image, seg_output);
874   - cv::Mat direct_image = mask_to_rgb(image, direct_output);
875   - cv::Mat merge_image = mask_to_rgb(image, merge_output);
876   - cv::imwrite("vis_image.jpg", vis_image);
877   - cv::imwrite("direct_image.jpg", direct_image);
878   - cv::imwrite("merge_image.jpg", merge_image);
879   - cv::imwrite("background_mask.jpg", background_mask);
  595 + double centr_x = centroids.at<double>(i, 0);
  596 + double centr_y = centroids.at<double>(i, 1);
  597 +
  598 + int region_class = cat;
  599 + // printf("region_class: %d\n", region_class);
  600 + cv::Mat region_mask;
  601 + cv::bitwise_and(measure_labels,n_masks,measure_labels);/////
  602 + cv::compare(measure_labels, i, region_mask, cv::CMP_EQ);
  603 +
  604 + std::vector< std::vector< cv::Point> > contours;
  605 + cv::findContours(region_mask,contours,cv::noArray(),cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE);
  606 + std::vector<cv::Point> contours_poly;
  607 + for (int j = 0; j < contours.size();j++) {
  608 + cv::approxPolyDP(cv::Mat(contours[j]), contours_poly, 10, true);
  609 + if (contours_poly.size() <= 2) continue;
  610 + poly_masks.push_back(contours_poly);
  611 + region_classes.push_back(cat);
  612 + if (x_sort.count(centr_x)) centr_x += 0.0001;
  613 + x_sort.insert(std::make_pair(centr_x, count));
  614 + ++ count;
  615 + // for (auto iter: contours_poly) {
  616 + // std::cout << "contour " << iter << " " << cat << std::endl;
  617 + // }
  618 +
  619 + }
  620 + }
  621 + }
  622 +
  623 +#if 0
  624 + //6.draw lanes
  625 + for (int i = 0; i < lanes.size(); ++i) {
  626 + int thickness = 4;
  627 + for (int j = 0; j < lanes[i].size()-1; ++j) {
  628 + cv::line(mask_rmlane, lanes[i][j], lanes[i][j+1], {seg_colors[cats[i]][0],seg_colors[cats[i]][1],seg_colors[cats[i]][2]}, thickness);
  629 + // std::cout << lanes[i][j] << " " << lanes[i][j+1] << " " << cats[i] << std::endl;
  630 + }
  631 + }
  632 +#endif
  633 + return mask_rmlane;
880 634 }
881 635 \ No newline at end of file
... ...
src/ai_engine_module/RoadSegAnalysis.h
... ... @@ -9,8 +9,7 @@ using namespace std;
9 9 struct RoadInfo{
10 10 std::vector<LineInfo> vec_line;
11 11 std::vector<SegInfo> vec_road;
12   -
13   - cv::Mat direct_mask;
  12 + std::vector<SegInfo> vec_direct;
14 13 };
15 14  
16 15 class RoadSegAnalysis
... ... @@ -23,7 +22,7 @@ public:
23 22  
24 23 std::vector<RoadInfo> detect(vector<sy_img> vec_img);
25 24  
26   - int check_reverse_driving(cv::Mat direct_mask, sy_rect rc, int src_width, int src_height, int head_or_tail);
  25 + int check_reverse_driving(std::vector<SegInfo>& vec_direct, sy_rect rc, int src_width, int src_height, int head_or_tail);
27 26  
28 27 int check_cross_line(std::vector<LineInfo>& vec_line, sy_rect rc);
29 28  
... ... @@ -32,11 +31,20 @@ public:
32 31 private:
33 32 int release();
34 33  
35   - std::vector<SegInfo> parse_seg(rs_result one_result, sy_img src);
  34 + RoadInfo parse_road(rs_result one_result, sy_img src);
  35 +
  36 + std::vector<SegInfo> parse_direct(rs_result one_result, sy_img src);
  37 +
  38 + // void post_direct(rs_result one_result, sy_img src);
  39 +
36 40  
37   - cv::Mat parse_direct(rs_result one_result, sy_img src);
  41 + cv::Mat mask_to_rgb(cv::Mat img, cv::Mat mask);
  42 + float contourArea(std::vector<cv::Point> contour, cv::Point2f& center);
  43 + void lanes_process(const rs_lane* lanes, int lane_count, std::vector<std::pair<std::vector<cv::Point>, int>>& combined, float scale_w = 1.0, float scale_h = 1.0);
  44 + cv::Mat imshow_lanes(cv::Mat img, const rs_lane* lanes, int lane_count);
  45 + int Mask2LanePoints(const cv::Mat& pred, std::vector<std::vector<cv::Point>>&lanes, std::vector<int>& cats);
  46 + cv::Mat seg_post_process(bool large_resolution, unsigned char *seg_array, std::vector<std::pair<std::vector<cv::Point>, int>> combined, std::vector<std::vector<cv::Point>> &poly_masks, std::vector<int> &region_classes, std::vector<std::vector<cv::Point>> &lanes, std::vector<int> &cats, std::map<double, int> &x_sort);
38 47  
39   - void post_direct(rs_result one_result, sy_img src);
40 48 private:
41 49 void* m_handle{nullptr};
42 50 aclrtContext ctx{nullptr};
... ...
src/village_inc.h
... ... @@ -36,10 +36,11 @@ typedef struct VehicleInfo {
36 36 manned_result manned_res;
37 37  
38 38 int type;
39   -
  39 +
40 40 int vpt_type;
41 41 int rainshed; //是否安装雨棚, 0 有雨棚 1 无雨棚
42   - int manned;
  42 + int truck_manned;
  43 + int motor_manned;
43 44  
44 45 int human_upper_color;
45 46 int human_lower_color;
... ...