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

第三部分:特征提取与目标检测

像边缘、角点、特定的纹理模式等都是图像的特征。提取这些特征是许多计算机视觉任务的关键第一步,例如图像匹配、对象识别、图像拼接等。目标检测则是在图像中找到特定对象(如人脸、汽车等)的位置。

本部分将涵盖以下关键主题:

  1. 特征点提取
    • 角点检测(Harris 角点)
    • SIFT/SURF 特征(概念介绍)
    • ORB 特征提取与匹配
  2. 轮廓检测与分析
    • 轮廓查找
    • 轮廓属性(面积、周长、形状)
    • 实战:简单形状识别
  3. 目标检测入门
    • 模板匹配
    • 级联分类器
    • 实战:人脸检测

我们将提供详细的解释和代码示例。公式部分将使用 LaTeX 格式方便复制和学习。


OpenCV 特征提取与目标检测 (第三部分)

欢迎来到 OpenCV 教程的第三部分!在前两部分,我们学习了图像的基础操作、像素访问以及基本的图像增强和滤波技术。现在,我们将提升一个层次,学习如何从图像中提取更抽象、更有意义的信息:特征。

为什么需要特征?

想象一下,你要识别一张照片里的某个人。你不会逐个比较两个图像中所有像素点是否完全一致,因为光照、角度、距离等变化都会导致像素值改变。你会寻找这个人的眼睛、鼻子、嘴巴等关键部位的形状、相对位置等信息,这些就是特征

特征提取就是寻找这些有区分度、相对稳定(对光照、旋转、缩放不敏感)的图像区域或点。提取到特征后,我们可以用它们来:

  • 匹配不同图像中的同一个物体或场景(如图像拼接、三维重建)。
  • 识别图像中的特定对象(如人脸、汽车)。
  • 跟踪视频中移动的物体。
  • 分析图像的结构和内容。

让我们开始学习这些强大的技术!

1. 特征点提取

特征点是图像中具有独特性、易于识别和跟踪的点,例如角点、图像纹理变化剧烈的点等。

1.1 角点检测 (Corner Detection)

角点是两条或多条边相交的点,它在各个方向上的像素强度变化都非常明显。因此,角点是图像中非常重要的特征点。

Harris 角点检测

Harris 角点检测是一种经典的角点检测算法。其基本思想是:如果在图像中的一个窗口沿任何方向移动,窗口内的像素灰度都发生显著变化,那么这个窗口所在的区域可能是一个角点。

OpenCV 提供了 cv2.cornerHarris() 函数来实现 Harris 角点检测。

Python

import cv2
import numpy as np# --- 练习 1.1: Harris 角点检测 ---# 1. 加载图像并转换为灰度图 (角点检测通常在灰度图上进行)
# Harris 角点检测的输入图像需要是 float32 类型
image_path = 'your_image.jpg'
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")image_color = np.zeros((400, 600, 3), dtype=np.uint8)cv2.putText(image_color, "Placeholder Image", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)# 将灰度图像转换为 float32
image_float = np.float32(image)# 2. 进行 Harris 角点检测
# 参数: src (输入图像, float32), blockSize (用于角点检测的邻域大小),
#       ksize (Sobel算子的大小,用于计算梯度), k (Harris检测器参数,通常在0.04-0.06)
harris_corners = cv2.cornerHarris(image_float, blockSize=2, ksize=3, k=0.04)# 3. 标记检测到的角点
# 结果 harris_corners 是一个浮点图像,值越大表示越可能是角点
# 我们对其进行阈值处理,并将角点位置在原始彩色图像上用圆圈标记出来
# 阈值可以根据 harris_corners 的最大值来设置,例如最大值的 1%
threshold = 0.01 * harris_corners.max()# 复制原始彩色图像,用于标记
output_image = image_color.copy()# 遍历结果图像,在R值大于阈值的位置绘制圆圈
# 注意: harris_corners 的维度与输入图像相同
# np.where(condition) 会返回满足条件的元素的索引 (y_coords, x_coords)
strong_corners_indices = np.where(harris_corners > threshold)# strong_corners_indices 是一个元组,第一个元素是所有满足条件的行的索引,第二个是所有满足条件的列的索引
y_coords, x_coords = strong_corners_indices# 在原彩色图上绘制圆圈
for i in range(len(x_coords)):center = (x_coords[i], y_coords[i])cv2.circle(output_image, center, 5, (0, 255, 0), 2) # 绿色圆圈,半径5,线宽2# 4. 显示结果
cv2.imshow('Original Image', image_color)
cv2.imshow('Harris Corners', output_image)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 1.1 完成 ---")

练习提示:

  • 尝试调整 blockSizeksizek 参数,观察检测到的角点数量和位置的变化。
  • 调整阈值 (threshold) 也会显著影响结果。较高的阈值会检测到更少的、更明显的角点。
1.2 SIFT/SURF 特征 (概念介绍)

SIFT (Scale-Invariant Feature Transform)SURF (Speeded Up Robust Features) 是两种非常著名的、对图像缩放和旋转具有不变性的局部特征点检测和描述算法。

  • 它们都能在图像中找到具有独特性的特征点(称为关键点)。
  • 对于每个关键点,它们都会计算一个描述符(一串数字),用来描述关键点周围区域的纹理信息。这个描述符对于光照、视角、缩放、旋转都有一定的鲁棒性。
  • SIFT 和 SURF 算法相对复杂且计算量较大。

重要提示: SIFT 和 SURF 算法在某些国家是受专利保护的。OpenCV 的主模块 (opencv-python) 可能不包含这些算法。你可能需要安装 opencv-contrib-python 库来使用它们。但是,由于专利问题和后续出现的更优秀的免费算法,SIFT 和 SURF 在学术界和工业界的使用受到一定限制。因此,本教程仅概念性介绍它们,我们将把重点放在一个免费且高效的替代品:ORB 特征。

1.3 ORB 特征提取与匹配

ORB (Oriented FAST and Rotated BRIEF) 是一种高效且免费的特征点检测和描述算法。它结合了 FAST 算法来检测关键点,并对 BRIEF 描述符进行了改进,使其具有方向和一定的尺度不变性。

ORB 的核心是两个主要部分:

  1. 检测器: 使用改进的 FAST 算法来寻找关键点。FAST 算法速度非常快,通过比较中心像素与周围圆环像素的灰度值来判断是否为关键点。ORB 在此基础上增加了多尺度检测和方向信息。
  2. 描述符: 使用改进的 BRIEF 描述符来描述关键点周围的区域。BRIEF 描述符通过比较关键点周围随机选取的像素对的灰度值来生成一个二进制串。ORB 对 BRIEF 进行了旋转使其具有旋转不变性。

特征匹配

