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

OpenCv高阶(8.0)——答题卡识别自动判分

文章目录

  • 前言
  • 一、代码分析及流程讲解
    • (一)初始化模块
      • 正确答案映射字典(题目序号: 正确选项索引)
      • 图像显示工具函数
    • (二)轮廓处理工具模块
    • (三)几何变换核心模块
  • 二、主处理流程
    • 图像读取
    • >>> 阶段1:图像预处理 <<<
      • 1、灰度转换(注意:COLOR_BGRA2GRAY适用于含alpha通道图像,通常使用COLOR_BGR2GRAY)
      • 2、高斯滤波(5x5卷积核去噪)
      • 3、Canny边缘检测(双阈值设置)
    • >>> 阶段2:答题卡定位 <<<
      • 1、轮廓检测(仅检测最外层轮廓)
      • 2、绘制所有轮廓(红色,3px线宽)
      • 3、轮廓筛选(按面积降序排列)
      • 4、执行透视变换
    • >>> 阶段3:选项识别 <<<
      • 1、灰度转换与二值化
      • 2、自适应阈值处理(反色二值化+OTSU算法)
      • 3、选项轮廓检测
      • 4、绘制绿色轮廓(1px线宽)
      • 5、选项筛选条件(宽高>20px,宽高比0.9-1.1)
      • 6、轮廓排序(从上到下)
    • >>> 阶段4:评分系统 <<<
      • 1、遍历每道题(每5个选项为一题)
      • 2、分数计算与显示
      • 3、在图像左上角添加红色分数文本
      • 4、结果展示
  • 总结


前言

一、代码分析及流程讲解

(一)初始化模块

import numpy as np
import cv2
import os

正确答案映射字典(题目序号: 正确选项索引)

ANSWER_KEY = {0:1, 1:4, 2:0, 3:3, 4:1}  

图像显示工具函数

def cv_show(name, value):"""可视化显示图像,按任意键继续"""cv2.imshow(name, value)cv2.waitKey(0)

(二)轮廓处理工具模块

轮廓定向排序函数
参数:
cnts: 轮廓列表
method: 排序方向(left-to-right/right-to-left/top-to-bottom/bottom-to-top)
返回值:
排序后的轮廓及边界框

def sort_contours(cnts, method='left-to-right'):reverse = Falsei = 0if method == 'right-to-left' or method == 'bottom-to-top':reverse = Trueif method == 'top-to-bottom' or method == 'bottom-to-top':i = 1# 获取轮廓边界框并排序boundingBoxes = [cv2.boundingRect(c) for c in cnts](cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))return cnts, boundingBoxes

保持宽高比的图像缩放函数
参数:
width: 目标宽度
height: 目标高度
inter: 插值方法

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):dim = None(h, w) = image.shape[:2]if width is None and height is None:return imageif width is None:r = height / float(h)dim = (int(w * r), height)else:r = width / float(w)dim = (width, int(h * r))return cv2.resize(image, dim, interpolation=inter)

(三)几何变换核心模块

坐标点规范化排序(左上、右上、右下、左下)
实现方法:
1. 计算各点坐标和,最小值为左上,最大值为右下
2. 计算坐标差值,最小值为右上,最大值为左下

def order_points(pts):rect = np.zeros((4, 2), dtype='float32')s = pts.sum(axis=1)rect[0] = pts[np.argmin(s)]  # 左上点rect[2] = pts[np.argmax(s)]  # 右下点diff = np.diff(pts, axis=1)rect[1] = pts[np.argmin(diff)]  # 右上点rect[3] = pts[np.argmax(diff)]  # 左下点return rect

透视变换函数
参数:
image: 原始图像
pts: 源图像四个坐标点
处理流程: 1. 坐标点规范化排序。2. 计算变换后图像尺寸。 3. 生成透视变换矩阵。 4. 执行透视变换

def four_point_transform(image, pts):rect = order_points(pts)(tl, tr, br, bl) = rect# 计算目标图像尺寸(取最大宽高)widthA = np.sqrt(((br[0]-bl[0])**2) + (br[1]-bl[1])**2)widthB = np.sqrt(((tr[0]-tl[0])**2) + (tr[1]-tl[1])**2)maxWidth = max(int(widthA), int(widthB))heightA = np.sqrt(((tr[0]-br[0])**2) + (tr[1]-br[1])**2)heightB = np.sqrt(((tl[0]-bl[0])**2) + (tl[1]-bl[1])**2)maxHeight = max(int(heightA), int(heightB))# 构建目标坐标矩阵dst = np.array([[0, 0],[maxWidth-1, 0],[maxWidth-1, maxHeight-1],[0, maxHeight-1]], dtype="float32")# 执行透视变换M = cv2.getPerspectiveTransform(rect, dst)warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))return warped

