1.c++引用传值的函数函数问题,关于&的源码用法不太懂,下面代码cv::calcHist第一个参数为什么用&,函数函数而cv::cvtColor不用
2.OpenCV-Python学习(3)—— OpenCV 图像色彩空间转换(cv.cvtColor)
3.OpenCV函数:提取轮廓相关函数使用方法
c++引用传值的源码问题,关于&的函数函数用法不太懂,下面代码cv::calcHist第一个参数为什么用&,源码读取粘贴源码而cv::cvtColor不用
这就要看函数原型了·~
一个传递值,函数函数一个传递值的源码地址。
原型中使用&表示这个参数传递本身。函数函数//这个函数原型
而在函数定义内使用函数调用,源码则表示传递地址。函数函数//这个函数调用
&在原型中和函数调用中的源码意思不是一样的·
cv::MatND getHistogram(const cv::Mat &image) //这个表示参数为引用类型,这是函数函数声音分时源码函数定义原型
cv::cvtColor(image, hue, CV_BGR2HSV); //这个是函数调用,函数的源码第一个参数的类型是 cv::Mat
cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges);
//也是函数调用,第一个参数类型是函数函数 cv::Mat
*OpenCV-Python学习(3)—— OpenCV 图像色彩空间转换(cv.cvtColor)
学习目标
本文主要介绍OpenCV-Python中图像色彩空间转换的使用,旨在帮助读者理解常见色彩空间及其转换方式。
常见色彩空间
RGB是计算机显示器的标准色彩系统,广泛应用于显示、打印等领域。
常见色彩空间取值范围
在色彩空间转换中,需要了解每个色彩空间的取值范围,以便正确地进行转换。
色彩空间转换注意事项
在进行色彩空间转换时,需要注意转换函数的参数设置,以及转换后的asp树形分类源码色彩空间是否适用于具体应用。
色彩空间转换函数cv.cvtColor()
OpenCV提供了cv.cvtColor()函数进行色彩空间转换,该函数支持多种色彩空间之间的转换。
参数说明
cv.cvtColor()函数的参数包括源图像、目标色彩空间、以及可选的标志位,用于指定转换方式。
注意
在使用cv.cvtColor()函数时,应确保目标色彩空间适用于特定场景,避免误用导致的图像失真。
获取色彩空间的转换类型
可以通过查阅相关文档,了解不同色彩空间之间的转换关系,从而选择合适的html 输出源码转换转换类型。
代码演示
以下代码演示了BGR与HSV、BGR与YCrCb之间的转换,以及色彩空间转换的不可逆性与可逆性实例。
7.1 BGR↔HSV、BGR↔YCrCb
7.1.1 代码
7.1.2 结果
7.2 色彩空间转换不可逆实例
7.2.1 代码
7.2.2 结果
7.2.3 注意
在进行不可逆色彩空间转换时,应谨慎操作,避免损失重要信息。
7.3 色彩空间转换可逆实例
7.3.1 代码
7.3.2 结果
总结
通过本篇文章的学习,读者应掌握了OpenCV-Python中色彩空间转换的基本知识,包括常见色彩空间、取值范围、转换注意事项,手机主播源码以及如何使用cv.cvtColor()函数进行色彩空间转换。
OpenCV函数:提取轮廓相关函数使用方法
0、绪:
步骤:
一、findContours()查找轮廓;
二、drawContours()画轮廓;
三、轮廓填充;
四、计算轮廓的面积和周长;
五、提取轮廓凸包,矩形,最小外接矩形,外接圆
findContours()查找轮廓: void findContours ( InputOutputArray image,//输入图像,必须是8位单通道二值图像 OutputArrayOfArrays contours,//检测到的轮廓,每个轮廓被表示成一个point向量 OutputArray hierarchy,//可选的输出向量,包含图像的拓扑信息。其中元素的个数和检测到的轮廓的数量相等 int mode,//说明需要的轮廓类型和希望的返回值方式 int method,//轮廓近似方法 Point offset = Point() ) 参数mode: ①mode的值决定把找到的轮廓如何挂到轮廓树节点变量(h_prev, h_next, v_prev, v_next)上,拓扑结构图如下; ②每种情况下,结构都可以看成是被横向连接(h_prev, h_next)联系和被纵向连接(v_prev, v_next)不同层次。 ③CV_RETR_EXTERNAL:只检测出最外轮廓即c0; CV_RETR_LIST:检测出所有的轮廓并将他们保存到表(list)中; CV_RETR_COMP:检测出所有的轮廓并将他们组织成双层的结构,第一层是外部轮廓边界,第二层边界是孔的边界; CV_RETR_TREE:检测出所有轮廓并且重新建立网状的轮廓结构; ④参数method: CV_CHAIN_CODE:用freeman链码输出轮廓,其他方法输出多边形(顶点的序列); CV_CHAIN_APPROX_NONE:将链码编码中的所有点转换为点; CV_CHAIN_APPROX_SIMPLE:压缩水平,垂直或斜的部分,只保存最后一个点; CV_CHAIN_APPROX_TC_L1,CV_CHAIN_QPPROX_TC_KCOS:使用Teh-Chin链逼近算法中的一个。 CV_LINK_RUNS:与上述的算法完全不同,连接所有的水平层次的轮廓。 注:findContours()查找时,这个图像会被直接涂改,因此如果是以后有用的图像,应该复制之后再进行查找;
drawContours()绘制轮廓: void drawContours( InputOutputArray image,//要绘制轮廓的图像 InputArrayOfArrays contours,//所有输入的轮廓,每个轮廓被保存成一个point向量 int contourIdx,//指定要绘制轮廓的编号,如果是负数,则绘制所有的轮廓 const Scalar color,//绘制轮廓所用的颜色 int thickness = 1, //绘制轮廓的线的粗细,如果是负数,则轮廓内部被填充 int lineType = 8, /绘制轮廓线的连通性 InputArray hierarchy = noArray(),//关于层级的可选参数,只有绘制部分轮廓时才会用到 int maxLevel = INT_MAX,//绘制轮廓的最高级别,这个参数只有hierarchy有效的时候才有效 Point offset = Point() ) 注: ①maxLevel=0,绘制与输入轮廓属于同一等级的所有轮廓即输入轮廓和与其相邻的轮廓 maxLevel=1, 绘制与输入轮廓同一等级的所有轮廓与其子节点。 maxLevel=2,绘制与输入轮廓同一等级的所有轮廓与其子节点以及子节点的子节点
轮廓填充: 步骤: a) 依次遍历轮廓点,将点绘制到img上; b) 使用floodFill以及一个种子点进行填充; 两种方法:自己编写程序;使用drawContours()函数; void drawMaxAreaLine(Mat dst, vectorPoint maxAreaPoints) { int step = dst.step; auto data = dst.data; for (int i = 0; i maxAreaPoints.size(); ++i) { *(data + maxAreaPoints[i].x + maxAreaPoints[i].y * step) = ; } } //孔洞填充算法 void fillHole(Mat src_Bw, Mat dst_Bw) { Size m_Size = src_Bw.size(); Mat Temp=Mat::zeros(m_Size.height+,m_Size.width+,src_Bw.type()); src_Bw.copyTo(Temp(Range(5, m_Size.height + 5), Range(5, m_Size.width + 5))); floodFill(Temp, Point(0, 0), Scalar()); Mat cutImg; Temp(Range(5, m_Size.height + 5), Range(5, m_Size.width + 5)).copyTo(cutImg); dst_Bw = src_Bw | (~cutImg); } 注:这里常会碰到种子点不好选取的问题,因为有时候所选择的种子点不能保证对所有轮廓都适用。也就是查找一个在轮廓内的点是存在一定难度的。 使用drawContours()就会很方便: vectorvectorPoint contours; contours.push_back(currentFrameEdge); Mat savedGrayMat = Mat::zeros(RectData[0].rows, RectData[0].cols, CV_8UC1); //drawMaxAreaLine(savedGrayMat, currentFrameEdge); //floodFill(savedGrayMat, Point(currentFrameEdge[0].x + 2, currentFrameEdge[0].y + 2), ); drawContours(savedGrayMat, contours, 0, Scalar(), CV_FILLED); imshow("savedGrayMat", savedGrayMat); waitKey();
计算轮廓的面积和周长: ①计算轮廓面积: double contourArea(InputArray contour, bool oriented=false ) InputArray contour:输入的点,一般是图像的轮廓点; bool oriented=false: 表示某一个方向上轮廓的的面积值,顺时针或者逆时针,一般选择默认false; ②计算轮廓边长: double arcLength(InputArray curve, bool closed) InputArray curve:表示图像的轮廓; bool closed:表示轮廓是否封闭的; 注: ①contourArea计算整个或部分轮廓的面积; 在计算部分轮廓的情况时,由轮廓弧线和连接两端点的弦围成的区域总面积被计算,如图; ②轮廓的位置将影响区域面积的符号,因此函数范围的有可能是负值。可以在运行时使用fabs()来得到面积的绝对值;
提取轮廓凸包,矩形,最小外接矩形,外接圆 ①convexhull():函数提取轮廓的凸包: 格式: void convexhul(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true) 参数: 第一个参数:要求凸包的点集 第二个参数:输出的凸包点,可以为vector,此时返回的是凸包点在原轮廓点集中的索引,也可以为vector,此时存放的是凸包点的位置 第三个参数:一个bool变量,表示求得的凸包是顺时针方向还是逆时针方向,true是顺时针方向; 第四个参数,第二个参数的返回类型是vector还是vector,可以忽略; ②boundingRect():计算轮廓外包矩形,矩形是与图像上下边界平行的; 格式: Rect boundingRect(InputArray points); 输入:二维点集,点的序列或向量 (Mat) 返回:Rect //寻找外包矩阵 Rect maxRect = boundingRect(contours[m_count]); //绘制外包矩阵 rectangle(contours_img_1, maxRect, Scalar(0, , 0)); ③minAreaRect():提取轮廓的最小外包矩形; 主要求包含点集最小面积的矩形,这个矩形是可以有偏转角度的,可以与图像的边界不平行; 格式: RotatedRect minAreaRect(InputArray points) 输入:二维点集,点的序列或向量 (Mat) 返回:RotatedRect ④minEnclosingcircle():提取轮廓的最小外包圆; 格式: void minEnclosingcircle(InputArray points,Point2f center,float radius) 输入: 二维点集:点的序列vector point 或向量 (Mat) , 圆心坐标; 半径;
示例: #include opencv2/opencv.hpp #include opencv2/highgui/highgui.hpp #include opencv2/imgproc/imgproc.hpp #include "opencv2/contrib/contrib.hpp" #include iostream #include stdio.h using namespace cv; using namespace std; void KmeansFun(); void fillHole(Mat src_Bw, Mat dst_Bw); int main() { Mat src_img = imread("data\\.jpg",1); Mat src_img_1(src_img.rows,src_img.cols,CV_8UC1,Scalar(0)); cvtColor(src_img, src_img_1, CV_BGR2GRAY); GaussianBlur(src_img_1, src_img_1, Size(3, 3), 3, 3); Mat threshold_img(src_img.rows,src_img.cols,CV_8UC1,Scalar(0)); threshold(src_img_1, threshold_img, 0, , THRESH_OTSU); imshow("1",threshold_img); vector vectorPoint contours; vectorVec4i hierarchy; findContours( threshold_img, contours, hierarchy,//轮廓的继承关系 CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE ); Mat contours_img(src_img.rows,src_img.cols,CV_8U,Scalar(0)); if(!contours.empty() !hierarchy.empty()) { int idx = 0; for( ; idx = 0; idx = hierarchy[idx][0] ) { Scalar color(,,); //Scalar color( (rand()), (rand()), (rand()) );//随机生成颜色 drawContours( contours_img, contours, idx, color, 1, 8, hierarchy ); } } imshow("contours_img",contours_img); int m_count = 0; Mat contours_img_1(src_img.rows,src_img.cols,CV_8UC3,Scalar(0)); if(!contours.empty() !hierarchy.empty()) //计算轮廓的面积 { for (int i = 0; i (int)contours.size(); i++) { double g_dConArea = abs(contourArea(contours[i], false)); double g_dConLength = arcLength(contours[i],true); cout "用轮廓面积计算函数计算出来的第" i "个轮廓的面积为:" g_dConArea endl; cout "用轮廓面积计算函数计算出来的第" i "个轮廓的边长为:" g_dConLength endl; if (g_dConArea = g_dConArea ) { m_count = i; //Scalar color( (rand()), (rand()), (rand()) );//随机生成颜色 //drawContours(contours_img_1, contours, m_count, color, CV_FILLED, 8, hierarchy );//对轮廓内部着色 //计算凸包 //vectorint hull; //convexHull(Mat(contours[m_count]), hull, true); ////绘制凸包 //int hull_count = (int)hull.size(); //Point pt0 = contours[m_count][hull[hull_count - 1]]; //for (int i = 0;i hull_count;i++) //{ // Point pt = contours[m_count][hull[i]]; // line(contours_img_1, pt0, pt, Scalar(0, , 0), 1,8); // pt0 = pt; //} ////寻找外包矩阵 //Rect maxRect = boundingRect(contours[m_count]); ////绘制外包矩阵 //rectangle(contours_img_1, maxRect, Scalar(0, , 0)); ////寻找最小外包矩形 //RotatedRect minRect = minAreaRect(contours[m_count]); //Point2f fourPoint2f[4]; ////将minRect的四个顶点坐标值放到fourPoint的数组中 //minRect.points(fourPoint2f); ////根据得到的四个点的坐标 绘制矩形 //for (int i = 0; i 3; i++) //{ // line(contours_img_1, fourPoint2f[i], fourPoint2f[i + 1], Scalar(0,0,), 3); //} //line(contours_img_1, fourPoint2f[0], fourPoint2f[3], Scalar(0, 0, ), 3); //在生成的那些随机点中寻找最小包围圆形 Point2f center; //圆心 float radius; //半径 minEnclosingCircle(contours[m_count], center, radius); //根据得到的圆形和半径 绘制圆形 circle(contours_img_1, static_castPoint(center), (int)radius, Scalar( (rand()), (rand()), (rand()) ), 3); } } } imshow("src_img",src_img); imshow("contours_img-1",contours_img_1); waitKey(0); return 0; }