8.2Roberts算子边缘检测

基本概念

Roberts算子是一种简单的一阶导数边缘检测算子,它通过计算图像在水平和垂直方向上的梯度来检测边缘。在OpenCV中,Roberts算子可以通过手动应用卷积核来实现。Roberts算子是一组2x2的小型滤波器,用于检测图像中的垂直和水平边缘。

Roberts算子掩模Roberts算子有两个掩模,分别用于检测水平和垂直方向上的边缘:

实现步骤

1. 应用掩模:将Roberts算子的掩模应用于图像。

2. 计算梯度:计算水平方向和垂直方向上的梯度。

3. 计算梯度幅度:通过水平梯度和垂直梯度的合成来得到最终的梯度幅度。

示例代码1

下面是基于C++的OpenCV代码示例,展示了如何使用Roberts算子来检测边缘。

步骤一:包含必要的头文件
首先,确保你的项目已经正确配置了OpenCV库,并且包含了必要的头文件。#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;步骤二:定义Roberts算子
Roberts算子的核如下所示:
Gx = [ 1  00 -1 ]Gy = [ 0  1-1  0 ]
在C++中,你可以通过创建一个Mat对象来表示这些核。Mat kernelGx = (Mat_<float>(2, 2) <<1, 0, 0, -1);
Mat kernelGy = (Mat_<float>(2, 2) <<0, 1,-1, 0);步骤三:加载并准备输入图像
你需要读取一个图像,并将其转换为灰度图像以简化边缘检测任务。Mat src = imread("path_to_your_image.jpg", IMREAD_GRAYSCALE);
if(src.empty())
{std::cout << "Error: Image cannot be loaded!" << std::endl;return -1;
}步骤四:应用Roberts算子
由于Roberts算子的大小是2x2,我们需要特别注意边界条件。在OpenCV中,你可以使用filter2D函数来应用自定义的卷积核。这里我们分别应用Gx和Gy核。Mat dstGx, dstGy;// Apply the kernels to the source image.
filter2D(src, dstGx, CV_32F, kernelGx);
filter2D(src, dstGy, CV_32F, kernelGy);// Convert back to CV_8UC1 (unsigned char) type for display.
Mat abs_dstGx, abs_dstGy;
convertScaleAbs(dstGx, abs_dstGx);
convertScaleAbs(dstGy, abs_dstGy);步骤五:组合结果
为了获得完整的边缘检测结果,通常需要合并Gx和Gy的结果。Mat edges;
addWeighted(abs_dstGx, 0.5, abs_dstGy, 0.5, 0, edges);步骤六:显示结果
最后,你可以使用imshow函数来展示原始图像和边缘检测后的结果。namedWindow("Original Image", WINDOW_AUTOSIZE);
imshow("Original Image", src);namedWindow("Edges", WINDOW_AUTOSIZE);
imshow("Edges", edges);waitKey(0);以上就是使用OpenCV和C++实现Roberts算子边缘检测的一个基本示例。
请根据实际情况调整路径和参数。

示例代码


#include "pch.h"
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;int main()
{Mat kernelGx = (Mat_<float>(2, 2) <<1, 0,0, -1);Mat kernelGy = (Mat_<float>(2, 2) <<0, 1,-1, 0);Mat src = imread("012.jpeg", IMREAD_GRAYSCALE);if (src.empty()){std::cout << "Error: Image cannot be loaded!" << std::endl;return -1;}Mat dstGx, dstGy;// Apply the kernels to the source image.filter2D(src, dstGx, CV_32F, kernelGx);filter2D(src, dstGy, CV_32F, kernelGy);// Convert back to CV_8UC1 (unsigned char) type for display.Mat abs_dstGx, abs_dstGy;convertScaleAbs(dstGx, abs_dstGx);convertScaleAbs(dstGy, abs_dstGy);Mat edges;addWeighted(abs_dstGx, 0.5, abs_dstGy, 0.5, 0, edges);namedWindow("Original Image", WINDOW_NORMAL);imshow("Original Image", src);namedWindow("Edges", WINDOW_NORMAL);imshow("Edges", edges);waitKey(0);return 0;
}

运行结果1

filter2D

filter2D函数是OpenCV提供的一个非常强大的工具,用于在图像上应用任何类型的卷积操作。它可以用于实现多种图像处理功能,如模糊、锐化、边缘检测等。

下面详细介绍filter2D函数的用法以及其参数的意义。

函数原型

