OpenCV4.9更多形态转换

返回:OpenCV系列文章目录(持续更新中......)

上一篇:OpenCV4.9处理平滑图像

下一篇:OpenCV4.9更多形态转换

基于这两者,我们可以对图像进行更复杂的转换。在这里,我们简要讨论 OpenCV 提供的 5 个操作:

开放

它是通过图像的侵蚀和扩张获得的。

  • 可用于删除小物体(假设物体在深色前景上是明亮的)
  • 例如,请查看下面的示例。左边的图像是原始图像,右边的图像是应用开始变换后的结果。我们可以观察到小点已经消失了。

关闭

它是通过图像的扩张和侵蚀获得的。

  • 可用于去除小孔(黑暗区域)。

形态梯度

  • 它是图像的膨胀和侵蚀之间的区别。

  • 它对于查找对象的轮廓很有用,如下所示:

高顶丝质礼帽

它是输入图像与其开口之间的差异。

黑帽

这是关闭图像与其输入图像之间的差异

   

代码:
 

本教程的代码如下所示。您也可以在此处下载

C++

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>using namespace cv;Mat src, dst;int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;const char* window_name = "Morphology Transformations Demo";void Morphology_Operations( int, void* );int main( int argc, char** argv )
{CommandLineParser parser( argc, argv, "{@input | baboon.jpg | input image}" );src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );if (src.empty()){std::cout << "Could not open or find the image!\n" << std::endl;std::cout << "Usage: " << argv[0] << " <Input image>" << std::endl;return EXIT_FAILURE;}namedWindow( window_name, WINDOW_AUTOSIZE ); // Create windowcreateTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,&morph_elem, max_elem,Morphology_Operations );createTrackbar( "Kernel size:\n 2n +1", window_name,&morph_size, max_kernel_size,Morphology_Operations );Morphology_Operations( 0, 0 );waitKey(0);return 0;
}void Morphology_Operations( int, void* )
{// Since MORPH_X : 2,3,4,5 and 6int operation = morph_operator + 2;Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );morphologyEx( src, dst, operation, element );imshow( window_name, dst );
}

Java:

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;public class MorphologyDemo2 {private static final String[] MORPH_OP = { "Opening", "Closing", "Gradient", "Top Hat", "Black Hat" };private static final int[] MORPH_OP_TYPE = { Imgproc.MORPH_OPEN, Imgproc.MORPH_CLOSE,Imgproc.MORPH_GRADIENT, Imgproc.MORPH_TOPHAT, Imgproc.MORPH_BLACKHAT };private static final String[] ELEMENT_TYPE = { "Rectangle", "Cross", "Ellipse" };private static final int MAX_KERNEL_SIZE = 21;private Mat matImgSrc;private Mat matImgDst = new Mat();private int morphOpType = Imgproc.MORPH_OPEN;private int elementType = Imgproc.CV_SHAPE_RECT;private int kernelSize = 0;private JFrame frame;private JLabel imgLabel;public MorphologyDemo2(String[] args) {String imagePath = args.length > 0 ? args[0] : "../data/LinuxLogo.jpg";matImgSrc = Imgcodecs.imread(imagePath);if (matImgSrc.empty()) {System.out.println("Empty image: " + imagePath);System.exit(0);}// Create and set up the window.frame = new JFrame("Morphology Transformations 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<String> morphOpBox = new JComboBox<>(MORPH_OP);morphOpBox.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {@SuppressWarnings("unchecked")JComboBox<String> cb = (JComboBox<String>)e.getSource();morphOpType = MORPH_OP_TYPE[cb.getSelectedIndex()];update();}});sliderPanel.add(morphOpBox);JComboBox<String> elementTypeBox = new JComboBox<>(ELEMENT_TYPE);elementTypeBox.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {@SuppressWarnings("unchecked")JComboBox<String> cb = (JComboBox<String>)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();}});sliderPanel.add(elementTypeBox);sliderPanel.add(new JLabel("Kernel size: 2n + 1"));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() {@Overridepublic void stateChanged(ChangeEvent e) {JSlider source = (JSlider) e.getSource();kernelSize = source.getValue();update();}});sliderPanel.add(slider);pane.add(sliderPanel, BorderLayout.PAGE_START);imgLabel = new JLabel(new ImageIcon(img));pane.add(imgLabel, BorderLayout.CENTER);}private void update() {Mat element = Imgproc.getStructuringElement(elementType, new Size(2 * kernelSize + 1, 2 * kernelSize + 1),new Point(kernelSize, kernelSize));Imgproc.morphologyEx(matImgSrc, matImgDst, morphOpType, element);Image img = HighGui.toBufferedImage(matImgDst);imgLabel.setIcon(new ImageIcon(img));frame.repaint();}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() {new MorphologyDemo2(args);}});}
}

Python:

from __future__ import print_function
import cv2 as cv
import numpy as np
import argparsemorph_size = 0
max_operator = 4
max_elem = 2
max_kernel_size = 21
title_trackbar_operator_type = 'Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat'
title_trackbar_element_type = 'Element:\n 0: Rect - 1: Cross - 2: Ellipse'
title_trackbar_kernel_size = 'Kernel size:\n 2n + 1'
title_window = 'Morphology Transformations Demo'
morph_op_dic = {0: cv.MORPH_OPEN, 1: cv.MORPH_CLOSE, 2: cv.MORPH_GRADIENT, 3: cv.MORPH_TOPHAT, 4: cv.MORPH_BLACKHAT}def morphology_operations(val):morph_operator = cv.getTrackbarPos(title_trackbar_operator_type, title_window)morph_size = cv.getTrackbarPos(title_trackbar_kernel_size, title_window)morph_elem = 0val_type = cv.getTrackbarPos(title_trackbar_element_type, title_window)if val_type == 0:morph_elem = cv.MORPH_RECTelif val_type == 1:morph_elem = cv.MORPH_CROSSelif val_type == 2:morph_elem = cv.MORPH_ELLIPSEelement = cv.getStructuringElement(morph_elem, (2*morph_size + 1, 2*morph_size+1), (morph_size, morph_size))operation = morph_op_dic[morph_operator]dst = cv.morphologyEx(src, operation, element)cv.imshow(title_window, dst)parser = argparse.ArgumentParser(description='Code for More Morphology Transformations tutorial.')
parser.add_argument('--input', help='Path to input image.', default='LinuxLogo.jpg')
args = parser.parse_args()src = cv.imread(cv.samples.findFile(args.input))
if src is None:print('Could not open or find the image: ', args.input)exit(0)cv.namedWindow(title_window)
cv.createTrackbar(title_trackbar_operator_type, title_window , 0, max_operator, morphology_operations)
cv.createTrackbar(title_trackbar_element_type, title_window , 0, max_elem, morphology_operations)
cv.createTrackbar(title_trackbar_kernel_size, title_window , 0, max_kernel_size, morphology_operations)morphology_operations(0)
cv.waitKey()

解释

让我们检查一下 C++ 程序的一般结构:

 createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );

