欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV繪制圖形功能

 更新時(shí)間:2022年01月19日 11:54:58   作者:蓬?蒿?人  
這篇文章主要為大家詳細(xì)介紹了OpenCV繪制圖形功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了OpenCV繪制圖形功能的具體代碼,供大家參考,具體內(nèi)容如下

1、繪制直線

繪制直線函數(shù)是cv::line,函數(shù)完整形式如下

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 線段端點(diǎn)1
@param pt2 線段端點(diǎn)2
@param color 線段顏色
@param thickness 線寬
@param lineType 線的類型
@param shift 點(diǎn)坐標(biāo)的小數(shù)位偏移
*/

color可以使用cv::Scalar構(gòu)造,但是傳入?yún)?shù)的順序是BGR,使用CV_RGB宏更直觀,以RGB順序傳入;

lineType取值有LINE_4、LINE_8和LINE_AA,分別表示4連接線,8連接線,抗鋸齒線,是以不同的算法產(chǎn)生直線(也可以是FILLED=-1,直接填充);

shift是指點(diǎn)坐標(biāo)的二進(jìn)制表示的位偏移,每加1坐標(biāo)值減一半,實(shí)驗(yàn)的結(jié)果,不知道理解的對(duì)不對(duì),使用默認(rèn)值0就可以了;

在兩個(gè)點(diǎn)之間繪制線寬為1的紅色直線定義為一個(gè)函數(shù)

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);
}

下面的實(shí)例在鼠標(biāo)兩次點(diǎn)擊位置中間畫一根直線,繪制完成可以按Enter鍵保存圖像。

cv::Mat g_originImage;//原始圖像
cv::Mat g_editImage;//編輯的圖像
std::vector<cv::Point> g_editPoints;//正在繪制的圖形的點(diǎn)
std::vector<std::vector<cv::Point>> g_lines;//所有的線段
?
void RedrawAllLines()
{
? ? g_originImage.copyTo(g_editImage);//恢復(fù)背景圖像
? ? 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è)點(diǎn)按下鼠標(biāo)之后添加到線段列表中,并重繪圖像
? ? ? ? ? ? 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));//第一個(gè)點(diǎn)
? ? ? ? }
? ? }
? ? else if (event == cv::EVENT_MOUSEMOVE)
? ? {
? ? ? ? if (g_editPoints.size() > 0)
? ? ? ? {
? ? ? ? ? ? //鼠標(biāo)移動(dòng)中,繪制到鼠標(biāo)位置的直線,但鼠標(biāo)當(dāng)前點(diǎn)不加入到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、繪制圓

繪制圓的函數(shù)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 圓心和半徑值的位偏移
*/

以兩個(gè)點(diǎn)畫一個(gè)圓,第一個(gè)點(diǎn)為圓心,兩點(diǎn)距離為圓半徑,定義為一個(gè)函數(shù)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);
}

以下示例實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊兩次繪制如上的一個(gè)圓,main函數(shù)與畫直線一樣,只要將鼠標(biāo)事件回調(diào)改成OnDrawCircleMouseEvent

std::vector<std::vector<cv::Point>> g_circles;//所有的圓
?
void RedrawAllCircles()
{
? ? g_originImage.copyTo(g_editImage);//恢復(fù)背景圖像
? ? 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));//第一個(gè)點(diǎn)
? ? ? ? }
? ? }
? ? 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、繪制橢圓

繪制橢圓的函數(shù)cv::ellipse,有兩種形式,其中一個(gè)定義如下

void ellipse(InputOutputArray img, const RotatedRect& box, const Scalar& color,int thickness = 1, int lineType = LINE_8);
/*
@param img 圖像
@param box 可以調(diào)整旋轉(zhuǎn)角度的矩形
@param color 線顏色
@param thickness 線寬,如果小于0則填充橢圓
@param lineType 線類型
*/

以兩個(gè)點(diǎn)組成的矩形內(nèi)畫一個(gè)橢圓,定義為函數(shù)DrawEllipse,這里不考慮矩形的旋轉(zhuǎn),固定為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);
}

以下示例實(shí)現(xiàn)在鼠標(biāo)兩次點(diǎn)擊位置中間畫一個(gè)橢圓,main函數(shù)與畫直線一樣,將鼠標(biāo)事件回調(diào)改成OnDrawEllipseMouseEvent