void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel,Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT);参数说明
src: 输入图像。可以是多通道图像。
dst: 输出图像。它将具有与输入图像相同的尺寸和类型(除非指定不同的深度)。
ddepth: 指定输出图像的深度。如果设置为-1,则输出图像的深度与输入图像相同。否则,可以指定不同的深度,如CV_32F(32位浮点数)。
kernel: 卷积核(滤波器)。这是一个二维数组,用于定义卷积运算。核的大小通常是奇数,例如3x3或5x5,以便有一个中心点。
anchor: 卷积核相对于每个像素的锚点位置。默认情况下(Point(-1,-1)),锚点位于核的中心。你可以改变锚点的位置来控制卷积核相对于图像像素的作用方式。
delta: 可选的常数值,将在卷积操作后加到每一个像素上。
borderType: 边界处理类型。当卷积核覆盖图像的边界时,需要指定如何处理边界外的数据。OpenCV提供了多种边界处理方式,例如:
BORDER_CONSTANT: 使用常数值填充边界外区域。
BORDER_REPLICATE: 复制边界像素。
BORDER_REFLECT: 镜像反射边界。
BORDER_WRAP: 边界环绕(类似于纹理坐标)。
BORDER_REFLECT_101 或 BORDER_DEFAULT: 默认的边界反射方式。

示例代码2

下面是一个简单的例子,演示如何使用filter2D函数来应用一个3x3的Sobel核来检测水平边缘。

#include "pch.h"
#include <opencv2/opencv.hpp>
#include <iostream>int main(int argc, char** argv)
{// 加载图像cv::Mat src = cv::imread("033.jpeg", cv::IMREAD_GRAYSCALE);if (src.empty()){std::cout << "Error: Image cannot be loaded!" << std::endl;return -1;}// 定义Sobel核cv::Mat kernel = (cv::Mat_<float>(3, 3) <<-1, -2, -1,0, 0, 0,1, 2, 1);// 创建输出图像cv::Mat dst;// 应用filter2D函数cv::filter2D(src, dst, -1, kernel);// 显示结果cv::namedWindow("Original Image", cv::WINDOW_NORMAL);cv::imshow("Original Image", src);cv::namedWindow("Filtered Image", cv::WINDOW_NORMAL);cv::imshow("Filtered Image", dst);cv::waitKey(0);return 0;
}在这个例子中,我们使用了一个Sobel核来检测水平边缘。如果你想要检测垂直边缘,可以相应地改变核的值。此外,如果需要调整输出图像的深度,可以修改ddepth参数。例如,使用CV_32F可以得到浮点数输出,这有助于避免整数溢出的问题。

运行结果2

示例代码3

