OpenCV.轮廓发现与绘制

本文详细介绍了图像处理中的轮廓发现与绘制过程,包括使用OpenCV库的findContours函数进行轮廓检测,以及drawContours函数进行轮廓绘制。通过二值图像处理,找到边缘点并构建拓扑结构,实现对图像轮廓的精确提取。同时,提供了Java代码示例,展示了如何在实际应用中实现这一功能。
摘要由CSDN通过智能技术生成

轮廓发现与绘制

一般而言,图像的轮廓都是由一系列的像素点构成,这些像素点属于二值图像的前景图像,每个轮廓都是一组点,而各组点则组成了轮廓。该方式的原理很复杂,简述即通过定义一系列的边缘点类型与拓扑集合结构类型,然后对二值图像的扫描来完成边缘类型的寻找与拓扑结构的构建,以此完成轮廓的发现。轮廓发现的函数声明如下:

findContours(image, contours, hierarchy, mode, method, offset);

各参数解释如下:

  • image
    8单通道的输入图像。

  • contours
    List类型的像素点集合,即泛型为MatOfPoint类型。

  • hierarchy
    拓扑信息。

  • mode
    返回的轮廓拓扑模式,其枚举有以下四种:RETR_EXTERNAL(表示获取最大层最大的轮廓)RETR_LIST(表示获取所有轮廓)RETR_CCOMP(表示获取的所有轮廓呈现的双层组织结构,第一层为外部边界,第二层为孔边界)RETR_TREE(表示对获取的轮廓进行按照树结构组织,显示归属于嵌套层次)

  • method
    描述轮廓的方法,其枚举有以下四种:CHAIN_APPROX_NONE(将链式编码中的说有点都转换为点输出)CHAIN_APPROX_SIMPLE(压缩水平,垂直,倾斜部分的轮廓点输出)CHAIN_APPROX_TC89_L1(Teh-Chin链式逼近算法)CHAIN_APPROX_TC89_KCOS(Teh-Chin链式逼近算法)

  • offset
    是否有位移。无位移则该参数为相对原点值为Point(0,0)。

轮廓发现后即可使用轮廓绘制函数进行操作。由于轮廓发现计算的是List,那么迭代循环轮廓即可。轮廓绘制的函数声明如下:

drawContours(image, contours,contourIdx, color , thickness);

各参数解释如下:

  • image
    待绘制轮廓的图像。

  • contours
    List集合,即上文提到的轮廓发现输出集合。

  • contourIdx
    声明绘制第几个轮廓。

  • color
    线条颜色。

  • thickness
    厚度,通常为1或2。

本例采用二值输入作为源,但也可采用Canny边缘检测作为输入。前者是基于二者分割,后者基于梯度计算,后者一般而言可以更好的反应图像轮廓的信息。

Java代码(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 = houghCircles(filePath);

                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImage(writableImage);
                        }
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    
    private WritableImage contourDiscoveryAndRendering(String filePath) throws IOException {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        Mat src = Imgcodecs.imread(filePath);
        Mat dst = new Mat();

        Mat gray = new Mat();
        Mat binary = new Mat();

        // Binary image.
        Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
        Imgproc.threshold(gray, binary, 0,255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);

        // Contour discovery
        List<MatOfPoint> contours = new ArrayList<>();
        Mat hierarchy = new Mat();
        Imgproc.findContours(binary, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0,0));

        // Contour rendering
        dst.create(src.size(), src.type());
        for (int i = 0; i < contours.size(); i++) {
            Imgproc.drawContours(dst, contours, i, new Scalar(0,0,255),2);
        }

        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;
    }

}



运行图
在这里插入图片描述
原图在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值