图像处理之梯度及边缘检测算子

news2024/10/6 16:22:53

文章目录

  • 一、sobel 算子
  • 二、Scharr算子
  • 三、Roberts算子
  • 四、拉普拉斯算子

梯度是一个量变化的速度,在数学中通常使用求导、求偏导获取梯度或者某一方向上的梯度。
在数字图像中梯度可以看为像素值分别在x,y方向上的变化速度,因为数字图像的离散型,以及像素是最小处理单元的特性,求数字图像的梯度时,不需要求导,只需要进行加减运算即可。(其实就是求导的差分近似形式).如下图所示:
在这里插入图片描述

一、sobel 算子

Sobel算子包含两组 3 ∗ 3的矩阵,分别为横向及纵向模板,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。下面是 G x G_x Gx G y G_y Gy的模板。
G x = [ + 1 0 − 1 + 2 0 − 2 + 1 0 − 1 ] ∗ A G_x= \left[ \begin{array} {cccc} +1&0&-1\\ +2 &0&-2\\ +1 &0&-1 \end{array} \right]*A Gx= +1+2+1000121 A

G y = [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] ∗ A G_y= \left[ \begin{array} {cccc} +1&+2&+1\\ 0&0&0\\ -1&-2&-1 \end{array} \right]*A Gy= +101+202+101 A
如上式, G x G_x Gx G y G_y Gy分别表示对图像A进行横向和纵向梯度检测得到的结果。
取二者平方和即可得到图像上每一点的梯度值,即在该点同时计算 x x x方向与 y y y方向的梯度。
G = G x 2 + G y 2 G=\sqrt{G_x^2+G_y^2} G=Gx2+Gy2
该点的梯度方向可以通过取这两个值的比的反正切 a r c t a n arctan arctan得到:
Θ = a r c t a n ( G y G x ) \Theta=arctan\left(\frac{G_y}{G_x}\right) Θ=arctan(GxGy)
实现代码如下:

def SobelX(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            result[i,j] =v
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def SobelY(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] =h
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

def Sobel(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

检测结果如下:
在这里插入图片描述

二、Scharr算子

Scharr算子是Sobel算子的一种特殊形式。其核的形式如下:
[ + 3 0 − 3 + 10 0 − 10 + 3 0 − 3 ] \left[ \begin{array} {cccc} +3&0&-3\\ +10 &0&-10\\ +3&0&-3 \end{array} \right] +3+10+30003103
[ − 3 − 10 − 3 0 0 0 + 3 + 10 + 3 ] \left[ \begin{array} {cccc} -3&-10&-3\\ 0 &0&0\\ +3&+10&+3 \end{array} \right] 30+3100+1030+3
前面提到了,Sobel算子中核越大就能够更好的近似导数,准确度也更高。因此,在核比较小时如3×3时,Sobel核的准确度较差,使用Scharr算子代替3×3的Sobel核能够提高精度。因为加大了在x方向或y方向的权重,使得梯度角(梯度方向)不会距离x或y方向太远,因此误差也不会太大。例如,只求x方向的梯度时,核的中心点的x方向的两个权值远大于其它权值,这使得求得的梯度更靠近x方向,一定程度减小了误差。

def Scharr(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])
    G_y = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

检测结果:
在这里插入图片描述

三、Roberts算子

[ − 1 0 0 1 ] \left[ \begin{array} {cccc} -1&0\\ 0&1\\ \end{array} \right] [1001]
[ 0 − 1 1 0 ] \left[ \begin{array} {cccc} 0&-1\\ 1 &0\\ \end{array} \right] [0110]

Roberts算子的核如上图所示,是一种简单的交叉差分算法,在求±45°的梯度时最有效。
相比于一般的水平竖直方向的差分算子,Roberts算子能够有效地保留边缘的角点,并且计算速度较快。缺点是对细节敏感导致对噪声也十分敏感。
实现代码:

def Roberts(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0], [0,1]])
    G_y = np.array([[0, -1], [1,0]])
    result = np.zeros(img.shape)
    for i in range(0, width - 1):
        for j in range(0, height - 1):
            v = np.sum(G_x * img[i:i + 2, j:j + 2])
            h = np.sum(G_y * img[i:i + 2, j:j + 2])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