下面是一个使用OpenCV C++实现Roberts算子进行边缘检测的示例代码:#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;// 定义Roberts算子掩模
static const float robertsHorizontal[] = { 1, 0, 0, -1 };// 定义Roberts交叉算子水平方向的内核
static const float robertsVertical[] = { 0, 1, -1, 0 };void detectEdgesWithRoberts(const Mat &src, Mat &horizontal, Mat &vertical, Mat &magnitude) 
{// 将数据复制到一个std::vector中std::vector<float> data(robertsHorizontal, robertsHorizontal + 4);// 创建一个2x2的单通道浮点型矩阵Mat kernelHorizontal = Mat(2, 2, CV_32F, data.data());// 将数据复制到一个std::vector中std::vector<float> data2(robertsVertical, robertsVertical + 4);// 创建一个2x2的单通道浮点型矩阵Mat kernelVertical = Mat(2, 2, CV_32F, data2.data());// 水平方向的边缘检测filter2D(src, horizontal, CV_32F, kernelHorizontal, Point(-1, -1), 0, BORDER_REPLICATE);// 垂直方向的边缘检测filter2D(src, vertical, CV_32F, kernelVertical, Point(-1, -1), 0, BORDER_REPLICATE);//// 计算梯度幅度//magnitude = sqrt(horizontal.mul(horizontal) + vertical.mul(vertical));//一下代码来代替//在 OpenCV 中,cv::Mat 类没有提供 mul 成员函数用于矩阵元素级别的乘法。要执行逐元素的乘法,您应该使用 cv::multiply 函数。同时,您需要确保 magnitude 矩阵的类型适合进行平方和开方运算。//使用 cv::multiply 函数来计算水平和垂直梯度的平方。//使用 cv::sqrt 函数来计算平方和的平方根,得到梯度的幅度。//使用 cv::convertScaleAbs 函数将结果转换为 8 位无符号整数格式。//// 创建一个临时矩阵来保存平方和cv::Mat tmp;// 计算水平和垂直梯度的平方和cv::multiply(horizontal, horizontal, tmp);cv::multiply(vertical, vertical, tmp, 1.0);cv::sqrt(tmp, magnitude);//// 将结果转换为8位无符号整数convertScaleAbs(magnitude, magnitude);
}int main(int argc, char** argv)
{/*if (argc != 2){cout << "Usage: ./RobertsEdgeDetection <Image Path>" << endl;return -1;}*/// 加载图像Mat img = imread("27.png", IMREAD_GRAYSCALE);if (!img.data) {cout << "Error opening image" << endl;return -1;}// 初始化输出矩阵Mat horizontal, vertical, magnitude;// 执行Roberts边缘检测detectEdgesWithRoberts(img, horizontal, vertical, magnitude);// 显示结果namedWindow("Original Image", WINDOW_NORMAL);imshow("Original Image", img);namedWindow("Roberts Horizontal", WINDOW_NORMAL);imshow("Roberts Horizontal", horizontal);namedWindow("Roberts Vertical", WINDOW_NORMAL);imshow("Roberts Vertical", vertical);namedWindow("Magnitude", WINDOW_NORMAL);imshow("Magnitude", magnitude);waitKey(0);destroyAllWindows();return 0;
}代码解释
1. 定义Roberts算子掩模:使用静态数组来定义Roberts算子的两个掩模。
2. 边缘检测:使用 filter2D 函数分别计算水平方向和垂直方向上的边缘。
3. 计算梯度幅度:通过计算水平方向和垂直方向边缘的平方和的平方根来得到梯度幅度。
4. 转换数据类型:使用 convertScaleAbs 函数将浮点型数据转换为8位无符号整数,以便于显示。
5. 显示结果:使用 imshow 函数显示原始图像、水平方向边缘、垂直方向边缘以及最终的梯度幅度图。注意事项
•噪声敏感性:Roberts算子对噪声非常敏感,因此在实际应用中,通常需要对图像进行平滑处理(如使用高斯滤波器)来减少噪声的影响。
•边界处理:在使用 filter2D 时,需要注意边界处理方式。在这个示例中,使用了 BORDER_REPLICATE 边界条件来处理边界像素。
•掩模大小:Roberts算子的掩模大小为2x2,这意味着它只考虑了图像中的局部信息,因此对于精细的边缘检测可能不够精确。通过这个示例,你应该能够理解如何在OpenCV中使用C++实现Roberts算子进行边缘检测。

运行结果3

cv::Mat kernelHorizontal(2, 2, CV_32F, robertsHorizontal); 该行代码还是错误如果 cv::Mat(2, 2, CV_32F, robertsHorizontal) 这样的构造方式仍然报错,可能是因为 OpenCV 的 cv::Mat 构造函数并不直接接受一个外部的浮点数数组作为参数。在这种情况下,您可以先将数据复制到一个 std::vector<float> 中,然后使用 cv::Mat 的构造函数从 std::vector 创建矩阵,或者手动创建一个 cv::Mat 并使用 cv::Mat::operator=() 或 cv::Mat::copyTo() 方法来填充数据。以下是两种可能的解决方案:
解决方案 1: 使用 std::vector<float>
#include <opencv2/opencv.hpp>
#include <vector>int main() {// 定义Roberts交叉算子水平方向的内核static const float robertsHorizontal[] = { 1, 0, 0, -1 };// 将数据复制到一个std::vector中std::vector<float> data(robertsHorizontal, robertsHorizontal + 4);// 创建一个2x2的单通道浮点型矩阵cv::Mat kernelHorizontal = cv::Mat(2, 2, CV_32F, data.data());// 检查是否成功创建了内核if (kernelHorizontal.empty()) {std::cout << "Error: Matrix is empty!" << std::endl;} else {std::cout << "Kernel:\n" << kernelHorizontal << std::endl;}return 0;
}解决方案 2: 手动创建并填充 cv::Mat
#include <opencv2/opencv.hpp>int main() {// 定义Roberts交叉算子水平方向的内核static const float robertsHorizontal[] = { 1, 0, 0, -1 };// 创建一个2x2的单通道浮点型矩阵cv::Mat kernelHorizontal = cv::Mat::zeros(2, 2, CV_32F);// 填充矩阵kernelHorizontal.at<float>(0, 0) = robertsHorizontal[0];kernelHorizontal.at<float>(0, 1) = robertsHorizontal[1];kernelHorizontal.at<float>(1, 0) = robertsHorizontal[2];kernelHorizontal.at<float>(1, 1) = robertsHorizontal[3];// 检查是否成功创建了内核if (kernelHorizontal.empty()) {std::cout << "Error: Matrix is empty!" << std::endl;} else {std::cout << "Kernel:\n" << kernelHorizontal << std::endl;}return 0;
}
这两种方法都可以解决您的问题。选择哪种取决于您的具体需求和个人偏好。第一种方法更简洁一些,而第二种方法则提供了更多的控制权。

