OpenCV基本結構(Point、Size、Rect、绝对值)

本文介绍了OpenCV中的基本结构,如Point、Size、Rect等,并详细解释了这些结构的用途及赋值方法。此外,还涵盖了OpenCV中的基本运算,包括图像相加、位运算、矩阵操作以及比较操作等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文转自:http://monkeycoding.com/?p=521

OpenCV有定義一些基本結構,像Point、Point2f、Size、Size2f、Rect、RotatedRect、Scalar等,方便我們進行影像處理,這些結構通常都當參數輸入,或是函式內部計算之用。

Point:2維整數點類別,通常用於影像的座標點,成員有x和y,要是輸入浮點數的話,則四捨五入取整數,以下為建構式和最基本的兩種賦值方法:

Point(int x, int y) //建構式
Point pt1(20,30);
Point pt2;
pt2.x = 20;
pt2.y = 30;

Point2f:2維浮點數點類別,通常用於幾何計算,用法和Point雷同,只是x和y是浮點數。

Point3i、Point3f、Point3d代表3維點x、y、z,而成員型態分別為int、float、double。


Size:尺寸類別,成員有width和height,分別表示寬和長(int型態),可用area()函式得到面積,以下為建構式最基本兩種賦值方法:

Size(int width, int height) //建構式
Size size1(150, 100);
Size size2;
size2.width = 150;
size2.height = 100;
int myArea = size2.area();

Size2f:尺寸類別,和Size用法雷同,只是width和height為float型態。


Rect:矩形類別,成員有x、y、width、height,分別表示左上角頂點的x座標,左上角頂點的y座標,矩形寬、矩形高,可用area()函式得到面積,以下為建構式和最基本的兩種賦值方法:

Rect(int x, int y, int width, int height) //建構式
Rect rect1(20,30,150,100);
Rect rect2;
rect2.x = 20;
rect2.y = 30;
rect2.width = 150;
rect2.height = 100;
int myRectArea = rect2.area();

RotatedRect:斜矩形類別,成員有矩形的質心center(Point2f類別),四周長size(Size2f類別)、旋轉角度angle(float類別),可用points()函式得到四個頂點,以下為建構式和最基本的兩種賦值方法:

RotatedRect(const Point2f &center, const Size2f &size, float angle) //建構式
RotatedRect rRect1(Point2f(150,150), Size2f(100,50), 30.0);
RotatedRect rRect2; 
rRect2.center = Point2f(150,150);
rRect2.size = Size2f(100,50);
rRect2.angle = 30.0;
Point2f vertices[4];
rRect2.points(vertices);

Scalar:代表4元素的向量,一般用於像素顏色,以下設定給灰階圖和彩色圖像素的方式:

  • Scalar(a, b, c):省略透明通道,由於OpenCV的彩色影像通常為BGR的順序,a代表藍色、b代表綠色、c代表紅色。

  • Scalar(a):通常用於灰階圖,像素強度為a。

openCV 图像相加,位运算,协方差,绝对值,比较

原文:http://blog.youkuaiyun.com/Dr_Neo/article/details/44107269

(1)基本运算

两图像相加:

add(InputArray src1,InputArray src2, OutputArray dst, InputArray mask=noArray(),int dtype=-1):如可用add(A,B,C)来计算C=A+B;如果指定了图像掩模mask(注:mask必须为单通道),则运算只在mask对应像素部位null的像素上进行,add(A,B,C,mask)意为if(mask[i]0)c[i]=a[i]+b[i];

addWeighted(InputArray src1,double alpha, InputArray src2, double beta, double gamma,OutputArraydst, int dtype=-1):计算加权和,如addWeighted(A,k1,B,k2,k3,C)表示C=k1*A+k2*B+k3;

scaleAdd(A,k1,B,C)表示C=k1*A+B

减:subtract(A,B,C)表示C=A-B

乘:mutiply(A,B,C,k)表示C=k*A*B

divide(InputArray src1,InputArray src2, OutputArray dst, double scale=1,int dtype=-1):除法,divide(A,B,C,k)表示C=(A*k/B);也可以直接用一个scale来除以array,divide(k,B,C)表示C=k/B

