《图像处理实例》 之 拟合求交点
要求:找出下面图像中三个点的坐标
出处不说明,主要方法介绍
代码:
1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 4 using namespace cv; 5 using namespace std; 6 vector<RotatedRect> Rects; 7 int main(int argc, char** argv) { 8 9 Mat inputImage = imread("laser.png"); 10 Mat gaussImage1, guassImage2; 11 cvtColor(inputImage, inputImage, COLOR_BGR2GRAY); 12 //------------------------防止光照和斑点的干扰--------------------// 13 GaussianBlur(inputImage, gaussImage1, Size(3, 3), 0, 0, 4); 14 GaussianBlur(inputImage, guassImage2, Size(5, 5), 0, 0, 4); 15 absdiff(gaussImage1, guassImage2, inputImage); 16 threshold(inputImage, inputImage, 5, 255, THRESH_BINARY); 17 Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1)); 18 morphologyEx(inputImage, inputImage, MORPH_CLOSE, kernel); 19 morphologyEx(inputImage, inputImage, MORPH_OPEN, kernel); 20 //----------------------查找最合适的两条线--=------------------------// 21 //***********先用轮廓检测 22 //***********最小外接矩形 23 //***********找到最合适的两个外接矩形,其中这两个矩形的长宽中一个值为最大的// 24 vector<vector<Point>> contours; 25 vector<Vec4i> hierarchy; 26 findContours(inputImage, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1)); 27 28 for (size_t i = 0; i < contours.size(); i++)//找合适的轮廓 29 { 30 RotatedRect Rect; 31 double minLH; 32 Rects.push_back(minAreaRect(contours[i])); 33 if (Rects.size() == 3) 34 { 35 vector<double> num; 36 for (size_t i = 0; i < 3; i++) 37 { 38 num.push_back(max(Rects[i].size.height, Rects[i].size.width)); 39 } 40 minLH = min(min(num[0], num[1]), num[2]); 41 vector<RotatedRect>::iterator it = Rects.begin(); 42 for (size_t i = 0; i < 3; i++,it++) 43 { 44 if (minLH == num[i]) Rects.erase(it); 45 break; 46 } 47 } 48 } 49 Mat showImage1 = Mat::zeros(inputImage.size(), CV_8UC3); 50 vector<Vec4f> lines; 51 for (size_t i = 0; i < contours.size(); i++)//拟合合适的直线 52 { 53 RotatedRect Rect = minAreaRect(contours[i]); 54 double maxHL = max(Rect.size.height, Rect.size.width); 55 double maxHLR = max(Rects[0].size.height, Rects[0].size.width); 56 double maxHLL = max(Rects[1].size.height, Rects[1].size.width); 57 Vec4f line; 58 if (maxHL == maxHLR || maxHL == maxHLL) 59 { 60 drawContours(showImage1, contours, static_cast<int>(i), Scalar(255, 0, 0), 1); 61 fitLine(contours[i], line, cv::DIST_L2, 0, 1e-2, 1e-2); 62 lines.push_back(line); 63 } 64 } 65 Mat showImage = Mat::zeros(inputImage.size(), CV_8UC3); 66 //获取点斜式的点和斜率 67 Point point0; 68 point0.x = lines[0][2]; 69 point0.y = lines[0][3]; 70 71 double k = lines[0][1] / lines[0][0]; 72 73 //计算直线的端点(y = k(x - x0) + y0) 74 Point point1, point2; 75 point1.x = 0; 76 point1.y = k * (0 - point0.x) + point0.y; 77 point2.x = 640; 78 point2.y = k * (640 - point0.x) + point0.y; 79 double b0 = point0.y - k * point0.x; 80 line(showImage, point1, point2, cv::Scalar(0, 255, 0), 1, 8, 0); 81 82 //获取点斜式的点和斜率 83 Point point3; 84 point3.x = lines[1][2]; 85 point3.y = lines[1][3]; 86 87 double k1 = lines[1][1] / lines[1][0]; 88 89 //计算直线的端点(y = k(x - x0) + y0) 90 Point point4, point5; 91 point4.x = 100; 92 point4.y = k1 * (100 - point3.x) + point3.y; 93 double b1 = point3.y - k1 * point3.x; 94 line(showImage, point3, point4, cv::Scalar(0, 0, 255), 1, 8, 0); 95 96 //----求直线交点 97 Point2f center; 98 center.x = (b1 - b0) / (k - k1); 99 center.y = k1 * center.x + b1; 100 char countText[50];//定义数组长度的时候千万多比实际使用多一点,不然就一直崩溃!!! 101 sprintf(countText, "Corn x is : %d", static_cast<int>(center.x)); 102 putText(showImage, countText, Point(30, 30), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 255, 255), 2, 6); 103 char countText1[50];//定义数组长度的时候千万多比实际使用多一点,不然就一直崩溃!!! 104 sprintf(countText1, "Corn y is : %d", static_cast<int>(center.y)); 105 putText(showImage, countText1, Point(30, 100), FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 255, 255), 2, 6); 106 //----------------------拟合中间的直线,然后进行两条直线的焦点-----------------// 107 //*******y = tan(angle)*x +b 108 //*******先求k 和 b 109 //*******直接利用交点公式计算 x = (b[1]-b[0])/(k[1]-k[0]) , y = k[1] * x + b[1] 110 /* 111 double k[2], b[2]; 112 Point center; 113 k[0] = tan(Rects[0].angle); 114 k[1] = tan(Rects[1].angle); 115 b[0] = Rects[0].center.y - k[0] * Rects[0].center.x; 116 b[1] = Rects[1].center.y - k[1] * Rects[1].center.x; 117 CV_Assert(abs(k[1] - k[0]) == 0); 118 center.x = (b[1] - b[0]) / (k[1] - k[0]); 119 center.y = k[1] * center.x + b[1]; 120 */ 121 /* 122 Mat showImage; 123 showImage.create(inputImage.size(), inputImage.type()); 124 vector<Vec4i> lines; 125 HoughLinesP(inputImage, lines, 1, CV_PI / 180, 50, 10, 5); 126 for (size_t i = 0; i < lines.size(); i++) 127 { 128 Vec4i l; 129 l = lines[i]; 130 line(showImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(100, 255, 200), 1, LINE_AA); 131 } 132 */ 133 waitKey(0); 134 }
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/core/core.hpp> 3 #include <iostream> 4 #include <vector> 5 using namespace std; 6 using namespace cv; 7 int count_Judge[2] = {0,0}; 8 /** 9 * @brief 对输入图像进行细化 10 * @param src为输入图像,用cvThreshold函数处理过的8位灰度图像格式,元素中只有0与1,1代表有元素,0代表为空白 11 * @param maxIterations限制迭代次数,如果不进行限制,默认为-1,代表不限制迭代次数,直到获得最终结果 12 * @return 为对src细化后的输出图像,格式与src格式相同,元素中只有0与1,1代表有元素,0代表为空白 13 */ 14 Mat thinImage(const cv::Mat & src, const int maxIterations = -1) 15 { 16 assert(src.type() == CV_8UC1); 17 cv::Mat dst; 18 int width = src.cols; 19 int height = src.rows; 20 src.copyTo(dst); 21 int count = 0; //记录迭代次数 22 while (true) 23 { 24 count++; 25 if (maxIterations != -1 && count > maxIterations) //限制次数并且迭代次数到达 26 break; 27 std::vector<uchar *> mFlag; //用于标记需要删除的点 28 //对点标记 29 for (int i = 0; i < height; ++i) 30 { 31 uchar * p = dst.ptr<uchar>(i); 32 for (int j = 0; j < width; ++j) 33 { 34 //如果满足四个条件,进行标记 35 // p9 p2 p3 36 // p8 p1 p4 37 // p7 p6 p5 38 uchar p1 = p[j]; 39 if (p1 != 1) continue; 40 uchar p4 = (j == width - 1) ? 0 : *(p + j + 1); 41 uchar p8 = (j == 0) ? 0 : *(p + j - 1); 42 uchar p2 = (i == 0) ? 0 : *(p - dst.step + j); 43 uchar p3 = (i == 0 || j == width - 1) ? 0 : *(p - dst.step + j + 1); 44 uchar p9 = (i == 0 || j == 0) ? 0 : *(p - dst.step + j - 1); 45 uchar p6 = (i == height - 1) ? 0 : *(p + dst.step + j); 46 uchar p5 = (i == height - 1 || j == width - 1) ? 0 : *(p + dst.step + j + 1); 47 uchar p7 = (i == height - 1 || j == 0) ? 0 : *(p + dst.step + j - 1); 48 if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6) 49 { 50 int ap = 0; 51 if (p2 == 0 && p3 == 1) ++ap; 52 if (p3 == 0 && p4 == 1) ++ap; 53 if (p4 == 0 && p5 == 1) ++ap; 54 if (p5 == 0 && p6 == 1) ++ap; 55 if (p6 == 0 && p7 == 1) ++ap; 56 if (p7 == 0 && p8 == 1) ++ap; 57 if (p8 == 0 && p9 == 1) ++ap; 58 if (p9 == 0 && p2 == 1) ++ap; 59 60 if (ap == 1 && p2 * p4 * p6 == 0 && p4 * p6 * p8 == 0) 61 { 62 //标记 63 mFlag.push_back(p + j); 64 } 65 } 66 } 67 } 68 69 //将标记的点删除 70 for (std::vector<uchar *>::iterator i = mFlag.begin(); i != mFlag.end(); ++i) 71 { 72 **i = 0; 73 } 74 75 //直到没有点满足,算法结束 76 if (mFlag.empty()) 77 { 78 break; 79 } 80 else 81 { 82 mFlag.clear();//将mFlag清空 83 } 84 85 //对点标记 86 for (int i = 0; i < height; ++i) 87 { 88 uchar * p = dst.ptr<uchar>(i); 89 for (int j = 0; j < width; ++j) 90 { 91 //如果满足四个条件,进行标记 92 // p9 p2 p3 93 // p8 p1 p4 94 // p7 p6 p5 95 uchar p1 = p[j]; 96 if (p1 != 1) continue; 97 uchar p4 = (j == width - 1) ? 0 : *(p + j + 1); 98 uchar p8 = (j == 0) ? 0 : *(p + j - 1); 99 uchar p2 = (i == 0) ? 0 : *(p - dst.step + j); 100 uchar p3 = (i == 0 || j == width - 1) ? 0 : *(p - dst.step + j + 1); 101 uchar p9 = (i == 0 || j == 0) ? 0 : *(p - dst.step + j - 1); 102 uchar p6 = (i == height - 1) ? 0 : *(p + dst.step + j); 103 uchar p5 = (i == height - 1 || j == width - 1) ? 0 : *(p + dst.step + j + 1); 104 uchar p7 = (i == height - 1 || j == 0) ? 0 : *(p + dst.step + j - 1); 105 106 if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) >= 2 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) <= 6) 107 { 108 int ap = 0; 109 if (p2 == 0 && p3 == 1) ++ap; 110 if (p3 == 0 && p4 == 1) ++ap; 111 if (p4 == 0 && p5 == 1) ++ap; 112 if (p5 == 0 && p6 == 1) ++ap; 113 if (p6 == 0 && p7 == 1) ++ap; 114 if (p7 == 0 && p8 == 1) ++ap; 115 if (p8 == 0 && p9 == 1) ++ap; 116 if (p9 == 0 && p2 == 1) ++ap; 117 118 if (ap == 1 && p2 * p4 * p8 == 0 && p2 * p6 * p8 == 0) 119 { 120 //标记 121 mFlag.push_back(p + j); 122 } 123 } 124 } 125 } 126 127 //将标记的点删除 128 for (std::vector<uchar *>::iterator i = mFlag.begin(); i != mFlag.end(); ++i) 129 { 130 **i = 0; 131 } 132 133 //直到没有点满足,算法结束 134 if (mFlag.empty()) 135 { 136 break; 137 } 138 else 139 { 140 mFlag.clear();//将mFlag清空 141 } 142 } 143 return dst; 144 } 145 void FindLine(InputArray _src, vector<Point2f>& lines, uchar method, uchar angle, double& b); 146 147 int main(int argc, char*argv[]) { 148 149 Mat inputImage = cv::imread("1.png"); 150 Mat src; 151 cvtColor(inputImage, src, COLOR_BGR2GRAY); 152 if (src.empty()) 153 { 154 std::cout << "读取文件失败!" << std::endl; 155 return -1; 156 } 157 158 //将原图像转换为二值图像 159 threshold(src, src, 0, 1, THRESH_BINARY | THRESH_OTSU); 160 //图像细化 161 src = thinImage(src); 162 //显示图像 163 src = src * 255; 164 Mat kernel = getStructuringElement(MORPH_RECT, Size(2, 1)); 165 morphologyEx(src, src, MORPH_OPEN, kernel); 166 vector<Point2f> lines2; 167 double b2; 168 FindLine(src, lines2, 2, 0, b2); 169 170 171 vector<Point2f> lines; 172 double b; 173 FindLine(src, lines, 0, 0, b); 174 175 176 vector<Point2f> lines1; 177 double b1; 178 FindLine(src, lines1, 1, 0, b1); 179 180 181 Mat showImage; 182 cvtColor(src, showImage, COLOR_GRAY2BGR); 183 line(showImage, lines2[0], lines2[1], Scalar(0, 0, 255), 1); 184 line(showImage, lines[0], lines[1], Scalar(0, 0, 255), 1); 185 line(showImage, lines1[0], lines1[1], Scalar(0, 0, 255), 1); 186 187 waitKey(0); 188 } 189 //---------------------------------------有角度,通过寻找一个点换算直线--------------------------------------------// 190 //-------@_src : input a image that Binary 191 //-------@lines : output lines message, y = kx + b ,lines[0] stand for k ,lines[1] stand for b 192 //-------@method : if method == 0 return left lines, method == 1 return right lines, else return horizon lines 193 // default method == 0 194 //-------@angle : if angle == true angle = 60 degree, else angle = 45 degree.default angle == true 195 void FindLine(InputArray _src, vector<Point2f>& lines, uchar method, uchar angle, double& b) 196 { 197 Mat src = _src.getMat(); 198 CV_Assert(src.depth() != 1); 199 double k = 0;//y = kx + b 200 Point2f aimPoint[3];//aimPoint[0]/aimPoint[1]存储查询的点,防止误判, aimPoint[3]:直线另一个点 201 if (method == 0) 202 { 203 204 for (size_t i = 0; i < src.rows; i++) 205 { 206 for (size_t j = 0; j < src.cols; j++) 207 { 208 //Point2f tempPoint(j, i); 209 //aimPoint = src.at<uchar>(i, j) > 0 ? tempPoint : aimPoint; 210 if (src.at<uchar>(i, j) > 0) 211 { 212 aimPoint[0] = aimPoint[1]; 213 aimPoint[1] = Point2f(j, i); 214 215 break; 216 } 217 218 } 219 } 220 } 221 else if (method == 1) 222 { 223 char flag[2] = { 0 ,0 }; 224 for (size_t i = 0; i < src.rows; i++) 225 { 226 for (size_t j = 0; j < src.cols; j++) 227 { 228 if (src.at<uchar>(i, src.cols - j - 1) > 0) 229 { 230 aimPoint[0] = aimPoint[1]; 231 aimPoint[1] = Point2f(src.cols - j - 1, i); 232 break; 233 } 234 } 235 } 236 } 237 else 238 { 239 int count[2]; 240 int a = 0, b = 0; 241 for (size_t i = 0; i < src.rows; i++) 242 { 243 for (size_t j = 0; j < src.cols; j++) 244 { 245 if (src.at<uchar>(i, j) > 0) 246 { 247 count[0]++; 248 } 249 //count[0] = src.at<uchar>(i, j) > 0 ? count[0]++ : count[0]; 250 } 251 if (count[0] > count[1]) 252 { 253 aimPoint[1] = Point2f(0, i); 254 aimPoint[0] = Point2f(0, i); 255 count[1] = count[0]; 256 } 257 count[0] = 0; 258 } 259 } 260 //------------防止误判 261 //if (abs(aimPoint[0].x - aimPoint[1].x) > 3) aimPoint[1] = aimPoint[0]; 262 count_Judge[0] = 0; 263 count_Judge[1] = 0; 264 for (size_t i = 0; i < src.cols; i++) 265 { 266 count_Judge[0] += src.at<uchar>(aimPoint[0].y, i) > 0 ? 1 : 0; 267 } 268 for (size_t i = 0; i < src.cols; i++) 269 { 270 count_Judge[1] += src.at<uchar>(aimPoint[0].y, i) > 0 ? 1 : 0; 271 } 272 if (count_Judge[0] >= count_Judge[1] || abs(aimPoint[0].y - aimPoint[1].y) > 2) aimPoint[1] = aimPoint[0]; 273 lines.push_back(aimPoint[1]); 274 if (angle == 0) 275 { 276 if (method == 0) 277 { 278 b = aimPoint[1].y - sqrt(3) * aimPoint[1].x / 3; 279 aimPoint[2] = Point2f(0, sqrt(3) * 0 + b); 280 } 281 else if (method == 1) 282 { 283 b = aimPoint[1].y + sqrt(3)*aimPoint[1].x / 3; 284 aimPoint[2] = Point2f(src.cols, (b / sqrt(3)) / 3); 285 } 286 else 287 { 288 b = aimPoint[1].y; 289 aimPoint[2] = Point2f(src.cols, b); 290 } 291 } 292 else if (angle == 1) 293 { 294 if (method == 0) 295 { 296 b = aimPoint[1].y - aimPoint[1].x; 297 aimPoint[2] = Point2f(0, 0 + b); 298 } 299 else if (method == 1) 300 { 301 b = aimPoint[1].y + aimPoint[1].x; 302 aimPoint[2] = Point2f(src.cols, b / (1)); 303 } 304 else 305 { 306 b = aimPoint[1].y; 307 aimPoint[2] = Point2f(src.cols, b); 308 } 309 } 310 else if (angle == 1) 311 { 312 if (method == 0) 313 { 314 b = aimPoint[1].y - sqrt(3)*aimPoint[1].x; 315 aimPoint[2] = Point2f(0, sqrt(3) * 0 + b); 316 } 317 else if (method == 1) 318 { 319 b = aimPoint[1].y + sqrt(3)*aimPoint[1].x; 320 aimPoint[2] = Point2f(src.cols, b / sqrt(3)); 321 } 322 else 323 { 324 b = aimPoint[1].y; 325 aimPoint[2] = Point2f(src.cols, b); 326 } 327 } 328 lines.push_back(aimPoint[2]); 329 }
作者:影醉阏轩窗
-------------------------------------------
个性签名:衣带渐宽终不悔,为伊消得人憔悴!
如果觉得这篇文章对你有小小的帮助的话,记得关注再下的公众号,同时在右下角点个“推荐”哦,博主在此感谢!