opencv腐蚀和膨胀
本文目的
目的:学习使用opencv的腐蚀和膨胀。不介绍算法,只以使用者的角度来理解
语言:java
版本:opencv-410
分解介绍
膨胀与腐蚀,关于算法方面的介绍不太懂,太复杂,只想从使用者的角度来理解下。
· 膨胀的作用:将白色区域变大,可以使相互分离的物体连接起来
· 腐蚀的作用:将黑色区域变大,可以断开两个连接在一起的物体
所以
使用膨胀时,图像会变的越来越亮,白色区域越来越多
使用腐蚀时,图像会变得越来越暗,黑色区域越来越多。
如官方文档的案例中:
原图:
膨胀后图片:可以看到白色区域变大了
腐蚀后图片:可以看到白色区域变小了
膨胀函数
javadoc:
dilate(Mat src, Mat dst, Mat kernel)dilate(Mat src, Mat dst, Mat kernel, Point anchor)
腐蚀函数
javadoc:
erode(Mat src, Mat dst, Mat kernel)
erode(Mat src, Mat dst, Mat kernel, Point anchor)
内核元素的构造
无论腐蚀还是膨胀都要先构造一个内核元素,也是一个Mat元素
对于自定义一个结构元素kernel,OpenCV提供了一个函数getStructuringElement,可以获取常用的结构元素的形状:矩形(包括线形)、椭圆(包括圆形)及十字形。
getStructuringElement的内部并没有什么优化实现,只是封装了一下功能。其原理同样是声明一个Mat,然后求形状,指定Mat的值。
总之:getStructuringElement是一种更加简便的方法实现一个kernel。
元素类型
结构性元素类型有三种:矩形,椭圆和十字
Imgproc.CV_SHAPE_RECT;
Imgproc.CV_SHAPE_CROSS;
Imgproc.CV_SHAPE_ELLIPSE;
三种类型元素,腐蚀时效果不一样,在下面的程序运行时拖动slider,可以看到。
代码
package com.joe.vision.machine.vision.samples;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.core.Point;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.util.ResourceUtils;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
/**
* 膨胀与腐蚀
* 膨胀的作用:将白色区域变大
* 腐蚀的作用:将黑色区域变大
*/
public class MorphologyDemo1 {
private static final String[] ELEMENT_TYPE = {"矩形", "十字", "椭圆"};
private static final String[] MORPH_OP = {"腐蚀", "膨胀"};
private static final int MAX_KERNEL_SIZE = 100;
private Mat matImgSrc;
private Mat matImgDst = new Mat();
private int elementType = Imgproc.CV_SHAPE_RECT;
private int kernelSize = 0;
private boolean doErosion = true;
private JFrame frame;
private JLabel imgLabel;
public MorphologyDemo1(String[] args) throws FileNotFoundException {
matImgSrc = Imgcodecs.imread(getFilePath("static/time.jpg"));
if (matImgSrc.empty()) {
System.out.println("Empty image:" );
System.exit(0);
}
// Create and set up the window.
frame = new JFrame("膨胀和腐蚀的demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
Image img = HighGui.toBufferedImage(matImgSrc);
addComponentsToPane(frame.getContentPane(), img);
// Use the content pane's default BorderLayout. No need for
// setLayout(new BorderLayout());
// Display the window.
frame.pack();
frame.setVisible(true);
}
private void addComponentsToPane(Container pane, Image img) {
if (!(pane.getLayout() instanceof BorderLayout)) {
pane.add(new JLabel("Container doesn't use BorderLayout!"));
return;
}
JPanel sliderPanel = new JPanel();
sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS));
//构造元素类型下拉选框
JComboBox elementTypeBox = buildElementTypeBox();
sliderPanel.add(elementTypeBox);
sliderPanel.add(new JLabel("内核尺寸: 2n + 1"));
//构造slider工具条
JSlider slider = buildSlider();
sliderPanel.add(slider);
//构造操作类型下拉选框,操作分为腐蚀和膨胀
JComboBox morphOpBox = buildOperateType();
sliderPanel.add(morphOpBox);
pane.add(sliderPanel, BorderLayout.PAGE_START);
imgLabel = new JLabel(new ImageIcon(img));
pane.add(imgLabel, BorderLayout.CENTER);
}
private JComboBox buildOperateType() {
JComboBox morphOpBox = new JComboBox<>(MORPH_OP);
morphOpBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@SuppressWarnings("unchecked")
JComboBox cb = (JComboBox) e.getSource();
doErosion = cb.getSelectedIndex() == 0;
update();
}
});
return morphOpBox;
}
private JComboBox buildElementTypeBox() {
JComboBox elementTypeBox = new JComboBox<>(ELEMENT_TYPE);
elementTypeBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@SuppressWarnings("unchecked")
JComboBox cb = (JComboBox) e.getSource();
if (cb.getSelectedIndex() == 0) {
elementType = Imgproc.CV_SHAPE_RECT;
} else if (cb.getSelectedIndex() == 1) {
elementType = Imgproc.CV_SHAPE_CROSS;
} else if (cb.getSelectedIndex() == 2) {
elementType = Imgproc.CV_SHAPE_ELLIPSE;
}
update();
}
});
return elementTypeBox;
}
private JSlider buildSlider() {
JSlider slider = new JSlider(0, MAX_KERNEL_SIZE, 0);
slider.setMajorTickSpacing(5);
slider.setMinorTickSpacing(5);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider) e.getSource();
kernelSize = source.getValue();
update();
}
});
return slider;
}
private void update() {
//OpenCV提供了一个函数getStructuringElement,可以获取常用的结构元素的形状:矩形(包括线形)、椭圆(包括圆形)及十字形。
Mat element = Imgproc.getStructuringElement(elementType, new Size(2 * kernelSize + 1, 2 * kernelSize + 1), new Point(kernelSize, kernelSize));
if (doErosion) {
//腐蚀
erode(element);
} else {
//膨胀
dilate(element);
}
Image img = HighGui.toBufferedImage(matImgDst);
imgLabel.setIcon(new ImageIcon(img));
frame.repaint();
}
private void dilate(Mat element) {
Imgproc.dilate(matImgSrc, matImgDst, element);
}
private void erode(Mat element) {
Imgproc.erode(matImgSrc, matImgDst, element);
}
public String getFilePath(String filename) throws FileNotFoundException {
File file = ResourceUtils.getFile(filename);
return file.getAbsolutePath();
}
public static void main(String[] args) {
// Load the native OpenCV library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
new MorphologyDemo1(args);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
});
}
}
效果
原图:
腐蚀效果:黑色区域变大,图片黑化
膨胀效果:白色区域变大