std::vector<std::vector<cv::Point>> g_ellipses;//所有的橢圓
void RedrawAllEllipses()
{
? ? g_originImage.copyTo(g_editImage);//恢復(fù)背景圖像
? ? 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));//第一個(gè)點(diǎn)
? ? ? ? }
? ? }
? ? 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、繪制矩形

繪制矩形的函數(shù)cv::rectangle,有兩種形式,其中一個(gè)定義如下

void rectangle(InputOutputArray img, Rect rec,const Scalar& color, int thickness = 1,int lineType = LINE_8, int shift = 0);
/*
@param img 圖像
@param rec 矩形坐標(biāo)
@param color 線顏色
@param thickness 線寬,如果小于0則填充橢圓
@param lineType 線類型
@param shift ?點(diǎn)坐標(biāo)位偏移
*/

在兩個(gè)點(diǎn)間畫一個(gè)矩形,定義為函數(shù)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);
}

以下示例實(shí)現(xiàn)在鼠標(biāo)兩次點(diǎn)擊位置中間畫一個(gè)矩形,main函數(shù)與畫直線一樣,將鼠標(biāo)事件回調(diào)改成OnDrawRectangleMouseEvent

?std::vector<std::vector<cv::Point>> g_rectangles;//所有的矩形
void RedrawAllRectangles()
{
? ? g_originImage.copyTo(g_editImage);//恢復(fù)背景圖像
? ? 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));//第一個(gè)點(diǎn)
? ? ? ? }
? ? }
? ? 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、繪制多邊形輪廓

繪制多邊形的函數(shù)cv::polylines,有兩種形式,其中一個(gè)定義如下

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 多邊形坐標(biāo)數(shù)組
@param isClosed 是否繪制閉合多邊形
@param color 線顏色
@param thickness 線寬
@param lineType 線類型
@param shift ?點(diǎn)坐標(biāo)位偏移
*/

這里的pts是一個(gè)2維數(shù)組,表示多個(gè)多邊形,以下分別實(shí)現(xiàn)繪制多個(gè)多邊形和單個(gè)多邊形的函數(shù)

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);
? ? }
}

以下示例實(shí)現(xiàn)在鼠標(biāo)多次點(diǎn)擊的位置繪制多邊形,main函數(shù)與畫直線一樣,將鼠標(biāo)事件回調(diào)改成OnDrawPolyMouseEvent

std::vector<std::vector<cv::Point>> g_polys;//所有的多邊形
void RedrawAllPolys()
{
? ? g_originImage.copyTo(g_editImage);//恢復(fù)背景圖像
? ? 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);//正在繪制的多邊形要單獨(dú)畫,而且不能閉合
? ? ? ? ? ? imshow("image", g_editImage);
? ? ? ? }
? ? ? ? else
? ? ? ? {
? ? ? ? ? ? g_editPoints.push_back(cv::Point(x, y));//第一個(gè)點(diǎn)
? ? ? ? }
? ? }
? ? else if (event == cv::EVENT_MOUSEMOVE)
? ? {
? ? ? ? if (g_editPoints.size() > 0)
? ? ? ? {
? ? ? ? ? ? RedrawAllPolys();
? ? ? ? ? ? DrawOnePoly(g_editImage,g_editPoints,false);//正在繪制的多邊形要單獨(dú)畫,而且不能閉合
? ? ? ? ? ? DrawLine(g_editImage, g_editPoints[g_editPoints.size() - 1], cv::Point(x, y));//繪制一根到鼠標(biāo)位置的直線
? ? ? ? ? ? imshow("image", g_editImage);
? ? ? ? }
? ? }
? ? else if (event == cv::EVENT_RBUTTONDOWN)
? ? {
? ? ? ? //右鍵按下結(jié)束多邊形繪制,加入到g_polys
? ? ? ? g_polys.push_back(g_editPoints);
? ? ? ? RedrawAllPolys();
? ? ? ? g_editPoints.clear();
? ? ? ? cv::imshow("image", g_editImage);
? ? }
}

6、繪制填充多邊形

繪制填充多邊形函數(shù)cv::fillPoly,有兩種形式,其中一個(gè)定義如下