检测结果如下:
在这里插入图片描述

四、拉普拉斯算子

拉普拉斯算子可由二阶导数定义:
Δ 2 ( x , y ) = ∂ 2 f ( x , y ) ∂ x 2 + ∂ 2 f ( x , y ) ∂ y 2 \Delta^2(x,y)=\frac{\partial^2f(x,y)}{\partial x^2}+\frac{\partial^2f(x,y)}{\partial y^2} Δ2(x,y)=x22f(x,y)+y22f(x,y)
而在数字图像中离散化,用二阶差分表示为:
∂ 2 f ( x , y ) ∂ x 2 ≈ Δ x f ( i + 1 , j ) − Δ x f ( i , j ) = [ f ( i + 1 , j ) − f ( i , j ) ] − [ f ( i , j ) − f ( i − 1 , j ) ] = f ( i + 1 , j ) + f ( i − 1 , j ) − 2 f ( i , j ) \begin{align*} \begin{split} \frac{\partial^2f(x,y)}{\partial x^2} &\approx \Delta_xf(i+1,j)-\Delta_xf(i,j) \\ &= \left[ f(i+1,j)-f(i,j) \right]- \left[f(i,j)-f(i-1,j) \right] \\ &=f(i+1,j)+f(i-1,j)-2f(i,j) \end{split} \end{align*} x22f(x,y)Δxf(i+1,j)Δxf(i,j)=[f(i+1,j)f(i,j)][f(i,j)f(i1,j)]=f(i+1,j)+f(i1,j)2f(i,j)
同理可得:
∂ 2 f ( x , y ) ∂ y 2 ≈ f ( i , j + 1 ) + f ( i , j − 1 ) − 2 f ( i , j ) \frac{\partial^2f(x,y)}{\partial y^2} \approx f(i,j+1)+f(i,j-1)-2f(i,j) y22f(x,y)f(i,j+1)+f(i,j1)2f(i,j)
所以拉普拉斯算子可以表示为:
Δ 2 ( x , y ) = f ( i + 1 , j ) + f ( i − 1 , j ) + f ( i , j + 1 ) + f ( i , j − 1 ) − 4 f ( i , j ) \Delta^2(x,y)=f(i+1,j)+f(i-1,j)+f(i,j+1)+f(i,j-1)-4f(i,j) Δ2(x,y)=f(i+1,j)+f(i1,j)+f(i,j+1)+f(i,j1)4f(i,j)
其卷积核如下:
[ 0 1 0 1 − 4 1 0 1 0 ] \left[ \begin{array} {cccc} 0&1&0\\ 1&-4&1\\ 0&1&0 \end{array} \right] 010141010
拉普拉斯算子法其实是一种图像边缘增强算子,常用于图像锐化,在增强边缘的同时也增强了噪声,因此使用前需要进行平滑或滤波处理。如下图,可以看出,在函数值发生突变的情况时,二阶导数能够增强突变点与其两侧的对比度。在数字图像中就是图像边缘处得到了增强,因此实现了图像的锐化。
在这里插入图片描述

代码实现如下:

def Laplacian(img):
    temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    height, width = img.shape[::-1]
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            result[i][j] = np.abs(np.sum(temLaplacian * img[i:i + 3, j:j + 3]))
    return result

检测结果如下:
在这里插入图片描述
整体代码如下:

import numpy as np
import cv2
import imgShow as iS