二、主处理流程

图像读取

image = cv2.imread('../data/images/test_01.png')
contours_img = image.copy()

>>> 阶段1:图像预处理 <<<

1、灰度转换(注意:COLOR_BGRA2GRAY适用于含alpha通道图像,通常使用COLOR_BGR2GRAY)

gray = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)  

2、高斯滤波(5x5卷积核去噪)

blurred = cv2.GaussianBlur(gray, (5,5), 0)
cv_show('blurred', blurred)

在这里插入图片描述

3、Canny边缘检测(双阈值设置)

edged = cv2.Canny(blurred, 75, 200)  
cv_show('edged', edged)

在这里插入图片描述

>>> 阶段2:答题卡定位 <<<

1、轮廓检测(仅检测最外层轮廓)

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

2、绘制所有轮廓(红色,3px线宽)

cv2.drawContours(contours_img, cnts, -1, (0,0,255), 3)  
cv_show('contours_img', contours_img)

在这里插入图片描述

3、轮廓筛选(按面积降序排列)

cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:# 多边形近似(精度=2%周长)peri = cv2.arcLength(c, True)approx = cv2.approxPolyDP(c, 0.02*peri, True)if len(approx) == 4:  # 识别四边形轮廓doCnt = approxbreak

4、执行透视变换

warped_t = four_point_transform(image, doCnt.reshape(4, 2))
warped_new = warped_t.copy()
cv_show('warped', warped_t)

在这里插入图片描述

>>> 阶段3:选项识别 <<<

1、灰度转换与二值化

warped_gray = cv2.cvtColor(warped_t, cv2.COLOR_BGRA2GRAY)

2、自适应阈值处理(反色二值化+OTSU算法)

thresh = cv2.threshold(warped_gray, 0, 255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv_show('thresh', thresh)

在这里插入图片描述

3、选项轮廓检测

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]

4、绘制绿色轮廓(1px线宽)

warped_contours = cv2.drawContours(warped_t.copy(), cnts, -1, (0,255,0), 1)
cv_show('warped_contours', warped_contours)

在这里插入图片描述

5、选项筛选条件(宽高>20px,宽高比0.9-1.1)

questionCnts = []
for c in cnts:(x, y, w, h) = cv2.boundingRect(c)ar = w / float(h)if w >= 20 and h >= 20 and 0.9 <= ar <= 1.1:questionCnts.append(c)

6、轮廓排序(从上到下)

questionCnts = sort_contours(questionCnts, method="top-to-bottom")[0]

>>> 阶段4:评分系统 <<<

correct = 0

1、遍历每道题(每5个选项为一题)

for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)):# 当前题目选项排序(左到右)cnts = sort_contours(questionCnts[i:i+5])[0]bubbled = None# 遍历每个选项for (j, c) in enumerate(cnts):# 创建选项掩膜mask = np.zeros(thresh.shape, dtype="uint8")cv_show('mask',mask)cv2.drawContours(mask, [c], -1, 255, -1)  # 填充式绘制# 应用掩膜统计像素thresh_mask_and = cv2.bitwise_and(thresh, thresh, mask=mask)cv_show('thresh_mask_and',thresh_mask_and)total = cv2.countNonZero(thresh_mask)# 记录最大填涂区域if bubbled is None or total > bubbled[0]:bubbled = (total, j)# 答案比对color = (0, 0, 255)  # 默认红色(错误)k = ANSWER_KEY[q]if k == bubbled[1]:color = (0, 255, 0)  # 绿色(正确)correct += 1# 绘制结果轮廓cv2.drawContours(warped_new, [cnts[k]], -1, color, 3)

在这里插入图片描述
通过掩膜的方法依次遍历每个选项。

2、分数计算与显示

score = (correct / 5.0) * 100
print("[INFO] score: {:.2f}%".format(score))

在这里插入图片描述

3、在图像左上角添加红色分数文本

cv2.putText(warped_new, "{:.2f}%".format(score), (10, 20),cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)

4、结果展示

cv_show('Original', image)        # 显示原始图像
cv_show("Exas", warped_new)     # 显示评分结果
cv2.waitKey(0)                    # 等待退出