如您所见,值范围为 <2-6>,这就是为什么我们在 Trackbar 输入的值中添加 (+2) 的原因: 

 int operation = morph_operator + 2;

  element:要使用的内核。我们使用函数 cv::getStructuringElement 来定义我们自己的结构。


  • 返回:OpenCV系列文章目录(持续更新中......)

  • 上一篇:OpenCV4.9侵蚀和扩张

    下一篇:OpenCV系列文章目录(持续更新中......)

    目标

    在本教程中,您将学习如何:

  • 使用 OpenCV 函数 cv::morphologyEx 应用形态转换,例如:
    • 开放
    • 关闭
    • 形态梯度
    • 高顶丝质礼帽
    • 黑帽
  • 理论

    注意

    下面的解释属于 Bradski 和 Kaehler 的 Learning OpenCV 一书。

    在上一教程中,我们介绍了两个基本的形态操作:

  • 侵蚀
  • 扩张。
  • 它是通过图像的侵蚀和扩张获得的。

      

  • 可用于删除小物体(假设物体在深色前景上是明亮的)
  • 例如,请查看下面的示例。左边的图像是原始图像,右边的图像是应用开始变换后的结果。我们可以观察到小点已经消失了。
  • 它是通过图像的扩张和侵蚀获得的。

  •   

  • 可用于去除小孔(黑暗区域)。
  • 它是图像的膨胀和侵蚀之间的区别。

  •   

  • 它对于查找对象的轮廓很有用,如下所示:
  • 它是输入图像与其开口之间的差异。

  •   

  • 这是关闭图像与其输入图像之间的差异

  • 加载图像
  • 创建一个窗口以显示形态操作的结果
  • 创建三个跟踪栏供用户输入参数:
    • 第一个跟踪栏运算符返回要使用的形态操作类型 (morph_operator
  •  

     第二个 trackbar Element 返回 morph_elem,它表示我们的内核是什么样的结构

     createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,&morph_elem, max_elem,Morphology_Operations );

    最终的跟踪栏 Kernel Size 返回要使用的内核大小 (morph_size)

     createTrackbar( "Kernel size:\n 2n +1", window_name,&morph_size, max_kernel_size,Morphology_Operations );

     每次我们移动任何滑块时,都会调用用户的函数Morphology_Operations来执行新的形态操作,并且它将根据当前的跟踪栏值更新输出图像。

     
    void Morphology_Operations( int, void* )
    {// Since MORPH_X : 2,3,4,5 and 6int operation = morph_operator + 2;Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );morphologyEx( src, dst, operation, element );imshow( window_name, dst );
    }

    我们可以观察到,执行形态变换的关键函数是 cv::morphologyEx 。在此示例中,我们使用四个参数(其余参数保留为默认值):

  • src : 源(输入)图像
  • dst:输出图像
  • operation:要执行的形态转换类型。请注意,我们有 5 种替代方案:

  • 开幕: MORPH_OPEN : 2
  • 结束语: MORPH_CLOSE: 3
  • 梯度:MORPH_GRADIENT:4
  • 礼帽:MORPH_TOPHAT:5
  • 黑帽:MORPH_BLACKHAT:6
  •  

    结果

  • 编译上面的代码后,我们可以执行它,给出一个图像路径作为参数。使用图像的结果:baboon.png
  • 这是显示窗口的两个快照。第一张图片显示了使用带有交叉内核的运算符 Opening 后的输出。第二张图片(右侧)显示了使用带有椭圆内核的 Blackhat 运算符的结果。