当然还有其他计算符,如log()、exp()

 

位运算:

bitwise_and(InputArray src1,InputArray src2, OutputArray dst, InputArray mask=noArray()):按位与,bitwise_and(A,B,C,mask)表示if(mask[i])a[i]^b[i]=c[i]

bitwise_not(A,B,mask):按位非,b[i] =~a[i]

bitwise_or(A,B,C):按位或,C=AB

bitewise_xor(A,B,C):按位异或,C=AB

 

此处需要注意的是,所有这些运算都会调用cv::saturate_cast函数来进行截断操作,以保证输出像素值都在合理的范围之内。另外,OpenCV对c++的很多操作符都进行了重载,所以可以直接使用运算符+,=,*,/,&,|,~,^,<,>等来对图像矩阵进行操作,矩阵求逆m.inv(),矩阵转置m.t(),行列式m.determinant(),向量模v.norm(),向量叉乘v1.cross(v2),向量点积v1.dot(v2)

 (2)矩阵操作

calcCovarMatrix():计算协方差矩阵

invert(InputArray src,OutputArray dst, int flags=DECOMP_LU):求逆矩阵

sqrt(InputArray src,OutputArray dst):计算平方根

求绝对值:

abs(const Mat& m):求绝对值,输入参数可是矩阵也可是表达式,如:C=abs(A),C=abs(A-B)

absdiff(InputArray src1,InputArray src2, OutputArray dst):absdiff(A,B,C)等价于C=abs(A-B)

cartToPolar(InputArray x, InputArray y,OutputArray magnitude, OutputArray angle, boolangleInDegrees=false):计算二维矢量的幅值和向角

dct(InputArray src,OutputArray dst, int flags=0):离散余弦变换

dft(InputArray src,OutputArray dst, int flags=0, int nonzeroRows=0):离散傅里叶变换

flip(InputArray src,OutputArray dst, int flipCode):对图像进行翻转,flipCode>0,进行垂直翻转;flipCode=0,进行水平翻转;flipCode<0,同时进行水平、垂直翻转;


 

(3)比较操作

CheckRange():用来判断输入array中的每个元素是否都处于某一范围内

compare(InputArray A, InputArray B,OutputArray C, int cmpop):根据参数cmpop的值来决定A和B比较的方式,其值有CMP_EQ,CMP_GT, CMP_GE, CMP_LT, CMP_LE, CMP_NE,结果输出为C;

min():如C=min(A,B)表示c[i]=min(a[i],b[i])

max():与min()类似


注意,此处所有函数在调用时都要加上命名空间cv::

opencv里面,基本上矩阵、向量能想到的操作都有相对应的函数,非常之多,在此不能一一列出,具体的在opencv的online documentation里面都有。建议大家在实际编程时,遇到跟矩阵相关的运算、操作时都先去查阅一下opencv的online documentation,要是里面有现成的函数就可以直接调用了,没有的再去自己想办法写。有关矩阵操作符的库函数主要集中在opencv_core模块中。


经过我多次实验的出结论:opencv中求得的协方差矩阵比matlab中的大(n-1)倍!(n是矩阵的行数)


