Canny算子

Canny算子_百度百科 (baidu.com)icon-default.png?t=N7T8https://baike.baidu.com/item/Canny%E7%AE%97%E5%AD%90/8821789?fr=ge_ala

图像处理中最经典的边沿检测算法: Canny边缘检测_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1U4411277i/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=7c3bfbf39d037fe80c97234396acc524

读取图像

需要处理成灰度图,因为输出会根据图片的尺寸来决定输出的位置以及窗口的大小,所以我这里自己初始化固定了窗口大小有输出的位置。

import numpy as np
import cv2

# 读取图像
image = cv2.imread('input_image.jpg', cv2.IMREAD_GRAYSCALE)

# 将灰度图像调整为固定大小
gray_resized = cv2.resize(image, (500, 400), interpolation=cv2.INTER_NEAREST)

# 获取屏幕尺寸
screen_height, screen_width = 1080, 1920

# 计算窗口左上角位置
window_x = int((screen_width - 500) / 2)
window_y = int((screen_height - 400) / 2)

# 创建窗口并显示结果
cv2.namedWindow('GrayImage', cv2.WINDOW_NORMAL)  # 设置窗口大小可调整
cv2.resizeWindow('GrayImage', 500, 400)
cv2.moveWindow('GrayImage', window_x, window_y)
cv2.imshow('GrayImage', gray_resized)
cv2.waitKey(0)
cv2.destroyAllWindows()

降噪(高斯滤波)

高斯滤波_百度百科 (baidu.com)icon-default.png?t=N7T8https://baike.baidu.com/item/%E9%AB%98%E6%96%AF%E6%BB%A4%E6%B3%A2/9032353?fr=ge_ala

OpenCV高斯滤波函数--GaussianBlur()参数说明_gaussianblur参数-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_28126689/article/details/105953157用于平滑图像以消除噪声,使得后续的梯度计算更加稳定。

# 高斯滤波
image_blur = cv2.GaussianBlur(image, (5, 5), 1)

梯度计算

计算水平和垂直方向的梯度,因为是向量的形式他这个只有四条线来划分,假设计算出水平方向是指向0,垂直方向是指向90,他结果就是指向45,如果角度是30也会变成40。

# 计算梯度
gradient_x = cv2.Sobel(image_blur, cv2.CV_64F, 1, 0, ksize=3)
gradient_y = cv2.Sobel(image_blur, cv2.CV_64F, 0, 1, ksize=3)

gradient_magnitude = np.sqrt(gradient_x ** 2 + gradient_y ** 2)
gradient_direction = np.arctan2(gradient_y, gradient_x) * 180 / np.pi

非极大值抑制

将梯度图像中的局部最大值保留,以消除非边缘像素。对于每个像素,只有梯度方向上的像素值是局部最大值,才会保留,其他像素将被抑制。

就是根据前面梯度的方向,假设他梯度方向是垂直的,如果当前位置上面的元素和下面位置的元素都小于当前位置的元素,则当前位置就是局部最大值,就应该保留下来,反之就会被抑制。

 # 非极大值抑制
gradient_magnitude_suppressed = np.zeros_like(gradient_magnitude)
    for i in range(1, gradient_magnitude.shape[0] - 1):
        for j in range(1, gradient_magnitude.shape[1] - 1):
            angle = gradient_direction[i, j]
            if (0 <= angle < 22.5) or (157.5 <= angle <= 180) or (-22.5 <= angle < 0) or (-180 <= angle < -157.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i, j + 1]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i, j - 1]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]
            elif (22.5 <= angle < 67.5) or (-157.5 <= angle < -112.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i - 1, j + 1]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i + 1, j - 1]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]
            elif (67.5 <= angle < 112.5) or (-112.5 <= angle < -67.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i - 1, j]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i + 1, j]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]
            elif (112.5 <= angle < 157.5) or (-67.5 <= angle < -22.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i - 1, j - 1]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i + 1, j + 1]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]

双阈值检测

像素梯度大于高阈值,则将其标记为强边缘;如果像素梯度介于低阈值和高阈值之间,则将其标记为弱边缘;否则,将其标记为非边缘。

介于两条线之间的就是可能保留可能淘汰还要看后续的处理,高分数线以上的直接保留,低分数线没达到的直接淘汰。