示例代码4

 #include "pch.h"
#include <iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2\imgproc\types_c.h>
#include<iostream>
using namespace std;
using namespace cv;
//#pragma comment(lib,"opencv_world450d.lib")
//Roberts算子实现
Mat roberts(Mat srcImage)
{Mat dstImage = srcImage.clone();int nRows = dstImage.rows;int nCols = dstImage.cols;for (int i = 0; i < nRows - 1; i++) {for (int j = 0; j < nCols - 1; j++) {//根据公式计算int t1 = (srcImage.at<uchar>(i, j) -srcImage.at<uchar>(i + 1, j + 1))*(srcImage.at<uchar>(i, j) -srcImage.at<uchar>(i + 1, j + 1));int t2 = (srcImage.at<uchar>(i + 1, j) -srcImage.at<uchar>(i, j + 1))*(srcImage.at<uchar>(i + 1, j) -srcImage.at<uchar>(i, j + 1));//计算g(x,y)dstImage.at<uchar>(i, j) = (uchar)sqrt(t1 + t2);}}return dstImage;
}void main()
{Mat srcImage = imread("356.jpeg");if (!srcImage.data) {cout << "falied to read" << endl;system("pause");return;}Mat srcGray;cvtColor(srcImage, srcGray, CV_BGR2GRAY);//高斯滤波GaussianBlur(srcGray, srcGray, Size(3, 3),0, 0, BORDER_DEFAULT);Mat dstImage = roberts(srcGray);namedWindow("源图", WINDOW_NORMAL);namedWindow("边缘图", WINDOW_NORMAL);imshow("源图", srcImage);imshow("边缘图", dstImage);waitKey(0);
}

运行结果4

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

GEE 案例:利用sentinel-2数据计算的NDVI指数对比植被退化情况

目录 简介 NDVI指数 数据 函数 ui.Chart.image.series(imageCollection, region, reducer, scale, xProperty) Arguments: Returns: ui.Chart 代码 结果 简介 利用sentinel-2数据计算的NDVI指数对比植被退化情况 NDVI指数 NDVI&#xff08;Normalized Difference Ve…

遥感图像目标检测数据集-DOTA数据集

DOTA数据集(v1.0版本和v1.5版本)&#xff0c;训练集1411张&#xff0c;验证集458张&#xff0c;测试集若干&#xff0c;共16种类别。数据集图片大小不一&#xff0c;需要进行裁剪&#xff0c;可设置裁剪重叠大小以及裁剪图片大小。此处按照默认参数裁剪&#xff0c;重叠200像素…

二极管选型

稳压二极管&#xff08;齐纳二极管&#xff09; 肖特基二极管 发光二极管 TVS二极管

记录一下ElementUI 3 在浏览器导入, table表格显示问题

当时问题忘了截图, 现在通过文字记录一下问题 我直接在html了引入 vue3 和 ElementUI 3 , 使用了table组件, 但是表格的td 总是只显示一列, 问题是我的 el-table-column 标签 没有结束标签 , 在vue文件模块化里写不需要结束标签, 在浏览器里无法直接识别出来, 所以他是渲染了第…

基于yolov8的肉鸡健康状态检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的肉鸡健康状态检测系统是一个先进的目标检测应用&#xff0c;旨在通过图像分析实现对肉鸡健康状态的快速、准确评估。该系统利用了YOLOv8模型的尖端技术&#xff0c;该模型由Ultralytics公司开发&#xff0c;具有卓越的检测精度和速度。 YOLOv8模型采…

C++---类与对象一

类的定义 class className{//成员字段//成员函数 };class定义类的关键字&#xff0c;className是自己决定的类名&#xff0c;{ } 为类的主体&#xff0c;花括号里是类的内容。类的内容大致分为类的成员属性&#xff08;变量&#xff09;和类的成员函数。注意定义类后面需要跟;…

理解人工智能、机器学习与深度学习的关系

1. 人工智能&#xff08;AI&#xff09;宏观的智能概念 人工智能&#xff08;Artificial Intelligence, AI&#xff09;是一个广泛的领域&#xff0c;涉及设计和开发能够表现出智能行为的计算机系统。这些系统可以模拟或执行类似于人类的认知功能&#xff0c;如学习、推理、决…

react 路由 react-router/react-router-dom

react-router-dom中包含react-router 安装前者即可 npm install react-router-dom -Simport { BrowserRouter as Router, Route, Link, Switch } from react-router-dom <Switch>组件&#xff0c;和switch语法一样&#xff0c;遇到匹配就结束&#xff0c;后面的<Route…

如何全面优化MySQL性能

MySQL数据库性能优化是一项复杂而细致的任务&#xff0c;它涉及到数据库设计、查询优化、服务器配置等多个方面。以下是几个关键的步骤和策略&#xff0c;旨在帮助提升MySQL数据库的运行效率&#xff1a; 优化数据库设计 选择合适的数据类型&#xff1a;合理选择数据类型不仅能…

树——数据结构

这次我来给大家讲解一下数据结构中的树 1. 树的概念 树是一种非线性的数据结构&#xff0c;它是由n(n>0&#xff09;个有限结点组成一个具有层次关系的集合。 叫做树的原因&#xff1a;看起来像一棵倒挂的树&#xff0c;根朝上&#xff0c;叶朝下。 特殊结点&#xff1a…

vmware中的ubuntu系统扩容分区

1.虚拟机关机 右击虚拟机/设置&#xff0c;进入虚拟机设置 3.启动虚拟机&#xff0c;进入命令行 4.fdisk -l查看要扩展的分区名 5.resize要扩容的分区 su root parted /dev/sda resizepart 3 100% fdisk -l resize2fs /dev/sda3 df -T完成 6.其他 进入磁盘管理 fdisk /d…

Doker学习笔记--黑马

介绍&#xff1a;快速构建、运行、管理应用的工具 在不同的服务器上部署多个应用&#xff0c;但是往往不同应用之间会有冲突&#xff0c;因为它们所依赖的环境&#xff0c;函数库&#xff0c;配置都不一样&#xff0c;此时docker在运行时形成了一个隔离环境&#xff08;容器&am…

idea上传jar包到nexus

注意&#xff1a;确保idea中项目为maven项目&#xff0c;并且在nexus中已经创建了maven私服。 1、配置pom.xml中推送代码配置 <distributionManagement> <repository> <id>releases</id> <url>http://127.0.0.1:8001/repository/myRelease/<…

c++9月18日

1&#xff0c;斐波那契数列 int str 0;int num 0;int kgo 0;int qto 0;cout<<"请输入字符串";string str1;getline(cin,str1);for(int i0;i<(int)(str1.size());i){if((str1.at(i)>65&&str1.at(i)<90)||(str1.at(i)>97&&str1.…

【oj刷题】二分查找篇:二分查找算法的原理和应用场景

前言&#xff1a; 二分查找算法&#xff0c;又称折半查找算法&#xff0c;是一种在有序数组中查找特定元素的高效查找方法。它通过将搜索区间不断缩小一半&#xff0c;从而在对数时间内找到目标元素。二分查找是基于分治策略的一种典型应用&#xff0c;能够高效的处理许多问题&…

Golang Beego+Vue打造的高校科研工作管理系统,让信息发布更及时,项目管理更透明

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

基于深度学习的眼部疾病检测识别系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 眼部疾病的早期诊断对于防止视力下降乃至失明至关重要。然而&#xff0c;专业的医疗资源分布不均&#xff0c;尤其是在偏远地区&#xff0c;人们很难获得专业的眼科医生提供的及时诊断服务。本系统…

密码学基础 C#实现门限共享密码算法

加密社 概念 门限秘密共享是一种密码学技术&#xff0c;将秘密 S 分割为 n 个部分&#xff0c;并将这些部分分发给 n 个参与者。所谓门限&#xff0c;是在分割这些秘密的时候&#xff0c;设置一个大小位于 1 和 n 之间的 k 值&#xff0c;使得给定任意 k−1 个或更少的秘密份额…

PaddleNLP本文分类及docker部署流程

本文记录使用PaddleNLP进行文本分类的全流程 参考&#xff1a;https://github.com/PaddlePaddle/PaddleNLP/tree/develop/legacy/applications/text_classification/multi_class 文章目录 1. 数据准备2. 模型训练2.1 准备关键库2.2 模型训练&#xff06;验证2.3 模型测试2.4 结…

comsol多物理场仿真技术与应用入门教学

一、COMSOL 多物理场仿真基础强化 几何建模 1、二维对象和三维对象的建模流程和快速建模方法&#xff0c;通过二维对象构建三维对象、三维提取二维结构等详细操作&#xff1b; 2、缩放、拉伸、阵列、移动、拷贝、镜像、旋转、线段、参数化曲线、布尔运算、转换等常用操作演示…