在这里插入图片描述

总结

完整代码展示

import numpy as np
import cv2
import osANSWER_KEY={0:1,1:4,2:0,3:3,4:1}def cv_show(name,value):cv2.imshow(name,value)cv2.waitKey(0)def sort_contours(cnts,method='left-to-right'):reverse=Falsei=0if method=='right-to-left' or method=='bottom-to-top':reverse=Trueif method=='top-to-bottom' or method=='bottom-to-top':i=1boundingBoxes=[cv2.boundingRect(c) for c in cnts](cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),key=lambda b:b[1][i],reverse=reverse))return cnts,boundingBoxesdef resize(image,width=None,height=None,inter=cv2.INTER_AREA):dim=None(h,w)=image.shape[:2]if width is None and height is None:return imageif width is None:r=height/float(h)dim=(int(w*r),height)else:r=width/float(w)dim=(width,int(h*r))resized=cv2.resize(image,dim,interpolation=inter)return resizeddef order_points(pts):#一共四个坐标点rect=np.zeros((4,2),dtype='float32')#按顺序找到对应的坐标0123,分别是左上右上右下、左下s=pts.sum(axis=1)   #对矩阵的每一行进行求和操作rect[0]=pts[np.argmin(s)]rect[2]=pts[np.argmax(s)]diff=np.diff(pts,axis=1)rect[1]=pts[np.argmin(diff)]rect[3]=pts[np.argmax(diff)]return rectdef four_point_transform(image,pts):#获取输入的坐标点rect=order_points(pts)(tl,tr,br,bl)=rect#计算输入的w和h值widthA=np.sqrt(((br[0]-bl[0])**2) +( br[1] - bl[1])**2)widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + (tr[1] - tl[1]) ** 2)maxwidth=max(int(widthA),int(widthB))heightA=np.sqrt(((tr[0]-br[0])**2) +( tr[1] - br[1])**2)heightB=np.sqrt(((tl[0]-bl[0])**2) +( tl[1] - bl[1])**2)maxheight=max(int(heightA),int(heightB))dst=np.array([[0,0],[maxwidth,0],[maxwidth,maxheight],[0,maxheight]],dtype='float32')M=cv2.getPerspectiveTransform(rect,dst)warped=cv2.warpPerspective(image,M,(maxwidth,maxheight))return warped#预处理
image=cv2.imread('../data/images/test_01.png')
contours_img=image.copy()"灰度处理、做高斯滤波、边缘检测"
gray = cv2.cvtColor(image, cv2.COLOR_BGRA2GRAY)
blurred = cv2.GaussianBlur(gray,(5,5),0)
cv_show('blurred',blurred)
edged = cv2.Canny(blurred, 75, 200)
cv_show('edged',edged)#轮廓检测
cnts=cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)
cv_show('contours_img',contours_img)
doCnt=None#根据轮廓大小进行排序,准备透视变换
cnts=sorted(cnts,key=cv2.contourArea,reverse=True)
for c in cnts:peri=cv2.arcLength(c,True)approx=cv2.approxPolyDP(c,0.02*peri,True)if len(approx)==4:doCnt=approxbreak#执行透视变换
warped_t=four_point_transform(image,doCnt.reshape(4,2))
warped_new=warped_t.copy()
cv_show('warped',warped_t)
warped=cv2.cvtColor(warped_t,cv2.COLOR_BGRA2GRAY)#阈值处理
thresh=cv2.threshold(warped,0,255,cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv_show('thresh',thresh)
thresh_contours=thresh.copy()cnts=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
warped_contours=cv2.drawContours(warped_t,cnts,-1,(0,255,0),1)
cv_show('warped_contours',warped_contours)questionCnts=[]
for c in cnts:(x,y,w,h)=cv2.boundingRect(c)ar=w/float(h)#根据实际情况指定标准if w>20 and h >20 and 0.9<ar<=1.1:questionCnts.append(c)#按照从上到下的顺序排序
questionCnts=sort_contours(questionCnts,method="top-to-bottom")[0]
correct=0   #计算正确率#依次取出每行的数据
for (q,i) in enumerate(np.arange(0,len(questionCnts),5)):cnts=sort_contours(questionCnts[i:i+5])[0]bubbled=None#遍历每一个结果for (j,c) in enumerate(cnts):mask=np.zeros(thresh.shape,dtype='uint8')cv2.drawContours(mask,[c],-1,255,-1)#-1代表填充cv_show('mask',mask)thresh_mask_and=cv2.bitwise_and(thresh,thresh,mask=mask)cv_show('thresh_mask_and',thresh_mask_and)total=cv2.countNonZero(thresh_mask_and)if bubbled is None or total>bubbled[0]:bubbled=(total,j)color=(0,0,255)k=ANSWER_KEY[q]if k==bubbled[1]:color=(0,255,0)correct+=1cv2.drawContours(warped_new,[cnts[k]],-1,color,3)cv_show('warped',warped_new)score=(correct/5.0)*100
print("[INFO] score:{:.2f}%".format(score))
cv2.putText(warped_new,"{:.2f}%".format(score),(10,20),cv2.FONT_HERSHEY_SIMPLEX,0.9,(0,0,255),2)cv_show('Oringinal',image)
cv_show("Exas",warped_new)
cv2.waitKey(0)

该代码通过经典的OpenCV图像处理技术,构建了一个完整的答题卡自动评分系统,展现了计算机视觉在自动化领域的典型应用。其模块化设计、清晰的代码结构和可调参数,为二次开发提供了良好的基础,具备较高的实用价值和扩展潜力。

相关文章:

OpenCv高阶(8.0)——答题卡识别自动判分

文章目录 前言一、代码分析及流程讲解&#xff08;一&#xff09;初始化模块正确答案映射字典&#xff08;题目序号: 正确选项索引&#xff09;图像显示工具函数 &#xff08;二&#xff09;轮廓处理工具模块&#xff08;三&#xff09;几何变换核心模块 二、主处理流程图像读取…...

量子通信技术:原理、应用与未来展望

在当今数字化时代&#xff0c;信息安全是全球关注的焦点。随着量子计算技术的飞速发展&#xff0c;传统的加密方法面临着前所未有的挑战。量子通信技术作为一种新兴的通信手段&#xff0c;以其绝对安全的特性&#xff0c;为信息安全领域带来了新的希望。本文将深入探讨量子通信…...

Token的组成详解:解密数字身份凭证的构造艺术

在当今的互联网身份认证体系中&#xff0c;Token如同数字世界的"安全护照"&#xff0c;承载着用户的身份信息和访问权限。据统计&#xff0c;现代应用中80%以上的身份验证依赖于Token机制。本文将深入解析Token的各个组成部分&#xff0c;通过典型实例揭示其设计原理…...

【SFT监督微调总结】大模型SFT全解析:从原理到工具链,解锁AI微调的核心密码

文章目录 一. 什么是监督微调(SFT)?二. SFT的核心原理与流程2.1 基本原理2.2 训练流程三、SFT训练的常用方法四、SFT训练用的数据格式4.1、基础单轮指令格式1. Alpaca 格式2. 单轮QA格式3. 代码-注释对4.2、多轮对话格式1. ShareGPT 格式2. 层次化对话格式3. 角色扮演对话4.…...

MacBook Air A2179(Intel版)安装macOS Catalina所需时间

MacBook Air A2179&#xff08;Intel版&#xff09;安装macOS Catalina所需时间如下&#xff1a; 一、标准安装时间范围 常规安装&#xff08;通过App Store&#xff09; • 下载时间&#xff1a;约30-60分钟&#xff08;取决于网络速度&#xff0c;安装包约8GB&#xff09; •…...

Git的windows开发与linux开发配置

Git的基本配置 安装 linux可以使用包管理器安装windows可以使用 mingw的git&#xff1a;https://git-scm.com/downloadsTortoiseGit&#xff1a;https://tortoisegit.org/download/ 配置 分为系统配置–system、全局配置–global、项目配置–local 配置名称和邮箱 git co…...

使用Mathematica绘制一类矩阵的特征值图像

学习过线性代数的&#xff0c;都知道&#xff1a;矩阵的特征值非常神秘&#xff0c;但却携带着矩阵的重要信息。 今天&#xff0c;我们将展示&#xff1a;一类矩阵&#xff0c;其特征值集体有着很好的分布特征。 modifiedroots[c_List] : Block[{a DiagonalMatrix[ConstantAr…...

C++中的宏

0 资料 最值宏do{}while(0)的宏封装技巧 1 最值宏 - C最值的宏&#xff0c;在两个头文件中&#xff0c;分别为cfloat和climits。其中&#xff0c;float的最值宏在cfloat中&#xff0c;且cfloat没有负值的最小宏&#xff0c;而其他char、int和double是在climits中。如下// --…...

谷粒商城的三级分类实现

先查出全部的数据再分类 分类的一级分类是根据数据的Parent_id进行确定的&#xff0c;所以要进行筛选&#xff1a; 主方法&#xff1a; public List<CategoryEntity> listWithTree() {//1.查出所有分类List<CategoryEntity> entities baseMapper.selectList(nul…...

基于大模型预测的闭合性髌骨骨折诊疗全流程研究报告

目录 一、引言 1.1 研究背景与目的 1.2 研究意义与价值 二、大模型预测原理与方法 2.1 大模型概述 2.2 预测方法与数据输入 2.3 模型训练与优化 三、术前预测分析 3.1 骨折类型预测 3.2 损伤程度评估 3.3 潜在风险预测 四、手术方案制定 4.1 传统手术方案对比 4.…...

基于CodeBuddy的Craft完成一个数字华容道的小游戏

参考 CodeBuddy&#xff0c;AI 时代的智能编程伙伴 插件功能入门 总结 本文主要基于CodeBuddy的Craft 完成一个数字华容道的小游戏&#xff0c;如果读者还不清楚怎么安装&#xff0c;在本文的前面附上了CodeBuddy 编程助手的安装步骤。读者可以根据需求自行确定从那开始。 …...

一文掌握vue3基础,适合自学入门案例丰富

Vue3 本文从Vue3的基础语法出发&#xff0c;全面系统的介绍了Vue3的核心概念与应用&#xff0c;旨在帮助自学者更轻松地掌握Vue3。文章内容由浅入深&#xff0c;从通过CDN引入Vue3开始&#xff0c;逐步介绍了组合式API、模块化开发、以及常见的Vue3指令和功能并从单个html的使…...

OpenHarmony 5.0设置应用设置手势导航开关打开后重新关闭导航栏和设置界面重合

目录 1.背景 2.解决方案 1.背景 在OpenHarmony 5.0中从设置界面打开手势导航开关然后重新关闭&#xff0c;此时设置界面导航栏和设置列表主界面重合&#xff0c;导致设置界面无法点击最下面的关于设备 2.解决方案 首先参考之前的如何设置导航栏文档&#xff0c;我们可以自己…...

[ARM][汇编] 02.ARM 汇编常用简单指令

目录 1.数据传输指令 MRS - Move from Status Register 指令用途 指令语法 代码示例 读取 CPSR 到通用寄存器 在异常处理程序中读取 SPSR 使用场景 MSR - Move to Status Register 指令语法 使用场景 示例代码 改变处理器模式为管理模式 设置条件标志位 异常处理…...

系统架构设计(十七):微服务数据一致性和高可用策略

数据一致性问题 问题本质 由于每个微服务拥有独立数据库&#xff0c;跨服务操作不能用传统的数据库事务&#xff0c;面临“分布式事务”一致性挑战。 数据一致性策略 策略核心思想应用场景优缺点强一致性&#xff08;Strong Consistency&#xff09;所有操作实时同步成功&a…...

[Harmony]获取设备参数

获取屏幕宽度/屏幕高度/状态栏高度/导航栏高度/刘海高度/设备型号/系统版本号... DevicesUtil import window from ohos.window; import { common } from kit.AbilityKit; import display from ohos.display; import deviceInfo from ohos.deviceInfo; import i18n from ohos.…...

Python60日基础学习打卡D31

如何把一个文件&#xff0c;拆分成多个具有着独立功能的文件&#xff0c;然后通过import的方式&#xff0c;来调用这些文件&#xff1f;这样具有几个好处&#xff1a; 可以让项目文件变得更加规范和清晰可以让项目文件更加容易维护&#xff0c;修改某一个功能的时候&#xff0…...

命名常量集合接口INamedConstantCollection<T>实现

public interface INamedConstantCollection<TObject, TName> : IEnumerable<TObject>, IEnumerable where TName : IComparable{TObject this[TName name] { get; }TObject this[int index] { get; }int Count { get; }int Capacity { get; }} 这是一个泛型接口&…...

TYUT-企业级开发教程-第6章

这一章 考点不多 什么是缓存&#xff1f;为什么要设计出缓存&#xff1f; 企业级应用为了避免读取数据时受限于数据库的访问效率而导致整体系统性能偏低&#xff0c;通 常会在应用程序与数据库之间建立一种临时的数据存储机制&#xff0c;该临时存储数据的区域称 为缓存。缓存…...

反射在spring boot自动配置的应用

目录 一&#xff0c;背景 二&#xff0c;知识回顾 2.1 理解使用反射技术&#xff0c;读取配置文件创建目标对象&#xff08;成员变量&#xff0c;方法&#xff0c;构造方法等&#xff09; 三&#xff0c;springboot自动配置 3.1 反射在自动配置中的工作流程 3.2 浏览源码…...

项目进度延误,如何按时交付?

项目进度延误可以通过加强计划管理、优化资源分配、强化团队沟通、设置关键里程碑和风险管理机制等方式来实现按时交付。加强计划管理、优化资源分配、强化团队沟通、设置关键里程碑、风险管理机制。其中&#xff0c;加强计划管理尤为关键&#xff0c;因为明确而详细的计划能提…...

内网穿透:轻松实现外网访问本地服务

异步通知的是需要通过外网的域名地址请求到的&#xff0c;由于我们还没有真正上线&#xff0c;那支付平台如何请求到我们本地服务的呢&#xff1f; 这里可以使用【内网穿透】技术来实现&#xff0c;通过【内网穿透软件】将内网与外网通过隧道打通&#xff0c;外网可以读取内网…...

缺乏进度跟踪机制,如何掌握项目状态?

要有效掌握项目状态&#xff0c;必须建立明确的进度跟踪机制、使用专业的项目管理工具、定期召开沟通会议、设立清晰的关键里程碑和实施风险监控。其中&#xff0c;建立明确的进度跟踪机制是关键&#xff0c;通过系统地追踪项目各个阶段的完成情况&#xff0c;及时发现问题并采…...

ES 调优帖:关于索引合并参数 index.merge.policy.deletePctAllowed 的取值优化

最近发现了 lucene 9.5 版本把 merge 策略的默认参数改了。 * GITHUB#11761: TieredMergePolicy now allowed a maximum allowable deletes percentage of down to 5%, and the defaultmaximum allowable deletes percentage is changed from 33% to 20%. (Marc DMello)也就是…...

基于 STM32 单片机的实验室多参数安全监测系统设计与实现

一、系统总体设计 本系统以 STM32F103C8T6 单片机为核心,集成温湿度监测、烟雾检测、气体泄漏报警、人体移动监测等功能模块,通过 OLED 显示屏实时显示数据,并支持 Wi-Fi 远程传输。系统可对实验室异常环境参数(如高温、烟雾、燃气泄漏)及非法入侵实时报警,保障实验室安…...

Spring Boot-Swagger离线文档(插件方式)

Swagger2Markup简介 Swagger2Markup是Github上的一个开源项目。该项目主要用来将Swagger自动生成的文档转换成几种流行的格式以便于静态部署和使用&#xff0c;比如&#xff1a;AsciiDoc、Markdown、Confluence。 项目主页&#xff1a;https://github.com/Swagger2Markup/swagg…...

Linux下Docker使用阿里云镜像加速器

在中国大陆环境中配置 Docker 使用阿里云镜像加速器&#xff0c;并确保通过 Clash 代理访问 Docker Hub 我这里用的Debian12。 步骤 1&#xff1a;获取阿里云镜像加速器地址 登录阿里云容器镜像服务控制台&#xff1a;(qinyang.wang) 网址&#xff1a;阿里云登录 - 欢迎登录阿…...

每日c/c++题 备战蓝桥杯(洛谷P1440 求m区间内的最小值 详解(单调队列优化))

洛谷P1440 求m区间最小值&#xff1a;单调队列优化详解&#xff08;从暴力到O(n)的蜕变&#xff09; tags: [算法, 数据结构, 滑动窗口, 洛谷, C] 引言 在处理序列数据的区间查询问题时&#xff0c;暴力枚举往往难以应对大规模数据。本文以洛谷P1440为切入点&#xff0c;深入…...

从代码学习深度学习 - 预训练word2vec PyTorch版

文章目录 前言辅助工具1. 绘图工具 (`utils_for_huitu.py`)2. 数据处理工具 (`utils_for_data.py`)3. 训练辅助工具 (`utils_for_train.py`)预训练 Word2Vec - 主流程1. 环境设置与数据加载2. 跳元模型 (Skip-gram Model)2.1. 嵌入层 (Embedding Layer)2.2. 定义前向传播3. 训练…...

OpenCV图像边缘检测

1.概念 图像边缘检测是计算机视觉和图像处理中的基础任务&#xff0c;用于识别图像中像素值发生剧烈变化的区域&#xff0c;这些区域通常对应物体的边界、纹理变化或噪声。 1.1原理 图像中的边缘通常表现为灰度值的突变&#xff08;如从亮到暗或从暗到亮的急剧变化&#xff09…...

AI能源危机:人工智能发展与环境可持续性的矛盾与解决之道

AI对能源的渴求正在演变成一个巨大的挑战。这不仅仅关乎电费支出&#xff0c;其环境影响也十分严重&#xff0c;包括消耗宝贵的水资源、产生大量电子垃圾&#xff0c;以及增加温室气体排放。 随着AI模型变得越来越复杂并融入我们生活的更多领域&#xff0c;一个巨大的问题悬而…...

基于flask+vue的电影可视化与智能推荐系统

基于flaskvue爬虫的电影数据的智能推荐与可视化系统&#xff0c;能展示电影评分、评论情感分析等直观的数据可视化图表&#xff0c;还能通过协同过滤算法为用户提供个性化电影推荐&#xff0c;帮助用户发现更多感兴趣的电影作品&#xff0c;具体界面如图所示。 本系统主要技术架…...

初步认识HarmonyOS NEXT端云一体化开发

视频课程学习报名入口:HarmonyOS NEXT端云一体化开发 1、课程设计理念 本课程采用"四维能力成长模型"设计理念,通过“能看懂→能听懂→能上手→能实战”的渐进式学习路径,帮助零基础开发者实现从理论认知到商业级应用开发的跨越。该模型将学习过程划分为四个维度…...

基于单片机的车辆防盗系统设计与实现

标题:基于单片机的车辆防盗系统设计与实现 内容:1.摘要 随着汽车保有量的不断增加&#xff0c;车辆被盗问题日益严峻&#xff0c;车辆防盗成为人们关注的焦点。本研究的目的是设计并实现一种基于单片机的车辆防盗系统。采用单片机作为核心控制单元&#xff0c;结合传感器技术、…...

LSM Tree算法原理

LSM Tree(Log-Structured Merge Tree)是一种针对写密集型场景优化的数据结构,广泛应用于LevelDB、RocksDB等数据库引擎中。其核心原理如下: ‌1. 写入优化:顺序写代替随机写‌ ‌内存缓冲(MemTable)‌:写入操作首先被写入内存中的数据结构(如跳表或平衡树),…...

通过 API 获取 1688 平台店铺所有商品信息的完整流程

在电商运营和数据分析中&#xff0c;获取 1688 平台店铺的商品信息是一项重要的任务。1688 作为国内领先的 B2B 电商平台&#xff0c;提供了丰富的开放平台 API 接口&#xff0c;方便开发者获取店铺商品的详细信息。本文将详细介绍如何通过 Python 调用 1688 的 API 接口&#…...

Python代码加密与发布方案详解

更多内容请见: python3案例和总结-专栏介绍和目录 文章目录 一、基础加密方案二、商业级加密方案三、高级混淆方案四、商业化发布方案五、反逆向技术六、最佳实践建议七、常见问题解决Python作为解释型语言,其源代码容易被查看和修改。本文将详细介绍多种Python代码保护方案,…...

Tractor S--二维转一维,然后最小生成树

P3073 [USACO13FEB] Tractor S - 洛谷 转成一维点图&#xff0c;然后最小生成树&#xff0c;最后的最大值就是最后一个点&#xff0c;记得记录维护连通块 同样的二维转一维---Cow Ski Area G---二维图转一维tarjan缩点-CSDN博客 #include<bits/stdc.h> using namespac…...

5月20日day31打卡

文件的规范拆分和写法 知识点回顾 规范的文件命名规范的文件夹管理机器学习项目的拆分编码格式和类型注解 作业&#xff1a;尝试针对之前的心脏病项目&#xff0c;准备拆分的项目文件&#xff0c;思考下哪些部分可以未来复用。 补充介绍&#xff1a; pyc文件的介绍 知识点回顾 …...

基于Spring Boot + Vue的教师工作量管理系统设计与实现

一、项目简介 随着高校信息化管理的发展&#xff0c;教师工作量管理成为教务系统中不可或缺的一部分。为此&#xff0c;我们设计并开发了一个基于 Spring Boot Vue 的教师工作量管理系统&#xff0c;系统结构清晰&#xff0c;功能完备&#xff0c;支持管理员和教师两个角色。…...

海康工业相机白平衡比选择器对应的值被重置后,如何恢复原成像

做项目的时候&#xff0c;有时候手抖&#xff0c;一不小心把一个成熟稳定的项目的相机配置&#xff0c;重置了&#xff0c;如何进行恢复呢&#xff0c;在不知道之前配置数据的情况下。 我在做项目的时候&#xff0c;为了让这个相机成像稳定一点&#xff0c;尤其是做颜色检测时…...

VMWare清理后,残留服务删除方案详解

VMWare清理后&#xff0c;残留服务删除方案详解 在虚拟化技术日益普及的今天&#xff0c;VMWare作为行业领先的虚拟化软件&#xff0c;广泛应用于企业和服务器的管理中。然而&#xff0c;由于其复杂的架构和深层次的系统集成&#xff0c;VMWare的卸载过程往往并不顺利。即使通…...

STM32定时器简单采集编码器脉冲

MCU&#xff1a;STM32H723ZGT6 编码器&#xff1a;&#xff08;欧姆龙&#xff09;E6B2-CWZ1X&#xff1b;1000P/R&#xff1b;8根线信号线分别为 A A- B B- Z Z- 以及5V和GND&#xff1b; A 脉冲输出 B 脉冲输出 Z 零点信号 当编码器旋转到零点时&#xff0c;Z信号会发出一个脉…...

第 4 章:网络与总线——CAN / Ethernet / USB-OTG

本章目标: 深入理解三种关键通信总线(CAN、Ethernet、USB-OTG)的协议架构、硬件接口与软件驱动 掌握 STM32(或同类 MCU)中各总线的寄存器配置、中断/DMA 驱动框架 通过实战案例,实现基于 CAN 总线的节点通信、基于 Ethernet 的 TCP/IP 通信,以及基于 USB-OTG 的虚拟串口…...

【python进阶知识】Day 31 文件的规范拆分和写法

知识点 规范的文件命名规范的文件夹管理机器学习项目的拆分编码格式和类型注解 机器学习流程 - 数据加载&#xff1a;从文件、数据库、API 等获取原始数据。 - 命名参考&#xff1a;load_data.py 、data_loader.py - 数据探索与可视化&#xff1a;了解数据特性&#xff0c;初期…...

leetcode 162. Find Peak Element

题目描述 如果nums[i-1]<nums[i]并且nums[i]>nums[i1]&#xff0c;那么nums[i]就是峰值。除此情况之外&#xff0c;nums[i-1]和nums[i1]至少有一个大于nums[i]&#xff0c;因为题目已经保证相邻的元素不相等。坚持向上坡方向走一定能达到一个峰值&#xff0c;如果往两边走…...

2025系统架构师---案例题(押题)

1. 微服务相关的概念: 微服务是一种架构风格,它将单体应用划分为一组小服务,服务之间相互协作,实现业务功能每个服务运行在独立的进程中,服务间采用轻量级的通信机制协作(通常是HTTP/JSON),每个服务围绕业务能力进行构建,并且能够通过自动化机制独立的部署。 微服务有…...

t检验详解:原理、类型与应用指南

t检验详解&#xff1a;原理、类型与应用指南 t检验&#xff08;t-test&#xff09;是一种用于比较两组数据均值是否存在显著差异的统计方法&#xff0c;适用于数据近似正态分布且满足方差齐性的场景。以下从核心原理、检验类型、实施步骤到实际应用进行系统解析。 一、t检验的…...

使用 OpenCV 实现万花筒效果

万花筒效果&#xff08;Kaleidoscope Effect&#xff09;是一种图像处理效果&#xff0c;通过对图像进行对称旋转或镜像处理&#xff0c;产生具有多重反射和对称的艺术效果。它常用于视频编辑、视觉艺术、游戏设计等领域&#xff0c;为图像添加富有创意和视觉冲击力的效果。 在…...

Rocketmq broker 是主从架构还是集群架构,可以故障自动转移吗

RocketMQ Broker的架构与故障转移机制 RocketMQ的Broker架构同时采用了主从架构和集群架构&#xff0c;并且支持故障自动转移。下面详细说明&#xff1a; 一、架构类型 1. 集群架构 RocketMQ天然支持分布式集群部署 一个RocketMQ集群包含多个Broker组(每组有主从) 不同Bro…...