Halcon例項轉OpenCV:計算回形針方向
阿新 • • 發佈:2020-08-16
Halcon中有一個計算回形針方向的例項clip.hdev,可以在例程中找到。原圖如下:
處理後的結果圖:
程式碼整理之後,核心部分如下:
dev_close_window () dev_open_window (0, 0, 700, 700, 'black', WindowHandle) dev_clear_window () dev_set_color ('green') read_image(Image, 'clip') threshold(Image, Region, 0, 56) connection(Region, ConnectedRegions) select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 3161.4, 6315.4) orientation_region(SelectedRegions, Phi) area_center(SelectedRegions, Area, Row, Column) query_font (WindowHandle, Font) *FontWithSize := Font[0]+'-18' *set_font(WindowHandle, FontWithSize) set_display_font (WindowHandle, 15, 'mono', 'true', 'true') Length := 80 for index := 0 to |Phi|-1 by 1 set_tposition(WindowHandle, Row[index], Column[index]) dev_set_color ('black') write_string(WindowHandle, deg(Phi[index])$'3.1f' + 'deg') dev_set_color ('blue') dev_set_line_width(3) disp_arrow(WindowHandle, Row[index], Column[index],Row[index]-Length*sin(Phi[index]), Column[index]+Length*cos(Phi[index]), 4) endfor
思路步驟:
①讀取影象
② 二值化
③ 根據面積剔除非回形針的region
④ 計算每個region的方向和中心
⑤ 結果輸出
轉到OpenCV時,主要有幾個小問題需要理清:
①輪廓的方向怎麼計算?直線擬合?還是計算輪廓中心和回形針端點來算角度?
② 回形針的端點座標如何計算?
③ 繪製箭頭?
如下是OpenCV實現的部分程式碼和效果圖:
void drawArrow(cv::Mat& img, cv::Point pStart, cv::Point pEnd, int len, int alpha, cv::Scalar& color, int thickness, int lineType) { //const double PI = 3.1415926; Point arrow; //計算 θ 角(最簡單的一種情況在下面圖示中已經展示,關鍵在於 atan2 函式,詳情見下面) double angle = atan2((double)(pStart.y - pEnd.y), (double)(pStart.x - pEnd.x)); line(img, pStart, pEnd, color, thickness, lineType); //計算箭角邊的另一端的端點位置(上面的還是下面的要看箭頭的指向,也就是pStart和pEnd的位置) arrow.x = pEnd.x + len * cos(angle + PI * alpha / 180); arrow.y = pEnd.y + len * sin(angle + PI * alpha / 180); line(img, pEnd, arrow, color, thickness, lineType); arrow.x = pEnd.x + len * cos(angle - PI * alpha / 180); arrow.y = pEnd.y + len * sin(angle - PI * alpha / 180); line(img, pEnd, arrow, color, thickness, lineType); } double CalLineAngle(Point &ptStart, Point &ptEnd) { double angle = 0.0; if (ptStart.x == ptEnd.x) angle = 90; else if (ptStart.y == ptEnd.y) angle = 0; else { angle = atan(double(ptEnd.y - ptStart.y) / (ptEnd.x - ptStart.x)) * (180 / PI); if (angle < 0) angle = abs(angle); else if (angle > 0) angle = 180 - angle; if (ptEnd.y - ptStart.y > 0 && ptEnd.x - ptStart.x) angle = angle - 180; } return angle; } int main() { Mat img = imread("./clip.png"); if (img.empty()) { cout << "Read image error, please check again!" << endl; return 1; } imshow("src", img); Mat gray; cvtColor(img, gray, CV_BGR2GRAY); threshold(gray, gray, 85, 255, CV_THRESH_BINARY_INV); //二值化 imshow("threshold", gray); vector<vector<Point>> contours; vector<Vec4i> hierarcy; findContours(gray, contours, hierarcy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); cout << "num=" << contours.size() << endl; vector<Rect> boundRect(contours.size()); //定義外接矩形集合 vector<RotatedRect> box(contours.size()); //定義最小外接矩形集合 Point2f rect[4]; for (int i = 0; i<contours.size(); i++) { box[i] = minAreaRect(Mat(contours[i])); //計算每個輪廓最小外接矩形 //boundRect[i] = boundingRect(Mat(contours[i])); if (box[i].size.width < 50 || box[i].size.height < 50) continue; ...... }
二值化效果:
結果圖:
完整程式碼與素材將釋出在知識星球主題中,歡迎關注公眾號:OpenCV與AI深度學習