参考文献:

1、《More Morphology Transformations》 ----Ana Huamán

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/809857.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FreeBuf 全球网络安全产业投融资观察(3月)

综述 据不完全统计&#xff0c;2024年3月&#xff0c;全球网络安全市场共发生投融资事件53起&#xff0c;其中国内4起&#xff0c;国外49起。 3月全球络安全产业投融资统计表&#xff08;数据来源&#xff1a;航行资本、36氪&#xff09; 整体而言&#xff0c;国内4起投融资事…

AI写作软件哪个好?这4款好评如潮

在信息时代&#xff0c;AI技术的发展的日新月异&#xff0c;AI写作软件也因此诞生。特别是人们对于高效、便捷的写作工具需求日益增长&#xff0c;AI写作软件作为一种新兴的工具&#xff0c;在帮助人们提升写作效率、拓展创作思路方面发挥着越来越重要的作用。这些AI写作软件为…

C语言 函数——代码风格

目录 基本的代码规范 程序版式 对齐&#xff08;Alignment&#xff09;与缩进&#xff08;indent&#xff09; 变量的对齐规则 空行——分隔程序段落的作用 代码行内的空格——增强单行清晰度 代码行 长行拆分 标识符命名规则 标识符命名的共性规则 windows应用程序…

PostgreSQL入门到实战-第十八弹

PostgreSQL入门到实战 PostgreSQL中表连接操作(二)官网地址PostgreSQL概述PostgreSQL中表别名命令理论PostgreSQL中表别名命令实战更新计划 PostgreSQL中表连接操作(二) 了解PostgreSQL表别名及其实际应用程序。 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容…

19c数据库/dev/shm/过小导致pga内存不够

pga_aggregate_limit已经设置了120G&#xff0c;alert还是报内存不够 查询select * from v$pgastat&#xff0c;发现MGA占了80G内存 查看/dev/shm: 发现设置了7G&#xff0c;操作系统是512G&#xff0c;正常情况下/dev/shm应该是操作系统的一半&#xff0c;修改为250G后数据库…

微信小程序 django+nodejs电影院票务售票选座系统324kd

小程序Android端运行软件 微信开发者工具/hbuiderx uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 前端&#xff1a;HTML5,CSS3 VUE 后端&#xff1a;java(springbootssm)/python(flaskdja…

vue3:菜单、标签页和面包屑联动效果

文章目录 1.整体思路2.实现过程 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; openAI 的 GPT 大模型的发展历程。 1.整体思路 在之前做的后台项目中&#xff0c;菜单、标签页和面包屑之间的联动&#xff0c;自己都是通过在路由前置守卫中&#xff0c;定义b…

微服务面试题二

1.什么是雪崩 微服务之间相互调用&#xff0c;因为调用链中的一个服务故障&#xff0c;引起整个链路都无法访问的情况。 如何解决雪崩&#xff1f; 超时处理&#xff1a;请求超时就返回错误信息&#xff0c;不会无休止等待仓壁模式&#xff1a;限定每个业务能使用的线程数&a…

WPS的JS宏如何批量实现文字的超链接

