霍夫直线检测及其直线聚类
霍夫直线检测及其直线聚类:
主要流程:
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 }
效果: