当前位置: 首页 > article >正文

数字图像处理(c++ opencv):图像分割-基本边缘检测

Kirsch边缘检测

Kirsch边缘检测利用8个方向的核对图像进行检测,使每个像素点的结果为八个方向中响应最大的值。

Kirsch核:
在这里插入图片描述

#include<iostream>
#include<opencv2/opencv.hpp>
#include<algorithm>

using namespace cv;
using namespace std;

int main()
{
	Mat image, image_gray, image_bw, image_bw1, image_bw2, image_bw3;
	Mat image_bw4, image_bw5, image_bw6, image_bw7, image_bw8;

	image = imread("lena.png");  //读取图像;
	if (image.empty())
	{
		cout << "读取错误" << endl;
		return -1;
	}

	//转换为灰度图像
	cvtColor(image, image_gray, COLOR_BGR2GRAY);
	cv::imshow("image_gray", image_gray);
	
	//构建检测核
	Mat kernel1 = (cv::Mat_<float>(3, 3) << -3, -3, 5, -3, 0, 5, -3, -3, 5);//N
	Mat kernel2 = (cv::Mat_<float>(3, 3) << -3, 5, 5, -3, 0, 5, -3, -3, -3);//NW
	Mat kernel3 = (cv::Mat_<float>(3, 3) << 5, 5, 5, -3, 0, -3, -3, -3, -3);//W
	Mat kernel4 = (cv::Mat_<float>(3, 3) << 5, 5, -3, 5, 0, -3, -3, -3, -3);//SW
	Mat kernel5 = (cv::Mat_<float>(3, 3) << 5, -3, -3, 5, 0, -3, 5, -3, -3);//S
	Mat kernel6 = (cv::Mat_<float>(3, 3) << -3, -3, -3, 5, 0, -3, 5, 5, -3);//SE
	Mat kernel7 = (cv::Mat_<float>(3, 3) << -3, -3, -3, -3, 0, -3, 5, 5, 5);//E
	Mat kernel8 = (cv::Mat_<float>(3, 3) << -3, -3, -3, -3, 0, 5, -3, 5, 5);//NE

	//利用filter2D进行处理
	filter2D(image_gray, image_bw1, -1, kernel1);
	filter2D(image_gray, image_bw2, -1, kernel2);
	filter2D(image_gray, image_bw3, -1, kernel3);
	filter2D(image_gray, image_bw4, -1, kernel4);
	filter2D(image_gray, image_bw5, -1, kernel5);
	filter2D(image_gray, image_bw6, -1, kernel6);
	filter2D(image_gray, image_bw7, -1, kernel7);
	filter2D(image_gray, image_bw8, -1, kernel8);

	//绝对值
	convertScaleAbs(image_bw1, image_bw1);
	convertScaleAbs(image_bw2, image_bw2);
	convertScaleAbs(image_bw3, image_bw3);
	convertScaleAbs(image_bw4, image_bw4);
	convertScaleAbs(image_bw5, image_bw5);
	convertScaleAbs(image_bw6, image_bw6);
	convertScaleAbs(image_bw7, image_bw7);
	convertScaleAbs(image_bw8, image_bw8);

	image_bw = image_gray.clone();
	for (int i = 0; i < image_gray.rows; i++)
	{
		for (int j = 0; j < image_gray.cols; j++)
		{
			int arr[] = {image_bw1.at<uchar>(i, j), image_bw2.at<uchar>(i, j)
				, image_bw3.at<uchar>(i, j), image_bw4.at<uchar>(i, j), image_bw5.at<uchar>(i, j)
				, image_bw6.at<uchar>(i, j), image_bw7.at<uchar>(i, j), image_bw8.at<uchar>(i, j)};
			int max_num = *max_element(arr, arr + 8);
			image_bw.at<uchar>(i, j) = max_num;
		}
	}
	
	threshold(image_bw, image_bw, 220, 255, 0);
	cv::imshow("image_bw", image_bw);

	cv::waitKey(0);  //暂停,保持图像显示,等待按键结束
	return 0;
}

在这里插入图片描述

log边缘检测

log边缘检测(Marr-Hildreth边缘检测)

来源

Marr和Hildreth在研究图像边缘时,认为:

  • (a)灰度变化与图像尺度是相关的,即不同图像对应不同大小的算子;

  • (b)边缘(灰度值突变处)在一阶导数中表现为峰值或谷值,在二阶导数中表现为过零点。

因此认为边缘检测算子应该有以下特征

  • (a)是一个微分算子,能够计算图像中每个点的一阶或二阶导数;

  • (b)尺度能够调节,以便尺度较大的算子能够检测模糊边缘(模糊的边缘宽度较大),小算子检测清晰边缘。

数学原理