void fillPoly(InputOutputArray img, InputArrayOfArrays pts,const Scalar& color, int lineType = LINE_8, int shift = 0,Point offset = Point() );
/*
@param img 圖像
@param pts 多邊形坐標(biāo)數(shù)組
@param color 線顏色
@param lineType 線類型
@param shift ?點(diǎn)坐標(biāo)位偏移
@param offset 所有多邊形點(diǎn)的偏移
*/

繪制填充多邊形與繪制多邊形輪廓差不多,只要將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);
? ? }
}

如果將上面的所有功能以一定方式組合起來,就可以在圖像上繪制多種形狀圖形并保存了。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++分步實(shí)現(xiàn)職工管理系統(tǒng)詳解

    C++分步實(shí)現(xiàn)職工管理系統(tǒng)詳解

    這篇文章主要為大家詳細(xì)介紹了基于C++實(shí)現(xiàn)職工管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-10-10
  • 詳解C++中的內(nèi)存同步模式(memory order)

    詳解C++中的內(nèi)存同步模式(memory order)

    這篇文章主要介紹了C++中的內(nèi)存同步模式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • C++詳解哈夫曼樹的概念與實(shí)現(xiàn)步驟

    C++詳解哈夫曼樹的概念與實(shí)現(xiàn)步驟

    給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹,若該樹的帶權(quán)路徑長(zhǎng)度達(dá)到最小,稱這樣的二叉樹為最優(yōu)二叉樹,也稱為哈夫曼樹(Huffman?Tree)。哈夫曼樹是帶權(quán)路徑長(zhǎng)度最短的樹,權(quán)值較大的結(jié)點(diǎn)離根較近
    2022-04-04
  • C++11新特性“=default”,“=delete”的使用

    C++11新特性“=default”,“=delete”的使用

    =default、=delete 是C++11的新特性,分別為:顯式缺省(告知編譯器生成函數(shù)默認(rèn)的缺省版本)和顯式刪除(告知編譯器不生成函數(shù)默認(rèn)的缺省版本),本文就來介紹一下如何使用
    2021-05-05
  • C語言中sizeof()與strlen()函數(shù)的使用入門及對(duì)比

    C語言中sizeof()與strlen()函數(shù)的使用入門及對(duì)比

    這篇文章主要介紹了C語言中sizeof()與strlen()函數(shù)的使用入門及對(duì)比,同時(shí)二者在C++中的使用情況也基本上同理,是需要的朋友可以參考下
    2015-12-12
  • C++線程同步實(shí)例分析

    C++線程同步實(shí)例分析

    這篇文章主要介紹了C++線程同步實(shí)例分析,以實(shí)例的形式較為深入的分析了C++的線程同步問題,是一個(gè)較為經(jīng)典的線程同步問題,需要的朋友可以參考下
    2014-10-10
  • c++字符串分割的方法

    c++字符串分割的方法

    這篇文章主要介紹了c++字符串分割的方法,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2020-08-08
  • C語言的動(dòng)態(tài)內(nèi)存分配及動(dòng)態(tài)內(nèi)存分配函數(shù)詳解

    C語言的動(dòng)態(tài)內(nèi)存分配及動(dòng)態(tài)內(nèi)存分配函數(shù)詳解

    這篇文章主要為大家詳細(xì)介紹了C語言的動(dòng)態(tài)內(nèi)存分配及動(dòng)態(tài)內(nèi)存分配函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • C++深入探究類與對(duì)象之友元與運(yùn)算符重載

    C++深入探究類與對(duì)象之友元與運(yùn)算符重載

    友元就是讓一個(gè)函數(shù)或者類,訪問另一個(gè)類中的私有成員;打個(gè)比方,這相當(dāng)于是說:朋友是值得信任的,所以可以對(duì)他們公開一些自己的隱私,運(yùn)算符重載的實(shí)質(zhì)就是函數(shù)重載或函數(shù)多態(tài),運(yùn)算符重載是一種形式的C++多態(tài),目的在于讓人能夠用同名的函數(shù)來完成不同的基本操作
    2022-04-04
  • C語言程序如何求學(xué)生總成績(jī)和平均成績(jī)

    C語言程序如何求學(xué)生總成績(jī)和平均成績(jī)

    這篇文章主要介紹了C語言程序如何求學(xué)生總成績(jī)和平均成績(jī),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評(píng)論