提取到图像的特征点及其描述符后,我们可以进行特征匹配。特征匹配的目的是在两幅图像中找到对应于同一物理点的特征点对。常用的匹配方法是比较描述符之间的相似度(例如,对于 ORB 的二进制描述符,可以使用汉明距离)。

BFMatcher (Brute-Force Matcher)

BFMatcher 是一种简单的特征匹配器。它对第一组描述符中的每个描述符,计算与第二组描述符中所有描述符的距离,然后找到最近的一个或几个。

通常,我们会使用 KNN (K-Nearest Neighbors) 匹配,找到每个描述符的 k 个最近邻,然后应用 Lowe's Ratio Test 进行过滤:如果最佳匹配的距离与次佳匹配的距离之比小于一个阈值(例如 0.75),则认为这是一个好的匹配点。

Python

import cv2
import numpy as np# --- 练习 1.3: ORB 特征提取与匹配 ---# 1. 加载两张图像 (最好包含一些相同的物体或场景)
# 请替换成你自己的图片路径
image_path1 = 'your_image1.jpg'
image_path2 = 'your_image2.jpg'
try:image1 = cv2.imread(image_path1, cv2.IMREAD_GRAYSCALE) # ORB通常在灰度图上工作image2 = cv2.imread(image_path2, cv2.IMREAD_GRAYSCALE)if image1 is None:raise FileNotFoundError(f"图片文件未找到: {image_path1}")if image2 is None:raise FileNotFoundError(f"图片文件未找到: {image_path2}")print("成功加载两张图像。")
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")print("将使用模拟图像代替,无法演示实际匹配效果。")# 如果图片加载失败,创建两个简单的模拟图像image1 = np.zeros((300, 400), dtype=np.uint8)cv2.putText(image1, "Image 1 Placeholder", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)image2 = np.zeros((300, 400), dtype=np.uint8)cv2.putText(image2, "Image 2 Placeholder", (50, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)# 2. 创建 ORB 特征检测器对象
orb = cv2.ORB_create(nfeatures=5000, # 最多检测的特征点数量scaleFactor=1.2, # 图像金字塔的缩放因子nlevels=8, # 图像金字塔的层数edgeThreshold=31, # 忽略边缘区域的像素数量firstLevel=0, # 金字塔的第一层WTA_K=2, # 描述符生成算法scoreType=cv2.ORB_HARRIS_SCORE, # 使用Harris角点响应或FAST角点响应patchSize=31 # 描述符计算的区域大小
)# 3. 检测关键点和计算描述符
# kp: 关键点列表
# des: 描述符 (numpy数组)
kp1, des1 = orb.detectAndCompute(image1, None)
kp2, des2 = orb.detectAndCompute(image2, None)# 确保描述符是 float32 类型,有些匹配器可能需要
# ORB 描述符是二进制的,这里不需要转换,但对于SIFT/SURF可能需要print(f"图像1检测到 {len(kp1)} 个关键点")
print(f"图像2检测到 {len(kp2)} 个关键点")# 4. 创建 Brute-Force 匹配器
# 对于ORB的二进制描述符,使用 cv2.NORM_HAMMING
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False) # crossCheck=True 会进行双向匹配过滤# 5. 进行特征匹配 (使用 KNN 匹配)
# k=2 表示为每个关键点找到 2 个最近邻
matches = bf.knnMatch(des1, des2, k=2)# 6. 应用 Lowe's Ratio Test 过滤好的匹配点
good_matches = []
ratio_threshold = 0.75 # 比例阈值for m, n in matches:# m是最佳匹配,n是次佳匹配if m.distance < ratio_threshold * n.distance:good_matches.append(m)print(f"经过 Lowe's Ratio Test 过滤后,找到 {len(good_matches)} 个好的匹配点")# 7. 绘制匹配结果
# 参数: img1, kp1, img2, kp2, matches, outImg, flags
# flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS 表示不绘制没有匹配点的关键点
match_image = cv2.drawMatchesKnn(image1, kp1, image2, kp2, [good_matches], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)# 8. 显示结果
cv2.imshow('ORB Feature Matches', match_image)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 1.3 完成 ---")

练习提示:

  • 尝试使用包含相同物体但拍摄角度、距离略有差异的两张图片。
  • 调整 ORB_create() 函数中的参数,例如 nfeatures,观察检测到的关键点数量和匹配结果的变化。
  • 调整 Lowe's Ratio Test 中的 ratio_threshold,较低的阈值会得到更严格(更少但更可靠)的匹配点。

2. 轮廓检测与分析

轮廓是连接所有连续的、具有相同颜色或亮度的点的曲线。它们代表了物体的边界。轮廓在物体检测、形状分析和识别、图像分割等领域非常有用。

查找轮廓通常在二值图像(只有黑白两种颜色)上进行。

2.1 轮廓查找

OpenCV 提供了 cv2.findContours() 函数来查找图像中的轮廓。

Python