# 双阈值检测
gradient_magnitude_suppressed_normalized = cv2.normalize(gradient_magnitude_suppressed, None, 0, 255,
                                                             cv2.NORM_MINMAX, cv2.CV_8U)
    low_threshold = int(low_threshold)
    high_threshold = int(high_threshold)

    strong_edges = (gradient_magnitude_suppressed_normalized >= high_threshold)
    weak_edges = (gradient_magnitude_suppressed_normalized >= low_threshold) & (
                gradient_magnitude_suppressed_normalized < high_threshold)

边缘连接

将弱边缘连接到强边缘,以形成完整的边缘。如果弱边缘与任何一个强边缘相连,则将其标记为边缘;否则,将其标记为非边缘。

就是画了两条分数线,低分数线以下的直接淘汰,高分数以上的直接录取,如果介于两条线之间的,看有没有关系,如果有关系就保留,没有关系就淘汰。

# 边缘连接
strong_edges_idx = np.argwhere(strong_edges)
weak_edges_idx = np.argwhere(weak_edges)

edge_image = np.zeros_like(gradient_magnitude_suppressed_normalized)
edge_image[strong_edges] = 255

for i, j in weak_edges_idx:
    if np.any(strong_edges[i - 1:i + 2, j - 1:j + 2]):
       edge_image[i, j] = 255

代码 

import numpy as np
import cv2


def CannyEdgeDetection(image, sigma=1, low_threshold=20, high_threshold=50):
    # 1. 高斯滤波
    image_blur = cv2.GaussianBlur(image, (5, 5), sigma)

    # 2. 计算梯度
    gradient_x = cv2.Sobel(image_blur, cv2.CV_64F, 1, 0, ksize=3)
    gradient_y = cv2.Sobel(image_blur, cv2.CV_64F, 0, 1, ksize=3)

    gradient_magnitude = np.sqrt(gradient_x ** 2 + gradient_y ** 2)
    gradient_direction = np.arctan2(gradient_y, gradient_x) * 180 / np.pi

    # 3. 非极大值抑制
    gradient_magnitude_suppressed = np.zeros_like(gradient_magnitude)
    for i in range(1, gradient_magnitude.shape[0] - 1):
        for j in range(1, gradient_magnitude.shape[1] - 1):
            angle = gradient_direction[i, j]
            if (0 <= angle < 22.5) or (157.5 <= angle <= 180) or (-22.5 <= angle < 0) or (-180 <= angle < -157.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i, j + 1]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i, j - 1]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]
            elif (22.5 <= angle < 67.5) or (-157.5 <= angle < -112.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i - 1, j + 1]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i + 1, j - 1]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]
            elif (67.5 <= angle < 112.5) or (-112.5 <= angle < -67.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i - 1, j]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i + 1, j]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]
            elif (112.5 <= angle < 157.5) or (-67.5 <= angle < -22.5):
                if (gradient_magnitude[i, j] >= gradient_magnitude[i - 1, j - 1]) and (
                        gradient_magnitude[i, j] >= gradient_magnitude[i + 1, j + 1]):
                    gradient_magnitude_suppressed[i, j] = gradient_magnitude[i, j]

    # 4. 双阈值检测
    gradient_magnitude_suppressed_normalized = cv2.normalize(gradient_magnitude_suppressed, None, 0, 255,
                                                             cv2.NORM_MINMAX, cv2.CV_8U)
    low_threshold = int(low_threshold)
    high_threshold = int(high_threshold)

    strong_edges = (gradient_magnitude_suppressed_normalized >= high_threshold)
    weak_edges = (gradient_magnitude_suppressed_normalized >= low_threshold) & (
                gradient_magnitude_suppressed_normalized < high_threshold)

    # 5. 边缘连接
    strong_edges_idx = np.argwhere(strong_edges)
    weak_edges_idx = np.argwhere(weak_edges)

    edge_image = np.zeros_like(gradient_magnitude_suppressed_normalized)
    edge_image[strong_edges] = 255

    for i, j in weak_edges_idx:
        if np.any(strong_edges[i - 1:i + 2, j - 1:j + 2]):
            edge_image[i, j] = 255

    return edge_image


# 读取图像
image = cv2.imread('input_image.jpg', cv2.IMREAD_GRAYSCALE)

# 使用Canny算子进行边缘检测
edges = CannyEdgeDetection(image)

