霍夫直线检测及其直线聚类

霍夫直线检测及其直线聚类:

 

主要流程:

1、霍夫直线检测;

 

 

 

 

 

 

 

 

 

 

2、霍夫直线聚类; 

 

 

 

 

 代码:

 

  1 #include <opencv2/opencv.hpp>
  2 #include <iostream>
  3 
  4 using namespace cv;
  5 using namespace std;
  6 
  7 
  8 int Rho_max = 500;
  9 void cluster_lines(vector<Vec2f> lines, vector<Vec2f> *lines_center);
 10 
 11 int main()
 12 {
 13     Mat src_img, gray_img;
 14     // Mat src = imread("/home/parobot/Pictures/rgb.jpeg");
 15     // resize(src, src_img, Size(round(1.0*src.cols), round(1.0*src.rows)));
 16     Mat src = imread("../testimg/005.jpg");
 17     //resize(src, src_img, Size(round(0.15*src.cols), round(0.15*src.rows)));
 18     // resize(src, src_img, Size(round(1.0*src.cols), round(1.0*src.rows)));
 19     src_img = src.clone();
 20 
 21     if (src_img.empty())
 22     {
 23         printf("could not load the image...\n");
 24         return -1;
 25     }
 26     namedWindow("原图", WINDOW_AUTOSIZE);
 27     imshow("原图", src_img);
 28     cvtColor(src_img, gray_img, COLOR_BGR2GRAY);
 29 
 30     vector<Mat> channels;
 31     split(src_img, channels);
 32     // imshow("red",   channels.at(2));
 33     // imshow("green", channels.at(1));
 34     // imshow("blue",  channels.at(0));
 35     cout << channels.at(0).size << endl;
 36 
 37     Rho_max = sqrtf(src_img.rows*src_img.rows + src_img.cols*src_img.cols);
 38 
 39     for (int i = 0; i < channels.at(0).rows; i++)
 40     {
 41         for (int j = 0; j < channels.at(0).cols; j++)
 42         {
 43             // 提取红色
 44             // 红色通道值,应该大于其它通道值           
 45             int red = channels.at(2).at<uchar>(i, j) - 30;
 46             if ((red < channels.at(0).at<uchar>(i, j))
 47                 || (red < channels.at(1).at<uchar>(i, j)))
 48             {
 49                 channels.at(0).at<uchar>(i, j) = 0;
 50                 channels.at(1).at<uchar>(i, j) = 0;
 51                 channels.at(2).at<uchar>(i, j) = 0;
 52             }
 53         }
 54     }
 55 
 56     Mat red_line;
 57     merge(channels, red_line);
 58 
 59     // 霍夫直线检测
 60     vector<Vec2f> lines;
 61     HoughLines(channels.at(2), lines, 1, CV_PI / 180, 200, 0, 0);
 62     cout << lines.size() << endl;
 63     for (int i = 0; i < lines.size(); i++)
 64     {
 65         float rho = lines[i][0], theta = lines[i][1];
 66         Point p1, p2;
 67         float a = cos(theta), b = sin(theta);
 68         float x0 = a * rho, y0 = b * rho;
 69         p1.x = cvRound(x0 + 1000 * (-b));
 70         p1.y = cvRound(y0 + 1000 * a);
 71         p2.x = cvRound(x0 - 1000 * (-b));
 72         p2.y = cvRound(y0 - 1000 * a);
 73         line(red_line, p1, p2, Scalar(255, 0, 0), 1, LINE_AA);
 74     }
 75 
 76     // 概率霍夫直线检测
 77     // vector<Vec4i> lines;
 78     // HoughLinesP(channels.at(2), lines, 1, CV_PI/180, 80, 50, 10);
 79     // cout << lines.size() << endl;
 80     // for (int i = 0; i < lines.size(); i ++)
 81     // {
 82     //    Vec4i l = lines[i];
 83     //     line(red_line, Point(l[0],l[1]), Point(l[2], l[3]), Scalar(255, 0, 0), 1, LINE_AA);
 84     // }
 85 
 86     //imwrite("../testimg/result_002.jpg", src_img);
 87 
 88     // 聚类
 89     vector<Vec2f> lines_center;
 90     cluster_lines(lines, &lines_center);
 91     cout << "lines_center.size : " << lines_center.size() << endl;
 92     for (int i = 0; i < lines_center.size(); i++)
 93     {
 94         float rho = lines_center[i][0], theta = lines_center[i][1];
 95         Point p1, p2;
 96         float a = cos(theta), b = sin(theta);
 97         float x0 = a * rho, y0 = b * rho;
 98         p1.x = cvRound(x0 + 1000 * (-b));
 99         p1.y = cvRound(y0 + 1000 * a);
100         p2.x = cvRound(x0 - 1000 * (-b));
101         p2.y = cvRound(y0 - 1000 * a);
102         line(red_line, p1, p2, Scalar(0, 255, 0), 2, LINE_AA);
103         line(src_img, p1, p2, Scalar(0, 255, 0), 2, LINE_AA);
104     }
105     imshow("cluster", red_line);
106     imshow("result", src_img);
107 
108     //imwrite("/home/parobot/Pictures/line/cluster" + Name + ".jpg", red_line);
109     //imwrite("/home/parobot/Pictures/line/result" + Name + ".jpg", src_img);
110 
111     waitKey(0);
112     return 0;
113 }
114 
115 void cluster_lines(vector<Vec2f> lines, vector<Vec2f> *lines_center)
116 {
117     int cluster_num = 1;
118     bool cluster_done = false;
119     vector<Vec2f> center_this;
120     vector<Vec2f> center_best;
121 
122     vector<vector<Vec2f>> center_episode;
123     center_episode.resize(3);
124 
125     while (!cluster_done)
126     {
127         cout << " ================================================ " << endl;
128         cout << "新的一次聚类中心点数量, cluster_num = " << cluster_num << endl;
129         center_this.resize(cluster_num);
130         center_best.resize(cluster_num);
131 
132         float error_min_rec = 0.0;
133         float *error_points= new float[lines.size()];
134         float *error_center= new float[cluster_num];
135         float error_center_sum_min;
136 
137         // 多次聚类取最优
138         int episode_best_index = 0;
139         for (int episode = 0; episode < 3; episode++)
140         {
141             cout << " ------------------------------------------ " << endl;
142             cout << "cluster begin, episode = " << episode << endl;
143             // 初始化:给中心点赋随机值 
144             // for (int i = 0; i < cluster_num; i ++)
145             // {
146             //     unsigned seed = time(0);
147             //     srand(seed);
148             //     int rho = rand()%(Rho_max + 1);
149             //     int angle = rand()%180;
150 
151             //     if (angle > 90)
152             //     {
153             //         center_this[i][0] =  -(float)rho;
154             //     }
155             //     else
156             //     {
157             //         center_this[i][0] =  (float)rho;
158             //     }
159             //     center_this[i][1] =  ((float)angle)*CV_PI/180.0;                
160             // }
161             unsigned seed = time(0);
162             srand(seed);
163             for (int i = 0; i < cluster_num; i++)
164             {
165                 int index = rand() % lines.size();
166                 center_this[i] = lines[index];
167                 cout << "center_this[" << i << "]" << center_this[i] << endl;
168             }
169 
170             // 循环多次,直到聚类中心收敛到稳态
171             bool center_stable = false;
172             int *Point_Belong = new int[lines.size()];
173             int *Center_Points_Num = new int[cluster_num];
174             //while (!center_stable)
175             for (int time = 0; time < 3; time++)
176             {
177                 cout << "update the cluster center ... ... ..." << endl;
178                 // 新一轮聚类的初始化
179                 for (int cj = 0; cj < cluster_num; cj++)
180                 {
181                     Center_Points_Num[cj] = 0.0;
182                 }
183 
184                 // 分类:遍历所有点,判断点归属于哪个中心                
185                 Vec2f *Center_Points_Vaule_Sum= new Vec2f[cluster_num];
186 
187                 for (int pi = 0; pi < lines.size(); pi++)
188                 {
189                     float moni_d0_min, moni_d1_min;
190                     float error_min = 1.0e10;
191                     // 计算中心距离:遍历所有中心点
192                     for (int cj = 0; cj < cluster_num; cj++)
193                     {
194                         // 折算最近方向的距离
195                         float dtheta = fabsf(lines[pi][1] - center_this[cj][1]);
196                         float drho;
197                         if (dtheta > CV_PI*0.5)
198                         {
199                             dtheta = fabsf(CV_PI - dtheta);
200                             drho = fabsf(lines[pi][0] + center_this[cj][0]);
201                         }
202                         else
203                         {
204                             drho = fabsf(lines[pi][0] - center_this[cj][0]);
205                         }
206 
207                         // 计算归一化距离
208                         float d0 = drho / Rho_max;
209                         float d1 = dtheta / (CV_PI*0.5);
210 
211                         float error_cj = sqrtf(d0*d0 + d1 * d1);
212                         if (error_min > error_cj)
213                         {
214                             error_min = error_cj;
215                             Point_Belong[pi] = cj;
216 
217                             moni_d0_min = d0;
218                             moni_d1_min = d1;
219                         }
220                     }
221 
222                     error_points[pi] = error_min;
223 
224                     cout << "d0 = " << moni_d0_min << ", d1 = " << moni_d1_min << endl;
225 
226                     // 计算累加和、个数
227                     Center_Points_Num[Point_Belong[pi]] ++;
228                     // 计算累加和:需要折算
229                     Vec2f re_line = lines[pi];
230                     float theta_err = lines[pi][1] - center_this[Point_Belong[pi]][1];
231                     if (theta_err > CV_PI*0.5)
232                     {
233                         re_line[1] -= CV_PI;
234                         re_line[0] = -lines[pi][0];
235                     }
236                     else if (theta_err < -CV_PI * 0.5)
237                     {
238                         re_line[1] += CV_PI;
239                         re_line[0] = -lines[pi][0];
240                     }
241 
242                     Center_Points_Vaule_Sum[Point_Belong[pi]] += re_line;
243 
244                     // cout << "lines[" << pi << "] " << lines[pi] << endl;
245                     // cout << "Center_Points_Vaule_Sum[" << Point_Belong[pi]<< "] " << Center_Points_Vaule_Sum[Point_Belong[pi]] << endl;
246                 }
247 
248                 // 更新中心点坐标
249                 bool center_change = false;
250                 for (int cj = 0; cj < cluster_num; cj++)
251                 {
252                     cout << "            center_this[" << cj << "] " << center_this[cj] << endl;
253                     cout << "Center_Points_Vaule_Sum[" << cj << "] " << Center_Points_Vaule_Sum[cj] << endl;
254                     cout << "      Center_Points_Num[" << cj << "] " << Center_Points_Num[cj] << endl;
255                     Vec2f center_temp = Center_Points_Vaule_Sum[cj] / Center_Points_Num[cj];
256                     if (center_this[cj] != center_temp)
257                     {
258                         center_change = true;
259                         center_this[cj] = center_temp;
260                     }
261                     cout << "               center_temp " << center_temp << endl;
262 
263                 }
264                 center_stable = !center_change;
265                 delete[]Center_Points_Vaule_Sum; Center_Points_Vaule_Sum = NULL;
266             }
267 
268             cout << "this elipse cluster is done " << center_stable << endl;
269             // 记录本次
270             center_episode[episode] = center_this;
271 
272 
273             // 更新方差            
274             for (int cj = 0; cj < cluster_num; cj++)
275             {
276                 error_center[cj] = 0;
277             }
278             for (int pi = 0; pi < lines.size(); pi++)
279             {
280                 error_center[Point_Belong[pi]] += error_points[pi] * error_points[pi] / Center_Points_Num[Point_Belong[pi]];
281             }
282 
283             // 选择最小方差
284             float error_center_sum = 0;
285             for (int cj = 0; cj < cluster_num; cj++)
286             {
287                 error_center_sum += error_center[cj];
288                 cout << "error_center[" << cj << "] " << error_center[cj] << endl;
289             }
290             if (episode == 0)
291             {
292                 error_center_sum_min = error_center_sum;
293                 episode_best_index = 0;
294             }
295             else
296             {
297                 if (error_center_sum_min < error_center_sum)
298                 {
299                     error_center_sum_min = error_center_sum;
300                     episode_best_index = episode;
301                 }
302             }
303             delete[]Point_Belong; Point_Belong = NULL;
304             delete[]Center_Points_Num; Center_Points_Num = NULL;
305         }
306 
307         center_best = center_episode[episode_best_index];
308 
309         if ((error_center_sum_min / cluster_num) < 0.05)
310         {
311             cluster_done = true;
312         }
313         else
314         {
315             cluster_num++;
316         }
317 
318         cout << "error_center_sum_min = " << error_center_sum_min << ", avg = " << error_center_sum_min / cluster_num << endl;
319         delete[]error_points; error_points = NULL;
320         delete[]error_center; error_center = NULL;
321     }
322 
323     lines_center->resize(center_best.size());
324     (*lines_center) = center_best;
325 
326     for (int i = 0; i < cluster_num; i++)
327     {
328         cout << "center_best[i] " << center_best[i] << endl;
329     }
330 
331 }

 

效果:

 

 

 

 

 

 

posted @ 2023-02-02 11:43  量子与太极  阅读(28)  评论(1编辑  收藏  举报