Marr和Hildreth认为满足上面特征的最好算子的函数为:高斯拉普拉斯(LOG)函数
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f3b45f403462413b9754f53e110c339f.png
来看看这个LOG函数怎么来的:

首先介绍一下用到的拉普拉斯算子高斯函数(均为二维空间中的表达)

拉普拉斯算子:拉普拉斯算子或是拉普拉斯算符(英语:Laplace operator, Laplacian)是由欧几里得空间中的一个函数的梯度的散度给出的微分算子,通常写成 在这里插入图片描述 ,也就是log算子的前半部分。有:
在这里插入图片描述
高斯:二维高斯分布常用于图像的卷积滤波,通过该分布可以取不同尺度的高斯核。G(x, y)也就是LOG函数后半部分,有在这里插入图片描述
在这里插入图片描述
根据上面两个的公式或定义,拉普拉斯可以计算图像的二阶导数,高斯可以构建不同尺度的算子,满足上面对算子的两个要求。LOG函数有:在这里插入图片描述
然后将高斯公式代入,推到得到最终的高斯拉普拉斯(LOG)函数表达式:
在这里插入图片描述
在这里插入图片描述

数字图像中的LOG检测算子核的构建

有两种方法构建检测核:

一是直接由LOG函数进行计算取核;(取样后还要标定系数使系数和为零)

二是首先构建高斯核,然后用拉普拉斯核进行卷积得到LOG核

拉普拉斯核:
在这里插入图片描述
由于拉普拉斯与高斯是线性计算,上面两种核的构建也就表示了使用LOG对图像进行边缘检测时有两种方法:

  • 一是直接用LOG核对图像进行卷积:
    在这里插入图片描述

  • 二是先对图像进行高斯滤波,再对滤波后的图像进行拉普拉斯变换:
    在这里插入图片描述

#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

void LOG1(Mat image_input, Mat image_output);
void LOG2(Mat image_input, Mat image_output);

int main()
{
	Mat img1 = imread("lena.png", 0);//读取灰度图像
	if (img1.empty())
	{
		cout << "读取错误" << endl;
		return -1;
	}
	imshow("img1", img1);

	Mat img2 = Mat(img1.size(), CV_8U, Scalar(0));
	Mat img3 = Mat(img1.size(), CV_8U, Scalar(0));
	LOG1(img1, img2);//LOG边缘检测
	imshow("img2", img2);

	LOG2(img1, img3);//LOG边缘检测
	imshow("img3", img3);
	waitKey();

	return 0;
}

void LOG1(Mat image_input, Mat image_output)
{
	Mat temp = Mat(image_input.size(), CV_64F, Scalar(0));

	//1、构建LOG算子
	Mat log_kernel = (cv::Mat_<float>(5, 5) << 0, 0, -1, 0, 0,
						   0, -1, -2, -1, 0,
						   -1, -2, 16, -2, -1,
						   0, -1, -2, -1, 0,
						   0, 0, -1, 0, 0);//LOG的5*5大小的核
	//2、卷积运算
	filter2D(image_input, image_output, -1, log_kernel);


}

void LOG2(Mat image_input, Mat image_output)
{

	GaussianBlur(image_input, image_output, Size(5, 5), 1, 1);
	Laplacian(image_output, image_output, image_input.depth(), 3, 1, 0, BORDER_DEFAULT);

}

在这里插入图片描述


http://www.kler.cn/a/399036.html

相关文章:

  • 几何合理的分片段感知的3D分子生成 FragGen - 评测
  • 树的直径计算:算法详解与实现
  • 机器学习-37-对ML的思考之机器学习发展的三个阶段和驱动AI发展三驾马车的由来
  • 文心一言编写小球反弹程序并优化
  • web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
  • AI驱动的桌面笔记应用Reor
  • PHP服务器如何开启WSS服务端Websocket
  • uni-app快速入门(七)--组件路由跳转和API路由跳转及参数传递
  • 【Qt 蓝牙服务器实现】
  • Cuda和Pytorch的兼容性
  • 大数据时代的隐私保护:数据治理的新视角
  • OMV7 树莓派 tf卡安装
  • 2024 RISC-V 中国峰会 演讲幻灯片和视频回放 均已公开
  • 21.UE5游戏存档,读档,函数库
  • Conda环境与Ubuntu环境移植详解
  • 【机器学习】机器学习中用到的高等数学知识-4.数值分析 (Numerical Analysis)
  • 怎么用Python+selenium自动化生成测试报告
  • Brave127编译指南 Windows篇:配置Git(四)
  • UE5运行时创建slate窗口
  • iOS UI自动化 Appium的元素定位方式及比较
  • matlab-fmincon函数做优化、optimoptions用法
  • 千图网 AI 绘画平台——智能图像创作工具
  • Ubuntu杀死指定进程
  • Linux:进程的优先级 进程切换
  • python 2小时学会八股文-数据结构
  • Spring MVC初探