# 将边缘图像调整为固定大小
edges_resized = cv2.resize(edges, (500, 400), interpolation=cv2.INTER_NEAREST)

# 获取屏幕尺寸
screen_height, screen_width = 1080, 1920

# 计算窗口左上角位置
window_x = int((screen_width - 500) / 2)
window_y = int((screen_height - 400) / 2)

# 创建窗口并显示结果
cv2.namedWindow('Canny Edge Detection', cv2.WINDOW_NORMAL)  # 设置窗口大小可调整
cv2.resizeWindow('Canny Edge Detection', 500, 400)
cv2.moveWindow('Canny Edge Detection', window_x, window_y)
cv2.imshow('Canny Edge Detection', edges_resized)
cv2.waitKey(0)
cv2.destroyAllWindows()

 这个代码是用chatGpt生成的,思路大概是没错的,但是不知道能不能对的上,还有就是识别出来的图像不对,可能很稀疏的几个点,也可能很密集,这个就需要调整高阈值和低阈值来处理。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

达梦 结果拼接=多行结果返回一列字符串.

sql 转换 查询出多行数据 (select t.PROPERTY from JD_CODING t left join DELIVERY_OF c on t.VALUE c.TYPE where t.PROPERTY stackingType group by t.PROPERTY) 更改后 转为一列的拼接字符串 ( select listagg( distinct t.PROPERTY,,) within group ( order by t.P…

linux的磁盘分区与管理

磁盘分区与管理 识别磁盘 一块硬盘的“艺术”之旅&#xff08;硬盘空间使用&#xff0c;经历的步骤&#xff09; •识别硬盘 > 分区规划 > 格式化 > 挂载使用 Unix/Linux的基本哲学理念&#xff1a;一切皆文件 /dev:存放设备&#xff08;键盘、鼠标、光驱、硬盘……

AI 绘图要如何入门?有哪些好用的软件推荐?(附工具+教程+变现模式)

1.Ai绘画如何入门 不需要把Ai绘画想的很复杂 抛去复杂的应用 使用现成简单的工具 只需要学会提示词 描述你想要的画面即可 提示词 不需要太复杂&#xff0c;也不能太简单&#xff0c;太简单依赖于ai的基本样式&#xff0c;关键是要抓住你想要的核心描述 AI不太擅长理解人类的…

国产操作系统上部署SVN版本控制系统

原文链接&#xff1a;国产操作系统上部署SVN版本控制系统 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产操作系统上部署SVN版本控制系统的文章。SVN&#xff08;Subversion&#xff09;是一款广泛使用的版本控制系统&#xff0c;它…

如何正确申请DigiCert OV通配符SSL证书以保护多个子域名?

在网络时代&#xff0c;网站安全性日益受到重视&#xff0c;而HTTPS协议作为保护网站和用户隐私的重要手段&#xff0c;其重要性不言而喻。HTTPS通过加密技术保护数据在传输过程中的安全性&#xff0c;确保网站的可靠性和安全性。然而&#xff0c;许多网站管理员对于如何申请一…

spdlog日志库源码:线程池thread_pool

线程池 线程池本质上一组事先创建的子线程&#xff0c;用于并发完成特定任务的机制&#xff0c;避免运行过程中频繁创建、销毁线程&#xff0c;从而降低程序运行效率。通常&#xff0c;线程池主要涉及到以下几个方面问题&#xff1a; 如何创建线程池&#xff1f;线程池如何执…

Java中的JSON神器,如何轻松玩转复杂数据结构

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、揭秘JSON世界的基石 在Java的世界中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;它基于文本&#xff0c;易于阅读和编写&#xff0c;同时也易于…

kubernetes-PV与PVC、存储卷

一、PV和PVC详解 当前&#xff0c;存储的方式和种类有很多&#xff0c;并且各种存储的参数也需要非常专业的技术人员才能够了解。在Kubernetes集群中&#xff0c;放了方便我们的使用和管理&#xff0c;Kubernetes提出了PV和PVC的概念&#xff0c;这样Kubernetes集群的管理人员就…

OpenAI 文生图模型演进:DDPM、IDDPM、ADM、GLIDE、DALL-E 2、DALL-E 3

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

前端实习记录——git篇(一些问题与相关命令)

1、版本控制 &#xff08;1&#xff09;版本回滚 git log // 查看版本git reset --mixed HEAD^ // 回滚到修改状态&#xff0c;文件内容没有变化git reset --soft HEAD^ // 回滚暂存区&#xff0c;^的个数代表几个版本git reset --hard HEAD^ // 回滚到修改状态&#xff…

Reids高频面试题汇总总结

一、Redis基础 Redis是什么? Redis是一个开源的内存数据存储系统,它可以用作数据库、缓存和消息中间件。Redis支持多种数据结构,如字符串、哈希表、列表、集合、有序集合等,并提供了丰富的操作命令来操作这些数据结构。Redis的主要特点是什么? 高性能:Redis将数据存储在内…

Linux —— 动静态库

一、基本认识 1.什么是库&#xff1f; 在编译C或C时&#xff0c;在使用一些函数时&#xff0c;我们都需要先声明头文件&#xff0c;头文件中一般存放着这些函数的声明&#xff0c;而具体的实现方法&#xff0c;一般就被放在库中&#xff0c;库文件在编译链接的阶段会被链接到…

PADS做CAM文件时,提示填充宽度对于精确的焊盘填充过大

1、开发环境&#xff1a; PADS VX1.2 2、问题复现&#xff1a; 同一个PCB文件&#xff0c;设计验证没有错误。但是输出CAM光辉文件时&#xff0c;总是弹出“填充宽度对于精确的焊盘填充过大&#xff0c;填充宽度……”&#xff0c;如下图&#xff1a; 3、错误的方法&#xff1…

未来已来:Facebook的数字革命与社交转型

在当今数字化时代&#xff0c;Facebook作为全球最大的社交网络之一&#xff0c;不仅扮演着连接人们的桥梁&#xff0c;更是引领着社交行业的数字革命与转型。本文将深入探讨Facebook如何通过创新技术、改变用户体验以及应对挑战&#xff0c;塑造了未来社交的面貌&#xff0c;以…

Python数据处理,使用 tkinter 模块点击获取文件目录

Python数据处理&#xff0c;使用 tkinter 模块点击获取文件目录 正文 正文 当我们进行数据处理读取文件内数据的时候&#xff0c;通常&#xff0c;我们需要设定好一个存放当前文件所在目录的变量。比如如下目录&#xff1a; file_path rC:\Users\xxx\Desktop\DataSet\Data.c…

使用DataGrip连接跳板机后再连接远程服务器的mysql数据库

相比配置本地数据库就是多了一步SSH/SSL配置。 添加新的mysql连接&#xff0c;选择SSH/SSL&#xff0c;勾选Use SSH tunnel&#xff1a; 点击右边的…配置跳板机连接&#xff0c;输入账号密码&#xff0c;然后保存&#xff1a; 接着配置General&#xff0c;里面填上要连接的数…

了解运维基础

一、运维概述 1、运维岗位的收入情况 2、运维的职位定义 什么是运维&#xff1f; 在技术人员之间&#xff0c;一致对运维有一个开玩笑的认知&#xff1a;运维就是修电脑的、装网线的、背锅的岗位。 其实不然&#xff0c;运维是一个非常广泛的定义&#xff0c;在不同的公司不同…

洗地机有哪些牌子比较好?洗地机排行榜十大品牌

随着洗地机市场竞争的日益激烈&#xff0c;市场上涌现出数百个品牌的产品&#xff0c;涵盖了从入门级到高端的各类价位和功能。这种多样化的选择一方面极大地满足了用户的不同需求&#xff0c;但另一方面也让消费者在挑选时面临一定的困扰。在众多种类的洗地机中&#xff0c;如…

Redis之内存管理过期、淘汰机制

1.Redis内存管理 我们的redis是一个内存型数据库&#xff0c;我们的数据也都是放在内存中的&#xff0c;内存是有限的空间&#xff0c;当数据满了之后&#xff0c;我们要怎么样继续保证redis的可用性呢?我们就需要采取点管理措施和机制来保证我们redis的可用性。 在redis.co…

人脸检测--FaceNet(四)

FaceNet 是一个由 Google 研究团队开发的人脸识别系统&#xff0c;它基于深度学习技术&#xff0c;可以实现高精度的人脸识别、验证和聚类任务。FaceNet 通过学习直接从图像像素到人脸嵌入的映射&#xff0c;使得它在各种人脸识别任务中表现出色。下面是对 FaceNet 的详细介绍&…