import cv2
import numpy as np# --- 练习 2.1: 轮廓查找 ---# 1. 加载图像并转换为灰度图
image_path = 'your_image.jpg'
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")image_color = np.zeros((400, 600, 3), dtype=np.uint8)cv2.putText(image_color, "Placeholder Image", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)# 2. 对灰度图进行二值化处理 (阈值分割)
# findContours 函数通常在二值图像上操作
# cv2.THRESH_BINARY: 大于阈值的设为最大值 (255), 否则设为0
# cv2.THRESH_OTSU: 使用Otsu算法自动寻找最佳阈值
ret, binary_image = cv2.threshold(image_gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 3. 查找轮廓
# cv2.findContours() 函数会返回轮廓列表和对应的层级关系
# 参数: image (输入图像, 8位单通道,通常是二值图), mode (轮廓检索模式), method (轮廓近似方法)
# RETR_TREE: 检索所有轮廓并建立完整的层级树
# CHAIN_APPROX_SIMPLE: 压缩水平、垂直和对角线段,只保留端点
# 注意: OpenCV 4.x 版本 findContours 返回值顺序变了,前面是image,后面是轮廓和层级
contours, hierarchy = cv2.findContours(binary_image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)print(f"检测到 {len(contours)} 个轮廓")# 4. 在原始彩色图像上绘制所有轮廓
# 参数: image (绘制目标图像), contours (轮廓列表), contourIdx (要绘制的轮廓索引,-1表示所有),
#       color (颜色), thickness (线宽)
# 复制原始彩色图像,以免修改原图
image_with_contours = image_color.copy()
cv2.drawContours(image_with_contours, contours, -1, (0, 255, 0), 2) # 绿色,线宽2# 5. 显示结果
cv2.imshow('Original Image', image_color)
cv2.imshow('Binary Image', binary_image)
cv2.imshow('Contours', image_with_contours)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 2.1 完成 ---")

练习提示:

  • cv2.findContours() 函数会改变输入图像,所以在查找轮廓时通常传入二值图像的副本或查找后不再使用该二值图像。
  • 尝试不同的 mode (如 cv2.RETR_LIST 不建立层级关系) 和 method (如 cv2.CHAIN_APPROX_NONE 存储所有轮廓点) 参数,观察它们对结果的影响。
2.2 轮廓属性

一旦找到轮廓,我们可以计算它们的各种属性来描述轮廓的形状、大小、位置等。

Python

import cv2
import numpy as np# --- 练习 2.2: 轮廓属性 ---# (沿用上一个练习的轮廓查找代码)
image_path = 'your_image.jpg'
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")image_color = np.zeros((400, 600, 3), dtype=np.uint8)cv2.putText(image_color, "Placeholder Image", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)ret, binary_image = cv2.threshold(image_gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 注意: findContours 修改了 binary_image,所以通常传递副本
contours, hierarchy = cv2.findContours(binary_image.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 复制原始彩色图像用于可视化属性
image_with_properties = image_color.copy()print("\n--- 轮廓属性 ---")
# 遍历所有找到的轮廓
for i, contour in enumerate(contours):# 忽略非常小的轮廓(可能是噪声)if cv2.contourArea(contour) < 100:continueprint(f"\n轮廓 {i+1}:")# 面积 (Area)area = cv2.contourArea(contour)print(f"  面积: {area:.2f}")# 周长 (Perimeter / Arc Length)# 参数: curve (轮廓), closed (是否闭合)perimeter = cv2.arcLength(contour, closed=True)print(f"  周长: {perimeter:.2f}")# 矩 (Moments) - 用于计算中心、面积等# M['m00'] 就是面积M = cv2.moments(contour)# 计算中心点 (Centroid)if M['m00'] != 0:cx = int(M['m10'] / M['m00'])cy = int(M['m01'] / M['m00'])print(f"  中心点 (cx, cy): ({cx}, {cy})")# 在中心点绘制圆圈cv2.circle(image_with_properties, (cx, cy), 5, (0, 0, 255), -1) # 红色实心圆# 外接矩形 (Bounding Rectangle) - 直立矩形# 参数: points (轮廓点)x, y, w, h = cv2.boundingRect(contour)print(f"  外接矩形 (x, y, w, h): ({x}, {y}, {w}, {h})")# 绘制外接矩形cv2.rectangle(image_with_properties, (x, y), (x+w, y+h), (255, 0, 0), 2) # 蓝色# 最小外接圆 (Minimum Enclosing Circle)# 参数: points (轮廓点)(center_x, center_y), radius = cv2.minEnclosingCircle(contour)center_circle = (int(center_x), int(center_y))radius_int = int(radius)print(f"  最小外接圆 (中心: {center_circle}, 半径: {radius_int})")# 绘制最小外接圆cv2.circle(image_with_properties, center_circle, radius_int, (0, 255, 255), 2) # 黄色# 轮廓近似 (Contour Approximation) - 简化轮廓# 使用 Ramer-Douglas-Peucker 算法# 参数: curve (轮廓), epsilon (近似精度,原始轮廓与近似轮廓之间的最大距离), closed (是否闭合)epsilon = 0.02 * perimeter # 精度通常设为周长的百分比approx = cv2.approxPolyDP(contour, epsilon, closed=True)print(f"  近似轮廓点数量: {len(approx)}")# 绘制近似轮廓 (可选,可以用 drawContours)# 6. 显示结果
cv2.imshow('Original Image', image_color)
cv2.imshow('Contours with Properties', image_with_properties)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 2.2 完成 ---")

练习提示:

  • 理解不同属性的含义及其计算方法。
  • 注意如何使用这些属性来描述轮廓的特征。例如,可以通过比较轮廓面积和其外接矩形面积的比例来判断轮廓的“紧凑”程度。
2.3 实战:简单形状识别

结合轮廓查找和轮廓属性,我们可以尝试识别一些简单的几何形状,如矩形、圆形。

思路:


3. 目标检测入门

目标检测比简单的形状识别更进一步,它旨在图像中找到特定类别的对象(如人脸、汽车、猫等)的位置,并通常用一个边界框标记出来。

3.1 模板匹配 (Template Matching)

模板匹配是一种简单直观的目标检测方法。它需要一个已知的模板图像(你要寻找的对象的小图像),然后在源图像中滑动这个模板,计算模板与源图像中对应区域的相似度。相似度最高的区域就被认为是找到了模板。

3.2 级联分类器 (Cascade Classifiers)

级联分类器是一种基于机器学习的目标检测方法。它使用一系列经过训练的分类器(弱分类器)组成一个级联结构。在检测时,图像区域会依次通过这些分类器。如果在任何一个阶段被判定为非目标,就会被立即丢弃,大大提高了检测速度。只有通过所有分类器的区域才会被认为是目标。

OpenCV 提供了一个使用 Haar-like 特征(类似于简单的边缘、线条特征)训练的级联分类器框架。尽管现代深度学习方法在许多目标检测任务上取得了更好的效果,但级联分类器(尤其是用于人脸检测)因为其速度快、实时性好,在一些场景下仍然有应用价值。

使用级联分类器进行目标检测需要:

Python

import cv2
import numpy as np# --- 练习 3.2: 级联分类器入门 ---# 1. 加载预训练的级联分类器模型
# 你需要找到 OpenCV 安装目录下的 haarcascades 文件夹,或者从网上下载
# 例如: '/usr/local/share/opencv4/haarcascades/haarcascade_frontalface_default.xml'
# 或者在项目目录下放置下载好的xml文件
cascade_path = 'haarcascade_frontalface_default.xml' # 替换成你的xml文件路径# 创建级联分类器对象
face_cascade = cv2.CascadeClassifier()# 加载分类器模型
if not face_cascade.load(cv2.samples.findFile(cascade_path)):print(f"错误: 无法加载级联分类器文件: {cascade_path}")print("请检查文件路径是否正确,或从以下位置下载:")print("https://github.com/opencv/opencv/tree/master/data/haarcascades")# 如果加载失败,创建一个空的分类器,后续检测会失败face_cascade = None# 2. 加载图像并转换为灰度图 (级联分类器通常在灰度图上工作)
image_path = 'your_image_with_faces.jpg' # 最好找一张包含人脸的图片
try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")print(f"成功加载图像: {image_path}")image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)image_gray = cv2.equalizeHist(image_gray) # 可选: 直方图均衡化,有时能提高检测效果except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")print("将使用模拟图像代替,无法演示实际检测效果。")# 创建模拟图像,无法包含真实人脸image_color = np.zeros((400, 600, 3), dtype=np.uint8)cv2.putText(image_color, "Placeholder Image", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)# 3. 进行目标检测 (人脸检测)
# 参数: image (灰度图), scaleFactor (图像缩放因子), minNeighbors (每个矩形应该具有的邻近个数),
#       minSize (最小可能对象大小), maxSize (最大可能对象大小)
if face_cascade: # 确保分类器加载成功faces = face_cascade.detectMultiScale(image_gray,scaleFactor=1.1, # 每次图像尺寸减小的比例minNeighbors=5, # 每个目标至少被检测到5次才被确认为目标minSize=(30, 30) # 最小目标尺寸 (宽, 高)# maxSize=(200, 200) # 最大目标尺寸)
else:faces = [] # 如果分类器加载失败,检测结果为空列表print(f"检测到 {len(faces)} 个人脸")# 4. 在原始彩色图像上绘制检测到的目标 (矩形框)
output_image = image_color.copy()
for (x, y, w, h) in faces:cv2.rectangle(output_image, (x, y), (x+w, y+h), (255, 0, 0), 2) # 蓝色矩形框# 5. 显示结果
cv2.imshow('Original Image', image_color)
cv2.imshow('Detected Faces', output_image)cv2.waitKey(0)
cv2.destroyAllWindows()print("\n--- 练习 3.2 完成 ---")

练习提示:

3.3 实战:人脸检测

这个实战练习就是将上一节学习的级联分类器应用到人脸检测任务上。你只需要确保有包含人脸的图片以及正确加载人脸分类器的 XML 文件。

  1. 找到轮廓。
  2. 过滤掉过小或过大的轮廓。
  3. 对轮廓进行近似。
  4. 根据近似轮廓的顶点数量来判断形状:
    • 如果顶点数量接近 4 且是凸多边形,可能是矩形/正方形。
    • 如果顶点数量很多(近似后变化不大)且是凸多边形,可能是圆形。
  5. 进一步细化:对于顶点数为 4 的,可以检查长宽比来区分正方形和矩形。对于圆形,可以检查面积与最小外接圆面积的比例。Python

    import cv2
    import numpy as np# --- 实战练习: 简单形状识别 ---# 1. 加载图像并转换为灰度图
    image_path = 'your_image.jpg' # 最好找一张有明显几何图形的图片
    try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
    except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")# 创建一个包含简单形状的模拟图像image_color = np.zeros((400, 400, 3), dtype=np.uint8)cv2.rectangle(image_color, (50, 50), (150, 150), (255, 0, 0), -1) # 蓝色方块cv2.circle(image_color, (300, 100), 50, (0, 255, 0), -1) # 绿色圆圈cv2.rectangle(image_color, (200, 200), (350, 300), (0, 0, 255), -1) # 红色矩形image_gray = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)# 2. 二值化图像
    ret, binary_image = cv2.threshold(image_gray, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 3. 查找轮廓 (注意使用副本)
    contours, hierarchy = cv2.findContours(binary_image.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 复制原始彩色图像用于绘制结果
    output_image = image_color.copy()print("\n--- 形状识别结果 ---")# 4. 遍历轮廓并进行识别
    for contour in contours:# 过滤小轮廓area = cv2.contourArea(contour)if area < 1000: # 过滤面积小于1000的轮廓continue# 计算周长perimeter = cv2.arcLength(contour, closed=True)# 轮廓近似epsilon = 0.04 * perimeter # 提高 epsilon 可以减少近似点数量,有助于识别多边形approx = cv2.approxPolyDP(contour, epsilon, closed=True)# 获取外接矩形属性x, y, w, h = cv2.boundingRect(approx)aspect_ratio = float(w) / hbbox_area = w * h# 识别形状shape = "未知"M = cv2.moments(contour)if M['m00'] != 0:cx = int(M['m10'] / M['m00'])cy = int(M['m01'] / M['m00'])center = (cx, cy)else:center = (x + w // 2, y + h // 2) # 使用外接矩形中心代替# 绘制轮廓并标注形状cv2.drawContours(output_image, [contour], -1, (0, 255, 0), 2) # 绘制当前轮廓num_vertices = len(approx)if num_vertices == 3:shape = "三角形"elif num_vertices == 4:# 判断是正方形还是矩形if 0.9 <= aspect_ratio <= 1.1 and 0.85 <= area / bbox_area <= 1.15: # 检查长宽比和面积比例shape = "正方形"else:shape = "矩形"elif num_vertices == 5:shape = "五边形"else:# 对于顶点数量多的轮廓,可能是圆形或其它复杂形状# 可以通过检查面积与最小外接圆面积的比例来判断是否接近圆形(center_circle_x, center_circle_y), radius = cv2.minEnclosingCircle(contour)circle_area = np.pi * radius**2if area / circle_area > 0.8: # 如果轮廓面积占最小外接圆面积的大部分shape = "圆形"else:shape = "其他" # 或者 "复杂形状"print(f"  轮廓点数量: {len(contour)}, 近似点数量: {num_vertices}, 识别为: {shape}")# 在中心点附近显示形状名称cv2.putText(output_image, shape, (center[0] - 20, center[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)# 5. 显示结果
    cv2.imshow('Original Image', image_color)
    cv2.imshow('Simple Shape Recognition', output_image)cv2.waitKey(0)
    cv2.destroyAllWindows()print("\n--- 实战练习: 简单形状识别 完成 ---")
    

    实战提示:

  6. 这个简单的形状识别方法对于理想的几何图形效果较好,对于真实照片中形状会受光照、遮挡、变形等影响,效果会下降。
  7. 调整 epsilon 参数会影响近似轮廓的顶点数量,从而影响识别结果。
  8. 圆形识别可以通过检查面积与最小外接圆面积的比例、或者周长与半径的关系等多种方法来实现。
  9. Python

    import cv2
    import numpy as np# --- 练习 3.1: 模板匹配 ---# 1. 加载源图像和模板图像
    # 请替换成你自己的图片路径,确保 template_image.jpg 是 source_image.jpg 的一部分
    source_image_path = 'your_source_image.jpg'
    template_image_path = 'your_template_image.jpg' # 模板图像要小于源图像try:source_image = cv2.imread(source_image_path)template_image = cv2.imread(template_image_path)if source_image is None:raise FileNotFoundError(f"源图片文件未找到: {source_image_path}")if template_image is None:raise FileNotFoundError(f"模板图片文件未找到: {template_image_path}")print("成功加载源图像和模板图像。")
    except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")print("将使用模拟图像代替,无法演示实际匹配效果。")# 创建模拟图像source_image = np.zeros((300, 400, 3), dtype=np.uint8)cv2.circle(source_image, (200, 150), 50, (0, 255, 0), -1)cv2.putText(source_image, "Source (Green Circle)", (50, 250), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)template_image = np.zeros((100, 100, 3), dtype=np.uint8)cv2.circle(template_image, (50, 50), 40, (0, 255, 0), -1)cv2.putText(template_image, "Template", (10, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)# 确保两张图像都是单通道或三通道,且类型一致
    # 模板匹配也可以在灰度图上进行,通常更快
    source_gray = cv2.cvtColor(source_image, cv2.COLOR_BGR2GRAY)
    template_gray = cv2.cvtColor(template_image, cv2.COLOR_BGR2GRAY)# 获取模板图像的宽度和高度
    w, h = template_gray.shape[::-1] # shape返回(h, w),[::-1]反转得到(w, h)# 2. 进行模板匹配
    # 参数: image (源图像), templ (模板图像), method (匹配方法)
    # cv2.TM_CCOEFF_NORMED: 归一化相关系数匹配,值越接近1越好
    # cv2.TM_SQDIFF_NORMED: 归一化平方差匹配,值越接近0越好
    method = cv2.TM_CCOEFF_NORMED
    result = cv2.matchTemplate(source_gray, template_gray, method)# 3. 查找最佳匹配位置
    # cv2.minMaxLoc() 找到匹配结果矩阵中的最小值、最大值及其位置
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)# 根据匹配方法,最佳匹配位置可能是 min_loc 或 max_loc
    # 对于 TM_CCOEFF_NORMED, TM_CCORR_NORMED, TM_CCOEFF,最大值表示最佳匹配
    # 对于 TM_SQDIFF, TM_SQDIFF_NORMED, TM_CCORR,最小值表示最佳匹配
    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:top_left = min_loc # 最佳匹配的左上角坐标
    else:top_left = max_loc# 计算最佳匹配区域的右下角坐标
    bottom_right = (top_left[0] + w, top_left[1] + h)# 4. 在源图像上绘制匹配结果 (矩形框)
    # 复制源图像以免修改原图
    output_image = source_image.copy()
    cv2.rectangle(output_image, top_left, bottom_right, (0, 0, 255), 2) # 红色矩形框# 5. 显示结果
    cv2.imshow('Source Image', source_image)
    cv2.imshow('Template Image', template_image)
    cv2.imshow('Template Matching Result', output_image)
    # 匹配结果矩阵通常数值范围较大,直接显示可能不直观,可以先归一化再显示
    # cv2.imshow('Match Result Matrix', cv2.normalize(result, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U))cv2.waitKey(0)
    cv2.destroyAllWindows()print("\n--- 练习 3.1 完成 ---")
    

    练习提示:

  10. 模板匹配对模板图像的大小、旋转、光照变化非常敏感。如果模板和目标在源图像中的外观有较大差异,匹配可能会失败。
  11. 尝试不同的 method 参数,比较它们的效果。
  12. cv2.matchTemplate 也可以返回多个匹配区域(例如,使用阈值过滤匹配结果矩阵)。
  13. 一个预先训练好的分类器模型文件(通常是 XML 格式)。OpenCV 库自带了一些常用的分类器模型,如人脸、眼睛等。你可以在 OpenCV 的 GitHub 仓库中找到它们(opencv/data/haarcascadesopencv_extra/testdata/cv/face/)。
  14. 使用 cv2.CascadeClassifier 类加载模型。
  15. 使用 cascade.detectMultiScale() 方法在图像中进行检测。
  16. 找到并替换 cascade_path 为你环境中正确的 XML 文件路径。
  17. 尝试不同的 scaleFactorminNeighbors 参数。减小 scaleFactor 可以检测到更小的目标,但速度变慢;增大 minNeighbors 可以减少误检,但可能漏掉一些目标。
  18. 尝试使用不同的图像进行测试。
  19. 除了人脸,OpenCV 还提供了眼睛、身体等其他预训练的级联分类器。
  20. Python

    import cv2
    import numpy as np# --- 实战练习: 人脸检测 ---# 1. 指定人脸分类器模型文件路径
    # 这是 OpenCV 官方提供的模型,你需要确保你的OpenCV安装目录有这个文件,或者手动下载放在项目目录
    # 例如: '/usr/local/share/opencv4/haarcascades/haarcascade_frontalface_default.xml'
    # 或者直接放在当前脚本同一目录下
    # 你可以从这里下载: https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xml
    cascade_filename = 'haarcascade_frontalface_default.xml'# 创建人脸分类器对象
    face_cascade = cv2.CascadeClassifier()# 尝试加载模型文件
    if not face_cascade.load(cv2.samples.findFile(cascade_filename)):print(f"错误: 无法加载人脸分类器文件: {cascade_filename}")print("请确保文件存在,并可能需要手动下载或找到OpenCV安装路径下的haarcascades文件夹。")print("使用一个空的分类器,后续检测将不会找到任何目标。")face_cascade = None # 设置为 None 表示加载失败# 2. 加载你要检测人脸的图像
    image_path = 'your_image_to_detect_faces.jpg' # 请替换为你想要检测人脸的图片路径
    try:image_color = cv2.imread(image_path)if image_color is None:raise FileNotFoundError(f"图片文件未找到: {image_path}")print(f"成功加载图像: {image_path}")
    except FileNotFoundError as e:print(e)print("请确保你的图片文件存在并位于正确路径。")# 创建一个空白图像作为备用image_color = np.zeros((400, 600, 3), dtype=np.uint8)cv2.putText(image_color, "Placeholder Image", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)# 3. 将图像转换为灰度图 (级联分类器工作在灰度图上)
    gray_image = cv2.cvtColor(image_color, cv2.COLOR_BGR2GRAY)
    # 可以选择性地进行直方图均衡化以增强对比度
    # gray_image = cv2.equalizeHist(gray_image)# 4. 进行人脸检测
    # 使用 detectMultiScale 方法
    # 参数: scaleFactor, minNeighbors, minSize, maxSize (这些参数会影响检测精度和速度)
    if face_cascade: # 只有在分类器加载成功时才执行检测faces = face_cascade.detectMultiScale(gray_image,scaleFactor=1.1, # 图像缩小比例minNeighbors=5,  # 构成检测目标的最小邻近矩形数量minSize=(30, 30) # 最小检测窗口大小)
    else:faces = [] # 如果分类器加载失败,结果为空print(f"检测到 {len(faces)} 个人脸")# 5. 在原始图像上绘制检测到的人脸矩形框
    output_image = image_color.copy()
    # faces 变量是一个包含检测到的人脸矩形信息的列表,每个元素是 (x, y, w, h)
    for (x, y, w, h) in faces:cv2.rectangle(output_image, (x, y), (x+w, y+h), (0, 255, 0), 2) # 绿色矩形框# 6. 显示结果
    cv2.imshow('Original Image', image_color)
    cv2.imshow('Face Detection Result', output_image)# 7. 等待按键,然后关闭窗口
    cv2.waitKey(0)
    cv2.destroyAllWindows()print("\n--- 实战练习: 人脸检测 完成 ---")
    

    实战提示:

  21. 最关键的一步是正确指定 cascade_filename 的路径。
  22. 尝试使用不同光照、角度、表情的人脸图片进行测试,观察检测效果。
  23. 调整 detectMultiScale 的参数,尤其是 scaleFactorminNeighbors,会显著影响检测结果。

相关文章:

第三部分:特征提取与目标检测

像边缘、角点、特定的纹理模式等都是图像的特征。提取这些特征是许多计算机视觉任务的关键第一步&#xff0c;例如图像匹配、对象识别、图像拼接等。目标检测则是在图像中找到特定对象&#xff08;如人脸、汽车等&#xff09;的位置。 本部分将涵盖以下关键主题&#xff1a; …...

MySQL bin目录下的可执行文件

文章目录 MySQL bin目录下的可执行文件1.mysqldump2.mysqladmin3.mysqlcheck4.mysqlimport5.mysqlshow6.mysqlbinlog7.常用可执行文件 MySQL bin目录下的可执行文件 1.mysqldump mysqldump 是 MySQL 的数据库备份工具。对数据备份、迁移或恢复非常重要。 备份整个数据库&…...

第四部分:赋予网页健壮的灵魂 —— TypeScript(中)

目录 4 类与面向对象&#xff1a;构建复杂的组件4.1 类的定义与成员4.2 继承 (Inheritance)4.3 接口实现 (Implements)4.4 抽象类 (Abstract Class)4.5 静态成员 (Static Members) 5 更高级的类型&#xff1a;让类型系统更灵活5.1 联合类型 (|)5.2 交叉类型 (&)5.3 字面量类…...

Learning vtkjs之ImageMarchingCubes

体积 等值面处理 介绍 vtkImageMarchingCubes - 对体积进行等值面处理 给定一个指定的等值&#xff0c;使用Marching Cubes算法生成一个等值面。 效果 新建了一个球&#xff0c;对比一下原始的&#xff08;透明的&#xff09;和ISO的效果 核心代码 参数部分 const updat…...

【“星睿O6”AI PC开发套件评测】+ tensorflow 初探

因为本次我的项目计划使用 tensorflow&#xff0c;所以这篇文章主要想做一个引子&#xff0c;介绍如何在“星睿O6”上搭建 tensorflow 的开发环境和验证测试。本文主要分为几个部分&#xff1a; 在“星睿O6”上编译安装 tensorflow基于 MNIST 数据集的模型训练和评估 tensorf…...

通义灵码全面接入Qwen3:AI编程进入智能体时代,PAI云上部署实战解析

引言&#xff1a;AI编程的范式革命 2025年4月30日&#xff0c;阿里云通义灵码宣布全面支持新一代大模型Qwen3&#xff0c;并同步推出编程智能体功能&#xff0c;标志着AI辅助开发从“工具助手”向“自主决策智能体”的跃迁。与此同时&#xff0c;阿里云PAI平台上线Qwen3全系列…...

如何禁止AutoCAD这类软件联网

推荐二、三方法&#xff0c;对其他软件影响最小 一、修改Hosts文件 Hosts文件是一个存储域名与IP地址映射关系的文本文件&#xff0c;通过修改Hosts文件可以将AutoCAD的域名指向本地回环地址&#xff08;127.0.0.1&#xff09;&#xff0c;从而实现禁止联网的目的。具体步骤如…...

音视频项目在微服务领域的趋势场景题深度解析

音视频项目在微服务领域的趋势场景题深度解析 在互联网大厂Java求职者的面试中&#xff0c;经常会被问到关于音视频项目在微服务领域的应用场景的相关问题。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官&#xff1a;马架构&#xff0c;欢迎来到我…...

100 个 NumPy 练习

本文翻译整理自&#xff1a;https://github.com/rougier/numpy-100 文章目录 关于 100 个 NumPy 练习相关链接资源关键功能特性 100 个 NumPy 练习题1、导入 NumPy 包并命名为 np (★☆☆)2、打印 NumPy 版本和配置信息 (★☆☆)3、创建一个大小为 10 的空向量 (★☆☆)4、如何…...

在Carla中构建自动驾驶:使用PID控制和ROS2进行路径跟踪

机器人软件开发什么是 P、PI 和 PID 控制器&#xff1f;比例 &#xff08;P&#xff09; 控制器比例积分 &#xff08;PI&#xff09; 控制器比例-积分-微分 &#xff08;PID&#xff09; 控制器横向控制简介CARLA ROS2 集成纵向控制横向控制关键要点结论引用 机器人软件开发 …...

Windows和 macOS 上安装 `nvm` 和 Node.js 16.16.0 的详细教程。

Windows和 macOS 上安装 nvm 和 Node.js 16.16.0 的详细教程。 --- ### 1. 安装 nvm&#xff08;Node Version Manager&#xff09; nvm 是一个 Node.js 版本管理工具&#xff0c;可以轻松安装和切换不同版本的 Node.js。 #### Windows 安装 nvm 1. **下载 nvm 安装包**&#x…...

day11 python超参数调整

模型组成&#xff1a;模型 算法 实例化设置的外参&#xff08;超参数&#xff09; 训练得到的内参调参评估&#xff1a;调参通常需要进行两次评估。若不使用交叉验证&#xff0c;需手动划分验证集和测试集&#xff1b;但许多调参方法自带交叉验证功能&#xff0c;实际中可省略…...

Linux C++ xercesc xml 怎么判断路径下有没有对应的节点

在Linux环境下使用Xerces-C库处理XML文件时&#xff0c;判断路径下是否存在对应的节点可以通过以下几个步骤实现&#xff1a; 加载XML文档 首先&#xff0c;你需要加载XML文档。这可以通过创建一个xercesc::DOMParser对象并使用它的parse方法来实现。 #include <xercesc/…...

罗技K580蓝牙键盘连接mac pro

罗技K580蓝牙键盘&#xff0c;满足了我们的使用需求。最棒的是&#xff0c;它能够同时连接两个设备&#xff0c;通过按F11和F12键进行切换&#xff0c;简直不要太方便&#xff01; 连接电脑 &#x1f4bb; USB连接 1、打开键盘&#xff1a;双手按住凹槽两边向前推&#xff0…...

Socket-UDP

Socket&#xff08;套接字 &#xff09;是计算机网络中用于实现进程间通信的重要编程接口&#xff0c;是对 TCP/IP 协议的封装 &#xff0c;可看作是不同主机上应用进程之间双向通信端点的抽象。以下是详细介绍&#xff1a; 作用与地位 作为应用层与传输层、网络层协议间的中…...

【游戏ai】从强化学习开始自学游戏ai-2 使用IPPO自博弈对抗pongv3环境

文章目录 前言一、环境设计二、动作设计三、状态设计四、神经网路设计五、效果展示其他问题总结 前言 本学期的大作业&#xff0c;要求完成多智能体PPO的乒乓球对抗环境&#xff0c;这里我使用IPPO的方法来实现。 正好之前做过这个单个PPO与pong环境内置的ai对抗的训练&#…...

LeRobot 项目部署运行逻辑(三)——机器人及舵机配置

Lerobot 目前的机器人硬件以舵机类型为主&#xff0c;并未配置机器人正逆运动学及运动学&#xff0c;遥操作映射以舵机关节角度为主 因此&#xff0c;需要在使用前需要对舵机各项参数及初始位置进行配置 目录 1 Mobile ALOHA 配置 2 Dynamixel 配置 2.1 配置软件 2.2 SDK …...

Ubuntu20.04安装NVIDIA Warp

Ubuntu20.04安装NVIDIA Warp 安装测试 Warp的gitee网址 Warp的github网址 写在前面&#xff1a;建议安装前先参考readme文件自检系统驱动和cuda是否支持&#xff0c;个人实测建议是python3.9&#xff0c;但python3.8.20也可以使用。 写在前面&#xff1a;后续本人可能会使用这…...

电子病历高质量语料库构建方法与架构项目(临床情景理解模块篇)

引言 随着人工智能技术在医疗健康领域的广泛应用,电子病历(Electronic Medical Records,EMR)作为临床医疗数据的重要载体,已成为医学研究和临床决策支持的关键资源。电子病历高质量语料库的构建为医疗人工智能模型的训练和应用提供了基础支撑,其中临床情境理解模块是连接…...

WPF性能优化举例

WPF性能优化集锦 一、UI渲染性能优化 1. 虚拟化技术 ​​ListView/GridView虚拟化​​: <ListView VirtualizingStackPanel.IsVirtualizing="True"VirtualizingStackPanel.VirtualizationMode="Recycling"ScrollViewer.IsDeferredScrollingEnabled=…...

【CUDA pytorch】

ev win10 3050ti 联想笔记本 nvcc --version 得到 PS C:\Users\25515> nvcc --version nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2022 NVIDIA Corporation Built on Tue_May__3_19:00:59_Pacific_Daylight_Time_2022 Cuda compilation tools, release …...

mac下载homebrew 安装和使用git

mac下载homebrew 安装和使用git 本人最近从windows换成mac&#xff0c;记录一下用homebrew安装git的过程 打开终端 command 空格&#xff0c;搜索终端 安装homebrew 在终端中输入下面命令&#xff0c;来安装homebrew /bin/bash -c "$(curl -fsSL https://raw.githu…...

Elasticsearch入门速通01:核心概念与选型指南

一、Elasticsearch 是什么&#xff1f; 一句话定义&#xff1a; 开源分布式搜索引擎&#xff0c;擅长处理海量数据的实时存储、搜索与分析&#xff0c;是ELK技术栈&#xff08;ElasticsearchKibanaBeatsLogstash&#xff09;的核心组件。 核心能力&#xff1a; 近实时搜索&…...

应对过度处方挑战:为药物推荐任务微调大语言模型(Xiangnan He)

Abstract 药物推荐系统因其有潜力根据患者的临床数据提供个性化且有效的药物组合&#xff0c;在医疗保健领域备受关注。然而&#xff0c;现有方法在适应不同的电子健康记录&#xff08;EHR&#xff09;系统以及有效利用非结构化数据方面面临挑战&#xff0c;导致其泛化能力有限…...

41 python http之requests 库

Python 的requests库就像你的 "接口助手",用几行代码就能发送 HTTP 请求,自动处理复杂的网络交互,让你告别手动拼接 URL 和解析响应的痛苦! 一、快速入门:3 步搞定基本请求 1.1 安装库:一键开启助手功能 pip install requests 1.2 发送 GET 请求 import r…...

百度网盘golang实习面经

goroutine内存泄漏的情况&#xff1f;如何避免&#xff1f; goroutine内存泄漏基本上是因为异常导致阻塞, 可以导致阻塞的情况 1 死锁, goroutine 等待的锁发生了死锁情况 2 chan没有正常被关闭,导致读取读chan的goroutine阻塞 如何避免 1 避免死锁 2 正常关闭 3 使用context管…...

super_small_toy_tpu

super_small_toy_tpu 小狼http://blog.csdn.net/xiaolangyangyang 1、基础框图 2、源码下载&#xff1a; GitHub - dldldlfma/super_small_toy_tpu 3、安装iverilog、vvp、gtkwave windows安装&#xff1a;https://bleyer.org/icarus/ ubuntu安装&#xff1a;sudo ap…...

Redis缓存穿透、缓存击穿与缓存雪崩:如何在.NET Core中解决

在高并发的互联网系统中&#xff0c;缓存技术作为优化系统性能的重要手段&#xff0c;已被广泛应用。然而&#xff0c;缓存系统本身也存在一些常见的问题&#xff0c;尤其是 缓存穿透、缓存击穿 和 缓存雪崩。这些问题如果处理不当&#xff0c;可能导致系统性能严重下降&#x…...

驱动车辆诊断测试创新 | 支持诊断测试的模拟器及数据文件转换生成

一 背景和挑战 | 背景&#xff1a; 随着汽车功能的日益丰富&#xff0c;ECU和域控制器的复杂性大大增加&#xff0c;导致测试需求大幅上升&#xff0c;尤其是在ECU的故障诊断和性能验证方面。然而&#xff0c;传统的实车测试方法难以满足高频率迭代和验证需求&#xff0c;不仅…...

VS Code技巧2:识别FreeCAD对象

在使用VS Code阅读FreeCAD代码或者FreeCAD的工作台代码时&#xff0c;VS Code无法识别FreeCAD对象&#xff0c;会提示Import “FreeCAD” could not be resolved&#xff1a; 问题解决如下几步即可。 第一步&#xff1a;确认 FreeCAD 的 Python 环境路径 在FreeCAD的Python控制…...

泰迪杯特等奖案例学习资料:基于多模态融合与边缘计算的智能温室环境调控系统

(第十二届泰迪杯数据挖掘挑战赛特等奖案例解析) 一、案例背景与核心挑战 1.1 应用场景与行业痛点 在现代设施农业中,温室环境调控直接影响作物产量与品质。传统温室管理存在以下问题: 环境参数耦合性高:温度、湿度、光照、CO₂浓度等参数相互影响,人工调控易顾此失彼。…...

猿人学web端爬虫攻防大赛赛题第13题——入门级cookie

1. F12开发者模式 刷新第一页&#xff0c;仔细研究发现里面有三次请求名为13的请求&#xff0c;根据题目提示cookie关键字&#xff0c;所以主要留意请求和响应的cookie值。 三次请求都带了sessionid&#xff0c;说明存在session&#xff08;后面写代码要用session来写&#x…...

机器指标监控技术方案

文章目录 机器指标监控技术方案架构图组件简介Prometheus 简介核心特性适用场景 Grafana 简介核心特性适用场景 Alertmanager 简介核心特性适用场景 数据采集机器Node ExporterMySQL ExporterRedis ExporterES ExporterRocketMQ ExporterSpringcloud ExporterNacos 数据存储短期…...

数据库设计理论:从需求分析到实现的全流程解析

引言 在当今信息爆炸的时代&#xff0c;数据已成为企业和组织最宝贵的资产之一。如何有效地组织、存储和管理这些数据&#xff0c;是数据库设计需要解决的核心问题。一个优秀的数据库设计能够提高系统性能&#xff0c;确保数据一致性&#xff0c;降低维护成本&#xff0c;而糟…...

一文详解 Linux下的开源打印系统CUPS(Common UNIX Printing System)

文章目录 前言一、CUPS 简介二、CUPS 常用指令解析2.1 安装 CUPS2.2 启动/重启服务2.3 添加打印机&#xff08;核心操作&#xff09;2.4 设置默认打印机2.5 打印文件2.6 查看打印任务2.7 取消打印任务2.8 查看、移除已添加的打印机 三、调试与常见问题3.1 日志查看3.2 驱动问题…...

uniapp打包apk详细教程

目录 1.打apk包前提条件 2.获取uni-app标识 3.进入dcloud开发者后台 4.开始打包 1.打apk包前提条件 1.在HBuilderX.exe软化中&#xff0c;登录自己的账号 2.在dcloud官网&#xff0c;同样登录自己的账号。没有可以免费注册。 2.获取uni-app标识 获取方法&#xff1a;点…...

C++初阶-string类2

目录 1.迭代器 1.1普通迭代器的使用 1.2string::begin 1.3string::end 1.4const迭代器的使用 1.5泛型迭代器和const反向迭代器 1.6string::rbegin 1.6string::rend 1.7string::cbegin、string::cend、string::crbegin、string::crend 与begin/end、rbegin/rend的区别 …...

Qt QComboBox 下拉复选多选(multicombobox)

Qt QComboBox 下拉复选多选&#xff08;multicombobox&#xff09;&#xff0c;备忘&#xff0c;待更多测试 【免费】QtQComboBox下拉复选多选&#xff08;multicombobox&#xff09;资源-CSDN文库...

逻辑回归之参数选择:从理论到实践

在机器学习的广阔领域中&#xff0c;逻辑回归作为一种经典的有监督学习算法&#xff0c;常用于解决分类问题。它以其简单易懂的原理和高效的计算性能&#xff0c;在实际应用中备受青睐。然而&#xff0c;要充分发挥逻辑回归的优势&#xff0c;参数选择是关键环节。本文将结合信…...

10、属性和数据处理---c++17

一、[[fallthrought]] 用途&#xff1a;在 switch 语句中标记某个分支 (case) 故意不写 break&#xff0c;明确告知编译器“执行穿透”是有意为之。 仅在需要向下穿透时使用&#xff0c;且应添加注释说明原因 #include<cstdio> #include<iostream> using namesp…...

conda管理python环境

安装conda 使用anaconda官网安装地址&#xff1a;https://www.anaconda.com/download/success 配置镜像环境 conda config --add channels Index of /anaconda/pkgs/main/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror conda config --add channels Index of /an…...

【Python学习路线】零基础到项目实战系统

目录 &#x1f31f; 前言技术背景与价值当前技术痛点解决方案概述目标读者说明 &#x1f9e0; 一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比 &#x1f4bb; 二、实战演示环境配置要求核心代码实现运行结果验证 ⚡ 三、性能对比测试方法论量化数据对比…...

C/C++核心机制深度解析:指针、结构体与动态内存管理(面试精要)

C/C核心机制深度解析&#xff1a;指针、结构体与动态内存管理&#xff08;面试精要&#xff09; 引言 在系统级编程领域&#xff0c;C/C语言凭借对硬件的直接操作能力和高效的内存管理机制&#xff0c;长期占据主导地位。面试中&#xff0c;指针、结构体和动态内存管理作为三…...

宇树科技举办“人型机器人格斗大赛”

2025 年 5 月至 6 月&#xff0c;一场全球瞩目的科技盛宴 —— 全球首场 “人形机器人格斗大赛”&#xff0c;将由杭州宇树科技盛大举办。届时&#xff0c;观众将迎来机器人格斗领域前所未有的视觉震撼。 为打造最强参赛阵容&#xff0c;宇树科技技术团队在过去数周里&#xf…...

getattr 的作用

getattr 是 Python 内置的一个函数&#xff0c;用于“动态地”获取对象的属性。**它允许你在运行时通过属性名称&#xff08;字符串形式&#xff09;来访问对象的属性&#xff0c;而不用在代码中直接硬编码属性名。**下面详细介绍该方法的用法和注意事项&#xff1a; ────…...

腾讯云服务器性能提升全栈指南(2025版)

腾讯云服务器性能提升全栈指南&#xff08;2025版&#xff09; 一、硬件选型与资源优化 1. 实例规格精准匹配 腾讯云服务器提供计算型CVM、内存型MEM、大数据型Hadoop等12种实例类型。根据业务特性选择&#xff1a; • 高并发Web应用&#xff1a;推荐SA3实例&#xff0…...

Kotlin与Jetpack Compose的详细使用指南

Kotlin与Jetpack Compose的详细使用指南&#xff0c;综合最新技术实践和官方文档整理&#xff1a; 一、环境配置与基础架构 ‌项目创建‌ 在Android Studio中选择Empty Compose Activity模板&#xff0c;默认生成包含Composable预览的MainActivity2要求Kotlin版本≥1.8.0&…...

潇洒郎: 100% 成功搭建Docker私有镜像仓库并管理、删除镜像

1、Registry Web管理界面 2、拉取Registry-Web镜像 创建配置文件 tee /opt/zwx-registry/web-config.yml <<-EOF registry:url: http://172.28.73.90:8010/v2name: registryreadonly: falseauth:enabled: false EOF 拉取docker-registry-web镜像并绑定Registry仓库 …...

【Spring Boot 注解】@ConfigurationProperties

文章目录 ConfigurationProperties注解一、简介二、依赖引入三、基本用法四、主要特性五、激活方式六&#xff0c;优点七、与 Value 对比 ConfigurationProperties注解 一、简介 ConfigurationProperties 是 Spring Boot 提供的一个强大注解&#xff0c;用于将外部配置&#…...

阿里云服务迁移实战: 06-切换DNS

概述 按前面的步骤&#xff0c;所有服务迁移完毕之后&#xff0c;最后就剩下 DNS 解析修改了。 修改解析 在域名解析处&#xff0c;修改域名的解析地址即可。 如果 IP 已经过户到了新账号&#xff0c;则不需要修改解析。 何确保业务稳定 域名解析更换时&#xff0c;由于 D…...