opencv邊緣檢測
本文目的
目的:學習使用opencv的邊緣檢測工具
語言:java
版本:opencv-410
簡介:主要介紹使用邊緣檢測工具來處理一件衣服,允許使用者調整邊緣檢測門檻值,濾波核心大小來觀察邊緣識别效果
分解介紹
主要函數
Imgproc.Canny(Mat image, Mat edges, double lowThreshold, double highThreshold, int apertureSize, boolean L2gradient)
參數說明
- · gray:原圖像,需是灰階圖像
- · detectedEdges:檢測器的輸出的邊緣圖像
- · lowThreshold:下限門檻值,如果像素梯度低于下限門檻值,則将像素不被認為邊緣
- · highThreshold:上限門檻值,如果像素梯度高于上限門檻值,則将像素被認為是邊緣(建議上限是下限的2倍或者3倍)
- · apertureSize:内部使用的Sobel核心的大小
- · L2gradient:計算圖像梯度幅值的标志,預設值為false
操作步驟
1.灰階變換
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
2.濾波處理
這裡采用中值波模糊
Imgproc.medianBlur(gray, gray,medianBlur_kenelSize % 2 == 1? medianBlur_kenelSize: medianBlur_kenelSize + 1);
3.邊緣檢測
Imgproc.Canny(gray, detectedEdges, lowThresh, lowThresh * RATIO, KERNEL_SIZE, false);
4.邊緣檢測結果和灰階圖檔合并
dst = new Mat(gray.size(), CvType.CV_8UC3, Scalar.all(0));gray.copyTo(dst, detectedEdges);
5.輸出到程式視窗
Image img = HighGui.toBufferedImage(dst);imgLabel.setIcon(new ImageIcon(img));
代碼
package com.joe.vision.machine.vision.samples;import org.opencv.core.Point;import org.opencv.core.*;import org.opencv.highgui.HighGui;import org.opencv.imgcodecs.Imgcodecs;import org.opencv.imgproc.Imgproc;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.FileNotFoundException;public class CannyTest {private static final int MAX_LOW_THRESHOLD = 100;private static final int RATIO = 3;private static final int KERNEL_SIZE = 3;private static final Size BLUR_SIZE = new Size(3, 3);private static int medianBlur_kenelSize = 1;private int lowThresh = 0;private Mat src;private Mat detectedEdges = new Mat();private Mat dst = new Mat();private Mat gray = new Mat();private JFrame frame;private JLabel imgLabel;private boolean iscloseOp = false;private boolean isInit = true;public CannyTest(String[] args) throws FileNotFoundException {String imagePath = FileLoadUtils.getFilePath("static/ppp.png");src = Imgcodecs.imread(imagePath);//圖檔太大,進行縮放Imgproc.resize(src, src, new Size(src.width() / 2, src.height() / 2));if (src.empty()) {System.out.println("Empty image: " + imagePath);System.exit(0);}// Create and set up the window.frame = new JFrame("Edge Map (Canny detector demo)");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// Set up the content pane.Image img = HighGui.toBufferedImage(src);addComponentsToPane(frame.getContentPane(), img);frame.pack();frame.setVisible(true);}public static void main(String[] args) {// Load the native OpenCV librarySystem.loadLibrary(Core.NATIVE_LIBRARY_NAME);// Schedule a job for the event dispatch thread:// creating and showing this application's GUI.javax.swing.SwingUtilities.invokeLater(new Runnable() {@Overridepublic void run() {try {new CannyTest(args);} catch (FileNotFoundException e) {e.printStackTrace();}}});}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));sliderPanel.add(new JLabel("下限門檻值"));JSlider slider = buildSlider();JSlider kenelSizeslider = buildKenelSlider();sliderPanel.add(slider);sliderPanel.add(new JLabel("濾波核心大小"));sliderPanel.add(kenelSizeslider);JButton button = buildCloseOp();sliderPanel.add(button);pane.add(sliderPanel, BorderLayout.PAGE_START);imgLabel = new JLabel(new ImageIcon(img));pane.add(imgLabel, BorderLayout.CENTER);}private JButton buildCloseOp() {JButton button = new JButton("閉運算-先膨脹再腐蝕");button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {iscloseOp = true;update();}});return button;}private JSlider buildSlider() {JSlider slider = new JSlider(0, MAX_LOW_THRESHOLD, 0);slider.setMajorTickSpacing(10);slider.setMinorTickSpacing(5);slider.setPaintTicks(true);slider.setPaintLabels(true);slider.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {JSlider source = (JSlider) e.getSource();lowThresh = source.getValue();update();}});return slider;}private JSlider buildKenelSlider() {JSlider slider = new JSlider(0, MAX_LOW_THRESHOLD, 0);slider.setMajorTickSpacing(10);slider.setMinorTickSpacing(5);slider.setPaintTicks(true);slider.setPaintLabels(true);slider.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {JSlider source = (JSlider) e.getSource();medianBlur_kenelSize = source.getValue();update();}});return slider;}private void update() {if (isInit) {//灰階變換Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);}//濾波處理Imgproc.medianBlur(gray, gray, medianBlur_kenelSize % 2 == 1 ? medianBlur_kenelSize : medianBlur_kenelSize + 1);//邊緣檢測Imgproc.Canny(gray, detectedEdges, lowThresh, lowThresh * RATIO, KERNEL_SIZE, false);dst = new Mat(gray.size(), CvType.CV_8UC3, Scalar.all(0));//圖像合并gray.copyTo(dst, detectedEdges);//閉運算if (iscloseOp) {Mat element = Imgproc.getStructuringElement(Imgproc.CV_SHAPE_RECT, new Size(2 * 5 + 1, 2 * 5 + 1), new Point(5, 5));Imgproc.morphologyEx(dst, dst, Imgproc.MORPH_CLOSE, element);iscloseOp = false;}gray = dst;Image img = HighGui.toBufferedImage(dst);imgLabel.setIcon(new ImageIcon(img));frame.repaint();}}
效果
原圖
不斷改變門檻值以及濾波的效果