表格中需要对文字进行超链接&#xff0c;每个链接指引到不同的地址。例如&#xff1a; 实现如下表格中&#xff0c;文件名称超级链接到对应的文件路径上&#xff0c;点击对应的文件名称&#xff0c;即可打开对应的文件。 序号文件名称文件路径1变更申请与处理表.xls文档\系统…

第十三届蓝桥杯省赛大学B组编程题(c++)

D.刷题统计 二分(AC): 注意:二分时右边界 right 的确定 #include<iostream> using namespace std; long long a,b,n; bool check(long long x){long long tx/7;x%7;long long temp0;if(x<5) tempx*a;else temp5*a(x-5)*b;long long cntt*(5*a2*b)temp;return cnt&g…

MySOL之旅--------MySQL数据库基础( 2 )

本篇碎碎念:尽自己最大的努力,直到筋疲力尽为止,加油 今日份励志文案: 别人都在前进,我为什么要停下 目录 补上一条博客缺失的内容 常用数据类型 数值类型&#xff1a; 字符串类型&#xff1a; 日期/时间类型&#xff1a; 二进制类型&#xff1a; 其他类型&#xff1a; …

抖音小店入驻有什么条件?资金少,没经验的普通人做得起吗?

大家好&#xff0c;我是电商花花。 在直播电商的推动下&#xff0c;抖音小店独特的电商模式下吸引着众多的商家&#xff0c;吸引着一波又一波的创业者入驻&#xff0c;想要在抖音小店上开垦出属于自己的电商净土。 想要入驻抖音小店还需要一些条件&#xff0c;然后才能入驻成…

Python机器学习学习线路

随着人工智能技术的飞速发展&#xff0c;机器学习已经成为计算机科学领域的热门话题。Python&#xff0c;作为一门功能强大且易于上手的编程语言&#xff0c;成为学习机器学习的理想选择。本文将为您介绍一条Python机器学习的学习线路&#xff0c;帮助您逐步掌握机器学习的基础…

ARM/X86+FPGA轨道交通/工程车辆行业的解决方案

深圳推出首条无人驾驶地铁—深圳地铁20号线&#xff0c;可以说是深圳地铁的一次开创性的突破。智能交通不断突破的背后&#xff0c;需要很严格的硬件软件等控制系 统&#xff1b;地铁无人驾驶意味着信号系统、通信系统、综合监控系统、站台屏蔽门工程等项目必须严格执行验收。…

ping命令返回无法访问目标主机和请求超时浅析

在日常经常用ping命令测试网络是否通信正常&#xff0c;使用ping命令时也经常会遇到这两种情况&#xff0c;那么表示网络出现了问题。 1、请求超时的原因 可以看到“请求超时”没有收到任何回复。要知道&#xff0c;IP数据报是有生存时间的&#xff0c;当其生存时间为零时就会…

goproxy一键安装脚本(稳定易用的proxy软件)

goproxy 官网 https://goproxy.cn/ go语言开发的简单易用高性能proxy 软件 #!/bin/bash # time: 2021-05-11 17:47:39 # by: Chen ##执行脚本需要传入网络设备名 ##例&#xff1a;sh goproxy-install.sh eth0# 0.安装必须要的依赖 yum install wget -y || apt install wget -y…

vue简单使用二(循环)

目录 属性绑定 if判断&#xff1a; for循环&#xff1a; 属性绑定 代码的形式来说明 三元表达式的写法&#xff1a; if判断&#xff1a; for循环&#xff1a; 完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"…

ActiveMQ + MQTT 集群搭建(虚机版本) + Springboot使用配置

文章目录 前言一、ActiveMQ、 MQTT是什么&#xff1f;1.ActiveMQ介绍2.MQTT介绍 二、集群搭建步骤1.下载apache-activemq-5.15.12-bin.tar.gz2.上传apache-activemq-5.15.12-bin.tar.gz到服务器并解压文件到文件夹clusters、master、slave三个文件夹下面形成三个节点&#xff0…

Win10下安装Anaconda

Anaconda是可以便捷获取包且对包能够进行管理&#xff0c;同时对环境可以统一管理的发行版本&#xff0c;它包含了conda、Python在内的超过180个科学包及其依赖项。 安装Anaconda Anaconda官方下载网址&#xff1a;https://www.anaconda.com/download 官网页面中&#xff0c…

Docker日志查看神器

探索Dozzle&#xff1a;简单实用的Docker日志查看工具 在容器化应用程序的开发和部署中&#xff0c;日志管理是至关重要的一环。为了便于查看和监控Docker容器的日志信息&#xff0c;开发人员和运维团队需要便捷的工具。Dozzle 就是这样一款简单实用的Docker日志查看工具&…