我们将在本文中介绍以下高级图像处理操作:
- Canny 边缘检测
- 轮廓和形状识别
Canny 边缘检测:Canny 边缘检测是一种流行的边缘检测算法。它是由 John F. Canny 在 1986 年开发的。它是一个多阶段算法,我们将按如下方式经历每个阶段:
- 噪声抑制:第一步是使用高斯平滑从图像中去除噪声,这涉及使用高斯核,其中靠近核中心的像素被赋予比远处像素更多的权重。
- 梯度计算:应用Sobel 滤波器计算图像的梯度以计算边缘强度和方向,该滤波器突出显示 x 和 y 轴上的强度变化。
- Non-Maximum Suppression: Non-Maximum Suppression通过遍历上一步生成的梯度矩阵中的所有值来寻找边缘方向强度更大的像素,从而减少边缘的厚度。
- 双阈值滞后:最后一步使用输入参数下阈值和上限阈值来过滤掉潜在边缘,根据以下标准丢弃不相关的边缘:如果像素梯度值高于上限阈值,则像素被接受为边缘。如果像素梯度值低于下限阈值,则像素被拒绝。如果像素梯度值介于两个阈值之间,则仅当它连接到高于阈值上限的像素时才会被接受。
ImgProc类为 Canny 边缘检测提供了一个Canny方法,该方法采用以下参数:
- Source Image: Mat
- Output edges: Mat
- Lower Threshold: double
- Upper Threshold: double
public static Mat cannyEdges(Mat img){
Mat canny = new Mat();
Imgproc.Canny(img,canny,30,100);
return canny;
}
Canny 边缘检测
Canny 边缘检测
双边滤波图像上的 Canny 边缘检测
注意:Canny 边缘检测算法基于梯度,因此对图像噪声高度敏感。因此,在灰度图像上应用 Canny 边缘检测是一种很好的做法。
轮廓:轮廓可以定义为连接沿边界具有相同强度的所有连续点的曲线。它们对于形状分析和对象检测很有用。
使用二值图像查找轮廓是一种很好的做法。二值图像是这样的图像,其中每个像素只能有两个可能的强度值(0 表示黑色,1 或 255 表示白色)。
ImgProc 类提供了一种用于生成二值图像的阈值方法,该方法使用以下参数:
- Source Image: Mat – grayscale image
- Output Image: Mat
- Threshold : double: 如果像素值小于阈值,则设置为 0。
- Maximum:双精度 – 分配给超过阈值的像素的最大值。
- Type of threshold:int – OpenCV 提供不同类型的阈值技术,如OTSU、TOZERO等。
public static Mat convertToBinary(Mat img){
Mat binImg = new Mat();
Imgproc.threshold(img,binImg,125 ,255,Imgproc.THRESH_BINARY);
return binImg;
}
图像转换为二进制
二进制图像
寻找轮廓:ImgProc 类提供了一个findContours方法,该方法接受以下输入参数:
- Image:Mat – 二进制图像
- Contours : List- 检测到的轮廓存储在这个列表中
- Hierarchy : Mat – 存储有关图像拓扑的信息
- Contour Retrieval Mode:int – OpenCV 提供以下检索模式:
- **RETR_LIST(0)**:检索所有轮廓而不保持层次关系。
- RETR_EXTERNAL(1): 仅检索所有极端外轮廓。
- RETR_CCOMP(2): 检索所有轮廓并将它们排列到 2 级层次结构中。对象的外部轮廓放置在层次 1 中,对象内部的孔的轮廓放置在层次 2 中。
- RETR_TREE(3): 检索所有轮廓并创建完整的层次结构列表。
- Contour Approximation Method : int – 近似方法指定存储边界坐标的方式。
- CHAIN_APPROX_NONE:存储所有边界点。
- CHAIN_APPROX_SIMPLE:去除冗余点并压缩轮廓;例如:对于一条线,存储两个端点。
public static void findAndDrawContours(Mat binImg,Mat org){
List<MatOfPoint> contourList = new ArrayList<MatOfPoint>();
Imgproc.findContours(binImg,contourList,new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Imgproc.drawContours(org, contourList, -1, new Scalar(50, 205, 50), 2);
HighGui.imshow("Contours",org);
HighGui.waitKey();
}
查找和绘制轮廓
绘制轮廓: ImgProc 类提供了一个drawContours方法,该方法使用以下参数:
- Image:Mat – 目标图像
- Contour List:List< MatOfPoint>
- Contour Index: int – 要绘制的轮廓索引,负值表示所有轮廓都已绘制。
- Color:Scalar – 轮廓的颜色。
- Thickness:int – 边界线的厚度。
轮廓
使用轮廓进行形状检测:我们可以使用轮廓来根据近似曲线中的周长、面积和阵列点的数量来检测形状。ImgProc 类提供了一个approxPolyDP方法,该方法返回基于轮廓的近似曲线并使用以下参数:
- curve:MatOfPoint2f
- approxCurve: MatOfPoint2f – 输出曲线
- epsilon: double – Epsilon 指定近似精度。这是原始曲线与其近似值之间的最大距离,我们可以使用 ImgProc arcLength 方法(返回曲线长度或周长)进行优化。
- closed:布尔值 – 如果近似曲线是闭合的,则为 true,否则为 false。
public static void shapeDetection(Mat binImg,Mat org){
List<MatOfPoint> contourList = new ArrayList<MatOfPoint>();
List<MatOfPoint> selectedContours = new ArrayList<>();
Imgproc.findContours(binImg,contourList,new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
for(int i=0;i<contourList.size();i++){
MatOfPoint2f point = new MatOfPoint2f();
point.fromList(contourList.get(i).toList());
MatOfPoint2f approxCurve = new MatOfPoint2f();
double parameter = Imgproc.arcLength(point, true);
Imgproc.approxPolyDP(point, approxCurve, parameter * 0.02, true);
long total = approxCurve.total();
//Detecting Rectangle Shape
if (total == 4) {
double area = Imgproc.contourArea(contourList.get(i));
//rectangle with area greater than 500
if(area>500)
selectedContours.add(contourList.get(i));
}
}
Imgproc.drawContours(org, selectedContours, -1, new Scalar(50, 205, 50), 3);
HighGui.imshow("Contours",org);
HighGui.waitKey();
}
使用轮廓进行形状检测
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。