OpenCV繪制圖形功能
本文實例為大傢分享瞭OpenCV繪制圖形功能的具體代碼,供大傢參考,具體內容如下
1、繪制直線
繪制直線函數是cv::line,函數完整形式如下
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0); /* @param img 圖像 @param pt1 線段端點1 @param pt2 線段端點2 @param color 線段顏色 @param thickness 線寬 @param lineType 線的類型 @param shift 點坐標的小數位偏移 */
color可以使用cv::Scalar構造,但是傳入參數的順序是BGR,使用CV_RGB宏更直觀,以RGB順序傳入;
lineType取值有LINE_4、LINE_8和LINE_AA,分別表示4連接線,8連接線,抗鋸齒線,是以不同的算法產生直線(也可以是FILLED=-1,直接填充);
shift是指點坐標的二進制表示的位偏移,每加1坐標值減一半,實驗的結果,不知道理解的對不對,使用默認值0就可以瞭;
在兩個點之間繪制線寬為1的紅色直線定義為一個函數
void DrawLine(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::line(destImg, pt1, pt2, CV_RGB(255, 0, 0), 1); }
下面的實例在鼠標兩次點擊位置中間畫一根直線,繪制完成可以按Enter鍵保存圖像。
cv::Mat g_originImage;//原始圖像 cv::Mat g_editImage;//編輯的圖像 std::vector<cv::Point> g_editPoints;//正在繪制的圖形的點 std::vector<std::vector<cv::Point>> g_lines;//所有的線段 void RedrawAllLines() { g_originImage.copyTo(g_editImage);//恢復背景圖像 for (int i = 0; i < g_lines.size(); i++) { if (g_lines[i].size() >= 2) { DrawLine(g_editImage,g_lines[i][0], g_lines[i][1]); } } } void OnDrawLineMouseEvent(int event, int x, int y, int flags, void* userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { //在第二個點按下鼠標之後添加到線段列表中,並重繪圖像 g_editPoints.push_back(cv::Point(x, y)); g_lines.push_back(g_editPoints); RedrawAllLines(); g_editPoints.clear(); imshow("image", g_editImage); } else { g_editPoints.push_back(cv::Point(x, y));//第一個點 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { //鼠標移動中,繪制到鼠標位置的直線,但鼠標當前點不加入到g_editPoints中 RedrawAllLines(); DrawLine(g_editImage,g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow("image", g_editImage); } } } int main(int argc, char **arv) { g_originImage = cv::imread("walkers.jpg"); g_originImage.copyTo(g_editImage); cv::namedWindow("image"); imshow("image", g_editImage); cv::setMouseCallback("image", OnDrawLineMouseEvent); int key = cv::waitKey(0); while (key != 27) { if (key == 13) { cv::imwrite("testsave.png", g_editImage); } key = cv::waitKey(0); } return 0; }
2、繪制圓
繪制圓的函數cv::circle
void circle(InputOutputArray img, Point center, int radius,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0); /* @param img 圖像 @param center 圓心 @param radius 半徑 @param color 線顏色 @param thickness 線寬,如果小於0則填充圓 @param lineType 線類型 @param shift 圓心和半徑值的位偏移 */
以兩個點畫一個圓,第一個點為圓心,兩點距離為圓半徑,定義為一個函數DrawCircle
void DrawCircle(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::Point deltaPt = pt2 - pt1; float radius = cv::sqrt(deltaPt.x*deltaPt.x + deltaPt.y*deltaPt.y); cv::circle(destImg, pt1, radius, CV_RGB(255, 0, 0), 1); }
以下示例實現鼠標點擊兩次繪制如上的一個圓,main函數與畫直線一樣,隻要將鼠標事件回調改成OnDrawCircleMouseEvent
std::vector<std::vector<cv::Point>> g_circles;//所有的圓 void RedrawAllCircles() { g_originImage.copyTo(g_editImage);//恢復背景圖像 for (int i = 0; i < g_circles.size(); i++) { if (g_circles[i].size() >= 2) { DrawCircle(g_editImage, g_circles[i][0], g_circles[i][1]); } } } void OnDrawCircleMouseEvent(int event, int x, int y, int flags, void* userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); g_circles.push_back(g_editPoints); RedrawAllCircles(); g_editPoints.clear(); imshow("image", g_editImage); } else { g_editPoints.push_back(cv::Point(x, y));//第一個點 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllCircles(); DrawCircle(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow("image", g_editImage); } } }
3、繪制橢圓
繪制橢圓的函數cv::ellipse,有兩種形式,其中一個定義如下
void ellipse(InputOutputArray img, const RotatedRect& box, const Scalar& color,int thickness = 1, int lineType = LINE_8); /* @param img 圖像 @param box 可以調整旋轉角度的矩形 @param color 線顏色 @param thickness 線寬,如果小於0則填充橢圓 @param lineType 線類型 */
以兩個點組成的矩形內畫一個橢圓,定義為函數DrawEllipse,這裡不考慮矩形的旋轉,固定為0
void DrawEllipse(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::Point2f center = cv::Point2f((pt1.x + pt2.x) / 2.0, (pt1.y + pt2.y) / 2.0); cv::Point2f size = cv::Point2f(cv::abs(pt2.x - pt1.x), cv::abs(pt2.y - pt1.y)); cv::ellipse(destImg,cv::RotatedRect(center, size, 0),CV_RGB(255, 0, 0), 1); }
以下示例實現在鼠標兩次點擊位置中間畫一個橢圓,main函數與畫直線一樣,將鼠標事件回調改成OnDrawEllipseMouseEvent
std::vector<std::vector<cv::Point>> g_ellipses;//所有的橢圓 void RedrawAllEllipses() { g_originImage.copyTo(g_editImage);//恢復背景圖像 for (int i = 0; i < g_ellipses.size(); i++) { if (g_ellipses[i].size() >= 2) { DrawEllipse(g_editImage, g_ellipses[i][0], g_ellipses[i][1]); } } } void OnDrawEllipseMouseEvent(int event, int x, int y, int flags, void* userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); g_ellipses.push_back(g_editPoints); RedrawAllEllipses(); g_editPoints.clear(); imshow("image", g_editImage); } else { g_editPoints.push_back(cv::Point(x, y));//第一個點 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllEllipses(); DrawEllipse(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow("image", g_editImage); } } }
4、繪制矩形
繪制矩形的函數cv::rectangle,有兩種形式,其中一個定義如下
void rectangle(InputOutputArray img, Rect rec,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0); /* @param img 圖像 @param rec 矩形坐標 @param color 線顏色 @param thickness 線寬,如果小於0則填充橢圓 @param lineType 線類型 @param shift 點坐標位偏移 */
在兩個點間畫一個矩形,定義為函數DrawRectangle
void DrawRectangle(const cv::Mat& destImg, const cv::Point& pt1, const cv::Point& pt2) { cv::rectangle(destImg, cv::Rect(pt1, pt2), CV_RGB(255, 0, 0), 1); }
以下示例實現在鼠標兩次點擊位置中間畫一個矩形,main函數與畫直線一樣,將鼠標事件回調改成OnDrawRectangleMouseEvent
std::vector<std::vector<cv::Point>> g_rectangles;//所有的矩形 void RedrawAllRectangles() { g_originImage.copyTo(g_editImage);//恢復背景圖像 for (int i = 0; i < g_rectangles.size(); i++) { if (g_rectangles[i].size() >= 2) { DrawRectangle(g_editImage, g_rectangles[i][0], g_rectangles[i][1]); } } } void OnDrawRectangleMouseEvent(int event, int x, int y, int flags, void* userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); g_rectangles.push_back(g_editPoints); RedrawAllRectangles(); g_editPoints.clear(); imshow("image", g_editImage); } else { g_editPoints.push_back(cv::Point(x, y));//第一個點 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllRectangles(); DrawRectangle(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y)); imshow("image", g_editImage); } } }
5、繪制多邊形輪廓
繪制多邊形的函數cv::polylines,有兩種形式,其中一個定義如下
void polylines(InputOutputArray img, InputArrayOfArrays pts,bool isClosed, const Scalar& color,int thickness = 1, int lineType = LINE_8, int shift = 0 ); /* @param img 圖像 @param pts 多邊形坐標數組 @param isClosed 是否繪制閉合多邊形 @param color 線顏色 @param thickness 線寬 @param lineType 線類型 @param shift 點坐標位偏移 */
這裡的pts是一個2維數組,表示多個多邊形,以下分別實現繪制多個多邊形和單個多邊形的函數
void DrawMultiPolys(const cv::Mat& destImg, const std::vector<std::vector<cv::Point>>& points, bool bClose) { cv::polylines(destImg, points, bClose, CV_RGB(255, 0, 0), 1); } void DrawOnePoly(const cv::Mat& destImg, const std::vector<cv::Point>& points,bool bClose) { if (points.size() >= 2) { std::vector<std::vector<cv::Point>> polyPoints; polyPoints.push_back(points); DrawMultiPolys(destImg,polyPoints,bClose); } }
以下示例實現在鼠標多次點擊的位置繪制多邊形,main函數與畫直線一樣,將鼠標事件回調改成OnDrawPolyMouseEvent
std::vector<std::vector<cv::Point>> g_polys;//所有的多邊形 void RedrawAllPolys() { g_originImage.copyTo(g_editImage);//恢復背景圖像 DrawMultiPolys(g_editImage,g_polys,true); } void OnDrawPolyMouseEvent(int event, int x, int y, int flags, void* userdata) { if (event == cv::EVENT_LBUTTONDOWN) { if (g_editPoints.size() > 0) { g_editPoints.push_back(cv::Point(x, y)); RedrawAllPolys(); DrawOnePoly(g_editImage, g_editPoints, false);//正在繪制的多邊形要單獨畫,而且不能閉合 imshow("image", g_editImage); } else { g_editPoints.push_back(cv::Point(x, y));//第一個點 } } else if (event == cv::EVENT_MOUSEMOVE) { if (g_editPoints.size() > 0) { RedrawAllPolys(); DrawOnePoly(g_editImage,g_editPoints,false);//正在繪制的多邊形要單獨畫,而且不能閉合 DrawLine(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y));//繪制一根到鼠標位置的直線 imshow("image", g_editImage); } } else if (event == cv::EVENT_RBUTTONDOWN) { //右鍵按下結束多邊形繪制,加入到g_polys g_polys.push_back(g_editPoints); RedrawAllPolys(); g_editPoints.clear(); cv::imshow("image", g_editImage); } }
6、繪制填充多邊形
繪制填充多邊形函數cv::fillPoly,有兩種形式,其中一個定義如下
void fillPoly(InputOutputArray img, InputArrayOfArrays pts,const Scalar& color, int lineType = LINE_8, int shift = 0,Point offset = Point() ); /* @param img 圖像 @param pts 多邊形坐標數組 @param color 線顏色 @param lineType 線類型 @param shift 點坐標位偏移 @param offset 所有多邊形點的偏移 */
繪制填充多邊形與繪制多邊形輪廓差不多,隻要將polylines換成fillpoly
void DrawMultiPolys(const cv::Mat& destImg, const std::vector<std::vector<cv::Point>>& points) { cv::fillPoly(destImg, points,CV_RGB(255, 0, 0)); } void DrawOnePoly(const cv::Mat& destImg, const std::vector<cv::Point>& points) { if (points.size() >= 2) { std::vector<std::vector<cv::Point>> polyPoints; polyPoints.push_back(points); DrawMultiPolys(destImg,polyPoints); } }
如果將上面的所有功能以一定方式組合起來,就可以在圖像上繪制多種形狀圖形並保存瞭。
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 使用c++實現OpenCV繪制圖形旋轉矩形
- 利用C++ OpenCV 實現從投影圖像恢復仿射特性
- C++ OpenCV繪制幾何圖形
- 使用c++實現OpenCV繪制圓端矩形
- OpenCV繪制圓端矩形的示例代碼