def SobelX(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            result[i,j] =v
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

def SobelY(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] =h
            if(result[i,j]<threshold):
                result[i,j]=0
    return result

def Sobel(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Sobel(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    G_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Scharr(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])
    G_y = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            v = np.sum(G_x * img[i:i + 3, j:j + 3])
            h = np.sum(G_y * img[i:i + 3, j:j + 3])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Roberts(img,threshold):
    height = img.shape[0]
    width = img.shape[1]
    G_x = np.array([[-1, 0], [0,1]])
    G_y = np.array([[0, -1], [1,0]])
    result = np.zeros(img.shape)
    for i in range(0, width - 1):
        for j in range(0, height - 1):
            v = np.sum(G_x * img[i:i + 2, j:j + 2])
            h = np.sum(G_y * img[i:i + 2, j:j + 2])
            result[i,j] = np.sqrt((v ** 2) + (h ** 2))
            if(result[i,j]<threshold):
                result[i,j]=0
    return result
def Laplacian(img):
    temLaplacian = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    height, width = img.shape[::-1]
    result = np.zeros(img.shape)
    for i in range(0, width - 2):
        for j in range(0, height - 2):
            result[i][j] = np.abs(np.sum(temLaplacian * img[i:i + 3, j:j + 3]))
    return result

img=cv2.imread("./originImg/HorizontalAndVertical.jpg")
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
sobelImg=Sobel(img,56)
iS.showImagegray(sobelImg, img, 25, 15, 'sobelDetection', 'origin', './ProcessedImg/sobelDetection.jpg')
imageList=[]
origin_img=[img,'origin_img']
imageList.append(origin_img)
sobelx=SobelX(img,0)
sobel2=[sobelx,'Sobel_X']
imageList.append(sobel2)
sobely=SobelY(img,0)
sobel1=[sobely,'Sobel_Y']
imageList.append(sobel1)
sobelImg=Sobel(img,56)
sobel3=[sobelImg,'Sobel']
imageList.append(sobel3)
iS.showMultipleimages(imageList,25,25,'./ProcessedImg/sobelEdge.jpg')
img1=cv2.imread('./originImg/Goldhill.tif')
img1=cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
LapImg=Laplacian(img1)
iS.showImagegray(LapImg, img1, 25, 15, 'LapImg', 'origin', './ProcessedImg/lapImg.jpg')
scharrImg=Scharr(img,56)
iS.showImagegray(scharrImg, img, 25, 15, 'scharrDetection', 'origin', './ProcessedImg/scharrDetection.jpg')
robertsImg=Roberts(img,56)
iS.showImagegray(robertsImg, img, 25, 15, 'robertsDetection', 'origin', './ProcessedImg/robertsDetection.jpg')
# cv2.imshow('sobely',sobely)
# cv2.waitKey(0)
# cv2.destroyAllWindows()

画图代码:

import matplotlib.pyplot as plt
import numpy as np
import math
#图像实际大小为 W*100 * H*100 像素  ,
def showImagegray(newImg,oldImg,W,H,newImgtitle,oldImgtitle,saveImgpath):

    plt.figure(figsize=(W,H))
    plt.subplot(121)
    plt.title(oldImgtitle,fontsize=30)
    plt.axis('off')
    plt.imshow(oldImg, cmap='gray')

    plt.subplot(122)
    plt.title(newImgtitle,fontsize=30)
    plt.axis('off')
    plt.imshow(newImg, cmap='gray')
    # plt.tight_layout()  # 调整整体空白
    plt.savefig(saveImgpath)
    plt.show()

def showMultipleimages(imageList,W,H,saveImgpath):

    imageLength=len(imageList)

    plt.rcParams['figure.figsize'] = (W,H)
    col=row=math.ceil(np.sqrt(imageLength))
    fig, a = plt.subplots(col, row)
    m = 0
    for i in range(col):
        for j in range(row):
            a[i][j].set_title(imageList[m][1])
            a[i][j].imshow(imageList[m][0], cmap=plt.cm.gray)
            m += 1
        #去掉边框和刻度
        for ax in a.flat:
            ax.set_axis_off()

    fig.tight_layout()  # 调整整体空白
    plt.subplots_adjust(wspace=0.2, hspace=0.2)  # 调整子图间距
    plt.savefig(saveImgpath)
    plt.show()



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

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

相关文章

vue3 如何将页面生成 pdf 导出

原文链接&#xff1a;vue3 如何将页面生成 pdf 导出 前言 最近工作中有需要将一些前端页面(如报表页面等)导出为pdf的需求&#xff0c;博主采用的是html2Canvas jspdf。 步骤 1.引入两个依赖 npm i html2canvas npm i jspdf点击 jsPDF GitHub、jsPDF 文档 查看关于jsPDF更多…

连续两个季度利润暴跌95%以上,三星回不去了

这两年&#xff0c;小编本人电脑的 CPU、显卡等核心硬件毫无升级欲望不愿折腾。 反倒是内存条、固态硬盘容量不知不觉翻了好几倍! 老实说&#xff0c;对大多数像咱这样的普通用户来说&#xff0c;CPU、显卡从两三年前的主流型号升级到现在的主流型号&#xff1b; 价格明显上涨…

求助:交流耦合放大电路(HPF)的阻抗匹配问题

1、同向的交流耦合放大电路 电路如下图所示&#xff0c;信号源是一个上升时间1ns&#xff0c;下降时间15ns的脉冲信号&#xff0c;经过传输线的时延为5ns&#xff0c;然后通过放大器的同向交流耦合放大&#xff0c;这里我们可以明确的直到&#xff0c;下图中的R25就是端接电阻…

JavaWeb——基于Spring Boot的图书数字化管理系统的设计与实现

课程设计总结 1 概述 1.1 项目开发背景 随着信息技术的快速发展&#xff0c;数字化管理已经成为各行各业提高效率和管理水平的重要手段。在图书管理领域&#xff0c;数字化管理系统可以有效地提高管理效率&#xff0c;提供更好的用户体验。本项目旨在开发一个基于Spring…

静态反射C++枚举名字的超简方案——C++闲得慌系列之(一)

C 有枚举&#xff0c;编译后其值就被转成整数了&#xff0c;有时程序会有输出枚举名字的需求&#xff0c;朴素的做法就是手工一个个写字符串&#xff08;名字&#xff09;&#xff0c;并实现匹配&#xff0c;比如&#xff1a; enum class Shape {rectangle, circular}; std::s…

再获信通院认可!华住&持安零信任项目获评零信任最佳方案奖!

2023年7月12日&#xff0c;在中国通信标准化协会算网融合产业及标准推进委员会&#xff08;CCSA TC621&#xff09;在京组织召开“2023算网融合产业发展峰会-零信任产业发展论坛”上&#xff0c;“2022零信任优秀案例”成果正式发布。 持安科技与华住集团共同完成的 “华住集团…

【SpringBoot】| Spring Boot 常见的底层注解剖析

目录 一&#xff1a;Spring Boot 常见的底层注解 1. 容器功能 1.1 组件添加 方法一&#xff1a;使用Configuration注解Bean注解 方法二&#xff1a;使用Configuration注解Import注解 方法三&#xff1a;使用Configuration注解Conditional注解 1.2 原生xml配置文件引入…

ITDR何以成为IAM的最佳搭档?

摘 要 ❖随着零信任方案的逐渐落地&#xff0c;身份成为企业的新边界。同时&#xff0c;身份基础设施成为了攻击焦点。 ❖最近的身份攻击变得更加巧妙和复杂&#xff0c;甚至可以绕过MFA。 ❖当前的IAM解决方案只能起到预防作用。 ❖企业更需要一个能够检测和响应身份威胁的…

Mysql 备份与还原

目录 一 数据库备份的重要性与分类 1.数据备份的重要性 2. 造成数据丢失的原因 3.从物理与逻辑的角度&#xff0c;备份分为 4.从数据库的备份策略角度&#xff0c;备份可分为 二、常见的备份方法 1.物理冷备 2.专用备份工具mydump或mysqlhotcopy 3.启用二进制日志进行增量…

上手vue2的学习笔记5之在vue2项目中调用elment-ui

前言 上手vue2的学习笔记4之搭建vue环境 参考链接&#xff1a;vue2.0项目引入element-ui 一、安装elment-ui 进入搭建的vue项目中 cd vue_bing_test 安装 element npm i element-ui二、引入elment-ui elment官方教程 将main.js改成如下内容&#xff1a; import Vue fro…

详解C语言自定义类型

目录 一&#xff0c;结构体 1.结构体的基础知识 2.结构体的声明 一般的声明 ‍特殊的声明&#xff08;匿名结构体类型&#xff09; 3.结构体的自引用 4.结构体变量的定义和初始化 ‍结构体变量的定义 结构体变量的初始化 结构体变量的嵌套初始化 5.结构体内存对齐 …

240-960MHz带编码器的单片OOK 发射器CMT2157B

CMT2157B 是一款真正意义上的单芯片、高灵活性、超低功耗、带编码器的OOK 射频发射芯片&#xff0c;非常适合于240 至960 MHz 的无线应用场 合。该芯片可实现完全兼容市面上最常用的527、1527、2262 和2240 等编码格式。此外&#xff0c;还支持用户各种自定义编码。该芯片支持4…

c数据类型相关的关键字

变量的相关关键字 charshortintlongfloatdoublestructunion&#xff1a;与共用体相关的关键字enum&#xff1a;枚举signed&#xff1a;定义有符号的&#xff0c;可以保存正数&#xff0c;也可以保存负数unsigned&#xff1a;定义无符号&#xff0c;只能保存正数和0&#xff1b…

【知识点汇总】

罗曼罗兰说&#xff1a;“世界上只有一种真正的英雄主义&#xff0c;那就是在看清生活的真相之后&#xff0c;依然热爱生活。” JAVA开发知识点汇总 JAVAJVM垃圾标记算法三色标记法可达性分析法引用计数法 可以作为GCroots的对象有哪些&#xff1f;GC的种类和触发机制年轻代触…

1、nacos配置中心

一、配置中心存的意义 1、微服务中配置文件的问题 配置文件的问题&#xff1a; 配置文件的数量会随着服务的增加持续递增单个配置文件无法区分多个运行环境配置文件内容无法动态更新&#xff0c;需要重启服务 引入配置文件&#xff1a;刚才架构就会成为这样。是由配置中心统…

openvpnas安装,可视化远程连接控制

本次安装环境为 centos7.9 本次安装软件为 openvpnas, 默认是两个连接授权&#xff0c;可以通过代码注入实现多连接授权 1.基础环境以及Python36安装 yum install python36 python36-devel wget -y 2.安装 openvpnas 1.在线安装 yum -y install https://as-repository.openv…

ASEMI快恢复二极管MURF2080CT怎么看芯片的第一脚

编辑-Z MURF2080CT是一款高压、高速二极管&#xff0c;常用于电源、逆变器、电机驱动器等领域。该二极管具有以下特点&#xff1a; 1. 高压承受能力&#xff1a;MURF2080CT的最大反向电压可达800V&#xff0c;能够承受较高的电压。 2. 快速开关速度&#xff1a;该二极管的开关…

二叉树Morris遍历改写成后序遍历(java)

Morris 遍历 Morris 遍历改写成后序遍历解题思路代码演示 Morris 遍历 Morris 遍历改写成后序遍历 通过Morris遍历的顺序&#xff0c;将其调整为后序遍历的顺序&#xff0c; 解题思路 不明白morris 遍历&#xff0c;先查看上期 遍历二叉树的神级方法–Morris遍历 morris 遍历改…

ros2 foxy robot-localization 里程计 imu多传感器融合踩坑指南

前言 Robot_localization是一个基于卡尔曼滤波 ROS的包&#xff0c;可以对里程计 imu gps多种传感器进行数据融合&#xff0c;进而完成机器人的定位的算法。对于不懂卡尔曼滤波的小伙伴&#xff0c;通过修改配置文件就能顺利的使用大佬们造好的轮子&#xff0c;极大的降低了使…

【雕爷学编程】Arduino动手做(163)---大尺寸8x8LED方格屏模块7

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…