Canny边缘检测
Canny边缘检测是一个较为特殊的检测图形,其特殊或者创新在于其使用两个阈值进行检测,然后将所有的边缘连接在一起,形成边缘曲线或线段。其对噪声较为敏感,故其在检测前需要进行降噪。滤波器可根据实际情况选择,但一般由于噪声的自然随机性,一般选择高斯滤波进行降噪。Canny一种步骤如下:
- 高斯滤波:抑制噪声;
- 灰度转换:在灰度图像上计算其梯度值;
- 计算梯度:Sobel或Scharr;
- 非最大信号抑制:在梯度图像上寻找局部最大值;
- 高低阈值连接:连接边缘像素为线段,形成轮廓。
其函数声明如下:
Canny(src, edges, threshold1, threshold2, apertueSize , L2gradient)
各参数解释如下:
-
src
输入源 -
edges
输出源 -
threshold1
低阈值1 -
threshold2
低阈值2 -
apertueSize
内部计算梯度Sobel -
L2gradient)
计算梯度的方法
Java代码(JavaFX Controller层)
public class Controller{
@FXML private Text fxText;
@FXML private ImageView imageView;
@FXML public void handleButtonEvent(ActionEvent actionEvent) throws IOException {
Node source = (Node) actionEvent.getSource();
Window theStage = source.getScene().getWindow();
FileChooser fileChooser = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.png");
fileChooser.getExtensionFilters().add(extFilter);
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("JPG Files(*.jpg)", "*.jpg"));
File file = fileChooser.showOpenDialog(theStage);
runInSubThread(file.getPath());
}
private void runInSubThread(String filePath){
new Thread(new Runnable() {
@Override
public void run() {
try {
WritableImage writableImage = edgeOfCanny(filePath);
Platform.runLater(new Runnable() {
@Override
public void run() {
imageView.setImage(writableImage);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
private WritableImage edgeOfCanny(String filePath) throws IOException {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat src = Imgcodecs.imread(filePath);
Mat dst = new Mat();
Mat edges = new Mat();
Imgproc.GaussianBlur(src, src, new Size(3,3),0);
Mat gray = new Mat();
Imgproc.cvtColor(src, gray, Imgproc.COLOR_RGB2GRAY);
Imgproc.Canny(src, edges, 50,150,3,true);
Core.bitwise_and(src, src, dst, edges);
MatOfByte matOfByte = new MatOfByte();
Imgcodecs.imencode(".jpg", dst, matOfByte);
byte[] bytes = matOfByte.toArray();
InputStream in = new ByteArrayInputStream(bytes);
BufferedImage bufImage = ImageIO.read(in);
WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null);
return writableImage;
}
}
运行图