<think>我们使用OpenCvSharp进行图像处理,目标:检测图像中的横线和竖线边缘,并计算它们的角度。步骤:1.读取图像,转为灰度图。2.使用边缘检测(如Canny)或者二值化(如自适应阈值)来突出线条。3.使用霍夫变换(HoughLinesP)检测直线。4.对检测到的直线进行分类(横线和竖线),并计算每条直线的角度。5.计算横线和竖线的平均角度(可选)或者分别统计。注意:横线通常角度接近0度或180度(水平方向),竖线角度接近90度(垂直方向)。但要注意霍夫变换返回的角度可能是0到180度之间的值(基于弧度或角度,需要转换)。霍夫变换(HoughLinesP)返回的是线段的两个端点,我们可以通过这两个点计算直线的角度(弧度或角度)。计算角度的方法:已知线段两个端点P1(x1,y1)和P2(x2,y2),则线段的方向向量为(dx,dy)=(x2-x1,y2-y1)角度(弧度)=atan2(dy,dx)注意:atan2返回的是从x轴正方向逆时针旋转的角度,范围[-π,π]。但是,我们通常关心的是直线与水平方向的夹角,这个角度在0到180度之间。实际上,对于一条直线,它与水平方向的夹角θ(0<=θ<180)可以通过以下方式得到:θ=atan2(dy,dx)*180/π然后转换为0~180度。然而,由于直线没有方向,我们也可以取绝对值,但要注意:水平线可能是0度或180度(实际上是一样的),垂直线是90度。但是,霍夫变换的标准实现中,使用的是极坐标表示(ρ,θ),其中θ就是直线法线与x轴的夹角(范围0~π弧度)。但HoughLinesP返回的是端点,所以我们需要自己计算角度。步骤细化:1.读取图像,灰度化。2.预处理:可以使用高斯模糊去噪,然后进行边缘检测(Canny)或二值化(如adaptiveThreshold)来获得二值图像。3.使用HoughLinesP检测直线。4.遍历每条直线,计算其角度(注意:由于图像坐标系中y轴向下,所以计算角度时要注意方向)。计算角度(以度为单位):doubleangle=Math.Atan2(y2-y1,x2-x1)*180/Math.PI;由于直线没有方向,我们可以将角度转换到0~180度之间:if(angle<0)angle+=180;angle=angle%180;//这样角度在0~180度之间5.分类:横线:角度在0附近(比如0~20度)或者180度附近(160~180度)可以视为横线(水平线)。竖线:角度在90度附近(比如70~110度)视为竖线(垂直线)。6.可以分别计算横线和竖线的平均角度。注意:由于图像中可能存在干扰,我们可以通过设置角度阈值来过滤。另外,我们也可以使用形态学操作来强化横线和竖线(如引用[4]中提到的),例如:横线:使用一个横着的矩形结构元素(比如宽度远大于高度)进行闭运算(先膨胀后腐蚀),可以连接同一行上的线段,然后检测直线。竖线:使用一个竖着的矩形结构元素(高度远大于宽度)进行闭运算。但根据问题要求,我们直接检测边缘并计算角度,也可以先进行形态学操作来增强横竖线。根据用户需求,我们提供两种方式:方式一:直接使用边缘检测和霍夫变换。方式二:使用形态学操作增强横竖线,然后再检测。这里我们先采用方式一,然后根据需要可以选择是否加入形态学增强。代码步骤:1.读取图像2.转为灰度图3.高斯模糊(可选)4.边缘检测(Canny)或二值化(这里我们使用Canny,也可以使用自适应二值化)5.使用HoughLinesP检测直线6.遍历直线,计算角度并分类7.输出横线和竖线的角度,并计算平均角度(可选)注意:用户要求检测图像区域内的横线和竖线边缘,所以我们只关注这两个方向的直线。代码示例:</think>### 使用 OpenCvSharp 检测横竖线边缘并计算角度 以下是完整的解决方案,包含代码实现和关键步骤说明: ```csharp using OpenCvSharp; using System; using System.Collections.Generic; public class LineDetector { public static void DetectLines(string imagePath) { // 1. 读取图像并预处理 using Mat src = new Mat(imagePath, ImreadModes.Color); using Mat gray = new Mat(); using Mat blurred = new Mat(); using Mat edges = new Mat(); // 转换为灰度图 Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); // 高斯模糊降噪 Cv2.GaussianBlur(gray, blurred, new Size(5, 5), 0); // Canny边缘检测 Cv2.Canny(blurred, edges, 50, 150); // 2. 使用霍夫变换检测直线 LineSegmentPoint[] lines = Cv2.HoughLinesP( edges, rho: 1, theta: Math.PI / 180, threshold: 80, minLineLength: 100, maxLineGap: 10 ); // 3. 分类横竖线并计算角度 var horizontalLines = new List<double>(); var verticalLines = new List<double>(); using Mat result = src.Clone(); foreach (LineSegmentPoint line in lines) { // 计算线段角度 (0~180度) double angle = CalculateLineAngle(line.P1, line.P2); // 分类横线(0°±2)和竖线(90°±2) if (angle < 20 || angle > 160) // 水平线 { Cv2.Line(result, line.P1, line.P2, Scalar.Red, 2); horizontalLines.Add(angle > 90 ? angle - 180 : angle); } else if (Math.Abs(angle - 90) < 20) // 垂直线 { Cv2.Line(result, line.P1, line.P2, Scalar.Green, 2); verticalLines.Add(angle); } } // 4. 计算平均角度 double avgHorizontalAngle = horizontalLines.Count > 0 ? horizontalLines.Average() : double.NaN; double avgVerticalAngle = verticalLines.Count > 0 ? verticalLines.Average() : double.NaN; // 5. 显示结果 Console.WriteLine($"检测到横线: {horizontalLines.Count}条, 平均角度: {avgHorizontalAngle:F2}°"); Console.WriteLine($"检测到竖线: {verticalLines.Count}条, 平均角度: {avgVerticalAngle:F2}°"); Cv2.ImShow("Detected Lines", result); Cv2.WaitKey(0); } // 计算线段角度 (0~180度) private static double CalculateLineAngle(Point p1, Point p2) { double dx = p2.X - p1.X; double dy = p2.Y - p1.Y; double radians = Math.Atan2(dy, dx); double degrees = radians * (180 / Math.PI); return (degrees < 0) ? degrees + 180 : degrees; } } ``` ### 关键步骤说明 1. **图像预处理** - 灰度转换:减少计算维度 `$ \text{BGR} \rightarrow \text{Gray} $` - 高斯模糊:使用 `$ 5\times5 $` 核降噪 `$ G(x,y) = \frac{1}{2\pi\sigma^2}e^{-\frac{x^2+y^2}{2\sigma^2}} $` - Canny边缘检测:双阈值(50,150)提取边缘[^2] 2. **直线检测** - 概率霍夫变换 `$ \text{HoughLinesP} $` 参数: - `rho=1`:距离分辨率(像素) - `theta=π/180`:角度分辨率() - `threshold=80`:累加器阈值 - `minLineLength=100`:最短线段长度 - `maxLineGap=10`:最大线段间隔[^3] 3. **角度计算原理** - 线段方向向量:`$ \vec{d} = (dx, dy) = (x_2-x_1, y_2-y_1) $` - 角度公式:`$ \theta = \arctan2(dy, dx) \times \frac{180}{\pi} $` - 角度范围:转换为 `$ [0^\circ, 180^\circ) $` 4. **分类标准** - 横线:`$ \theta \in [0^\circ, 20^\circ) \cup [160^\circ, 180^\circ) $` - 竖线:`$ \theta \in [70^\circ, 110^\circ) $` ### 优化建议 1. **形态学处理强化线条** ```csharp // 强化横线 using Mat horizontalKernel = Cv2.GetStructuringElement( MorphShapes.Rect, new Size(30, 1)); Cv2.MorphologyEx(edges, edges, MorphTypes.Close, horizontalKernel); // 强化竖线 using Mat verticalKernel = Cv2.GetStructuringElement( MorphShapes.Rect, new Size(1, 30)); Cv2.MorphologyEx(edges, edges, MorphTypes.Close, verticalKernel); ``` 通过形态学闭运算连接断线[^4] 2. **角度校准** ```csharp // 排除接近45°的干扰线 if (Math.Abs(angle - 45) < 10 || Math.Abs(angle - 135) < 10) continue; ``` 3. **参数调整建议** - 复杂背景:提高Canny高阈值(150→200) - 虚线检测:增大maxLineGap(10→20) - 短线段检测:减小minLineLength(100→50) ### 应用场景 1. 文档扫描矫正(计算文本倾斜角度) 2. 工业检测(PCB板线路角度分析) 3. 建筑图纸解析(提取墙体正交结构
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值