一、概述
JavaCV
是一个在Java平台上用于计算机视觉的库,它为我们在Java环境
下实现Canny边缘检测
提供了便利。通过JavaCV
,我们可以轻松地将Canny边缘检测算法
应用到各种图像处理项目中,充分发挥其优势。在图像处理领域,边缘检测是一项至关重要的任务。图像中的边缘包含了丰富的信息,例如物体的轮廓、区域的边界等。边缘检测算法有多种,其中 Canny边缘检测
算法 以其精确性和可靠性而备受关注。Canny边缘检测算法的目标是在尽可能减少噪声影响的同时,准确地检测出图像中的边缘。它不像一些简单的边缘检测算法那样容易受到噪声干扰而产生虚假边缘,也不会遗漏重要的边缘信息。在实际应用中,Canny边缘检测
广泛应用于计算机视觉、医学图像处理、工业检测等众多领域。例如,在计算机视觉的目标识别任务中,准确的边缘检测可以帮助我们更好地定位和识别目标物体的形状;在医学图像处理中,对X光
、CT等图像
进行边缘检测有助于医生发现病变区域的轮廓;在工业检测方面,可以用于检测产品的外形缺陷等。
二、JavaCV环境配置
在使用JavaCV之前,需要先配置开发环境。
可以通过Maven引入JavaCV的依赖,或者手动下载Jar包。
以下是Maven依赖添加示例:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>3d</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.9</version>
</dependency>
</dependencies>
</project>
三、功能介绍
在 JavaCV 中实现边缘检测通常使用 OpenCV 提供的算法,如 Canny 边缘检测、Sobel 算子 或 Laplacian 算子。
原始图
3.1 Canny代码例子
package com.test;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgproc.Canny;
import static org.bytedeco.opencv.global.opencv_imgproc.GaussianBlur;
import static org.opencv.imgcodecs.Imgcodecs.IMREAD_GRAYSCALE;
//边缘检测是图像处理中的一个关键步骤,
// 它有助于识别图像中对象的轮廓
//这里我们使用了Canny边缘检测算法,它是一种广泛使用的边缘检测算法。
// Canny函数的两个参数分别为低阈值和高阈值,
// 这些阈值用于决定何种梯度强度的边缘应该被检测。
public class ImageEdgeDetectionExample {
public static void main(String[] args) {
// 加载图像
Mat image = imread("/Users/csguo007/Desktop/images.jpeg", IMREAD_GRAYSCALE);
// 检查图像是否正确加载
if (image.empty()) {
System.out.println("Error loading image!");
return;
}
//图片灰度处理
Mat gray = new Mat();
opencv_imgproc.cvtColor(image, gray, opencv_imgproc.COLOR_BGR2GRAY); // 转换为灰度图,因为边缘检测通常在灰度图上进行
// 应用高斯模糊
Mat blurImage =new Mat();
GaussianBlur(gray, blurImage, new Size(5, 5), 0);
// 创建一个Mat对象用于存放边缘检测结果
// 使用Canny算法进行边缘检测
Mat edges = new Mat();
opencv_imgproc.Canny(blurImage, edges, 100, 200);
// 查找轮廓
Mat hierarchy = new Mat();
MatVector contours = new MatVector();
opencv_imgproc.findContours(edges, contours, hierarchy, opencv_imgproc.RETR_TREE, opencv_imgproc.CHAIN_APPROX_SIMPLE);
//在原始图像上绘制轮廓
for (int i = 0; i < contours.size(); i++) {
Rect rect = opencv_imgproc.boundingRect(contours.get(i));
//线条的颜色
Scalar scalar = new Scalar(255, 0, 0, 255);
//绘制线条
opencv_imgproc.rectangle(edges, rect, scalar);
}
// 创建一个窗口
CanvasFrame canvasFrame = new CanvasFrame("Image Display");
canvasFrame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
canvasFrame.showImage(new OpenCVFrameConverter.ToMat().convert(edges));
}
}
3.2 Sobel 算子(基于梯度)
package com.test;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.opencv.core.CvType.CV_16S;
//Sobel 通过计算图像梯度(水平和垂直方向)检测边缘。
public class ImageEdgetSobel {
public static void main(String[] args) {
// 加载图像
Mat image = imread("/Users/csguo007/Desktop/images.jpeg");
// 检查图像是否正确加载
if (image.empty()) {
System.out.println("Error loading image!");
return;
}
//图片灰度处理
Mat gray = new Mat();
opencv_imgproc.cvtColor(image, gray, opencv_imgproc.COLOR_BGR2GRAY); // 转换为灰度图,因为边缘检测通常在灰度图上进行
// 1. 计算X和Y方向的梯度
Mat gradX = new Mat(), gradY = new Mat(), absGradX = new Mat(), absGradY = new Mat();
opencv_imgproc.Sobel(gray, gradX, CV_16S, 1, 0, 3, 1, 0, BORDER_DEFAULT);
opencv_imgproc.Sobel(gray, gradY, CV_16S, 0, 1, 3, 1, 0, BORDER_DEFAULT);
// 2. 转换到8UC1格式
opencv_core.convertScaleAbs(gradX, absGradX);
opencv_core.convertScaleAbs(gradY, absGradY);
//边缘,合并梯度
Mat edges = new Mat();
opencv_core.addWeighted(absGradX, 0.5, absGradY, 0.5, 0, edges);
// 4. 创建一个窗口,显示结果
CanvasFrame canvasFrame = new CanvasFrame("Image Display");
canvasFrame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
canvasFrame.showImage(new OpenCVFrameConverter.ToMat().convert(edges));
}
}
3.3 Laplacian 算子(二阶微分)
Laplacian 通过计算图像的二阶导数检测边缘,对噪声更敏感。
package com.test;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.Mat;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.opencv.core.CvType.CV_16S;
//Laplacian 通过计算图像的二阶导数检测边缘,对噪声更敏感。
public class ImageEdgetLaplacian {
public static void main(String[] args) {
// 加载图像
Mat src = imread("/Users/csguo007/Desktop/images.jpeg");
// 检查图像是否正确加载
if (src.empty()) {
System.out.println("Error loading image!");
return;
}
//图片灰度处理
Mat gray = new Mat();
opencv_imgproc.cvtColor(src, gray, opencv_imgproc.COLOR_BGR2GRAY); // 转换为灰度图,因为边缘检测通常在灰度图上进行
// 创建目标图像Mat对象
Mat dst = new Mat();
int apertureSize = 3; // 可以根据需要调整大小,通常为1, 3, 5等奇数
double scale = 1; // 缩放因子,通常为1,除非需要放大结果
double delta = 0; // 偏移量,可以为正值或负值,用于调整结果图像的亮度或对比度
// 应用Laplacian算子进行边缘检测
opencv_imgproc.Laplacian(gray, dst, CV_16S, apertureSize, scale, delta,1);
// 转换为8UC1
opencv_core.convertScaleAbs(dst, dst);
// 4. 创建一个窗口,显示结果
CanvasFrame canvasFrame = new CanvasFrame("Image Display");
canvasFrame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
canvasFrame.showImage(new OpenCVFrameConverter.ToMat().convert(dst));
}
}
现实中,对应于像素值变化剧烈的情况如下:
1) 深度的不连续 (物体处在不同的物平面上)
2) 表面方向的不连续 (例如,正方体的不同的两个面)
3) 物体材料不同 (光的反射系数也不同)
4) 场景中光照不同 (例如,有树荫的路面)
OpenCV 中,边缘检测常用的是索贝尔算子 (Sobel) 和拉普拉斯算子 (Laplace),分别是对图像求一阶导和二阶导。
四. 对比与选择
方法 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Canny | 边缘清晰,抗噪能力强 | 需调参(高低阈值) | 通用场景(如物体轮廓检测) |
Sobel | 方向敏感(可分离X/Y方向) | 边缘较粗 | 梯度分析(如车道线检测) |
Laplacian | 对边缘突变敏感 | 对噪声敏感 | 高频边缘检测 |
五. 进阶优化
(1)自适应阈值
使用 adaptiveThreshold
替代全局阈值:
Mat binary = new Mat();
adaptiveThreshold(src, binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11, 2);
(2)边缘增强
先锐化图像再检测边缘:
Mat kernel = new Mat(3, 3, CV_32F, new Scalar(-1));
kernel.put(1, 1, 9);
// 锐化核
filter2D(src, sharpened, -1, kernel);
(3)边缘细化
使用形态学操作(如腐蚀)细化边缘:
Mat thinned = new Mat();
Mat kernel = getStructuringElement(MORPH_CROSS, new Size(3, 3));
morphologyEx(edges, thinned, MORPH_ERODE, kernel);
七、学习资源
更多学习资料,欢迎加入我们