2026/3/8 8:26:43
网站建设
项目流程
网站icp不备案有关系吗,学校模板图片,怎么进入微信公众号平台,手机号码网站开发一、引言目标识别是数字图像处理的核心应用之一#xff0c;广泛应用于安防监控、自动驾驶、医学影像分析等领域。本文基于《数字图像处理》第 12 章内容#xff0c;从基础概念到实战代码#xff0c;全方位讲解目标识别的核心方法#xff0c;所有代码均可直接运行#xff0…一、引言目标识别是数字图像处理的核心应用之一广泛应用于安防监控、自动驾驶、医学影像分析等领域。本文基于《数字图像处理》第 12 章内容从基础概念到实战代码全方位讲解目标识别的核心方法所有代码均可直接运行配套效果对比图帮助大家直观理解。二、核心知识点讲解12.1 模式与模式类概念解析模式可以理解为事物的特征描述比如一张人脸的五官特征、一个手写数字的轮廓特征等。模式类具有相同特征的模式集合比如所有数字 0 的手写样本构成一个模式类所有数字 1 的样本构成另一个模式类。简单来说目标识别的本质就是提取待识别目标的模式特征 → 与已知模式类对比 → 判定目标所属类别。12.2 基于决策理论的识别方法这类方法的核心是通过数学模型决策函数对提取的特征进行分类决策下面讲解 3 种核心方法并配套实战代码。12.2.1 匹配法核心思想将待识别目标的特征与模板库中的特征逐一比对相似度最高的模板对应的类别即为识别结果最直观的 模板匹配。实战代码模板匹配识别数字import cv2 import numpy as np import matplotlib.pyplot as plt # 设置matplotlib支持中文显示 plt.rcParams[font.sans-serif] [SimHei] # 黑体 plt.rcParams[axes.unicode_minus] False # 解决负号显示问题 def template_matching_demo(): # 1. 准备原始图像和模板图像 # 原始图像包含待识别数字 img_original cv2.imread(digits.png, 0) # 以灰度模式读取 if img_original is None: print(请确保digits.png文件存在于当前目录) return # 截取模板数字5 template img_original[50:100, 50:100] # 手动截取数字5的区域作为模板 # 2. 执行模板匹配 # 6种匹配方法这里用平方差匹配TM_SQDIFF值越小匹配度越高 methods [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED, cv2.TM_CCORR, cv2.TM_CCORR_NORMED, cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED] # 选第一种方法演示 res cv2.matchTemplate(img_original, template, methods[0]) min_val, max_val, min_loc, max_loc cv2.minMaxLoc(res) # 3. 标记匹配结果 h, w template.shape[:2] top_left min_loc # 平方差匹配中最小值对应最佳匹配位置 bottom_right (top_left[0] w, top_left[1] h) img_result cv2.cvtColor(img_original, cv2.COLOR_GRAY2BGR) # 转彩色方便画框 cv2.rectangle(img_result, top_left, bottom_right, (0, 0, 255), 2) # 红色框标记 # 4. 绘制效果对比图 plt.figure(figsize(12, 6)) # 子图1原始灰度图 plt.subplot(1, 3, 1) plt.imshow(img_original, cmapgray) plt.title(原始图像数字集) plt.axis(off) # 子图2模板图像 plt.subplot(1, 3, 2) plt.imshow(template, cmapgray) plt.title(模板数字5) plt.axis(off) # 子图3匹配结果 plt.subplot(1, 3, 3) plt.imshow(cv2.cvtColor(img_result, cv2.COLOR_BGR2RGB)) # 转RGB适配matplotlib plt.title(匹配结果红色框为识别目标) plt.axis(off) plt.tight_layout() plt.show() # 运行模板匹配示例 if __name__ __main__: template_matching_demo()效果说明运行代码后会显示 3 张图原始数字集、数字 5 模板、匹配结果红色框标记识别到的数字 5 位置。注意需提前准备digits.png可从 OpenCV 官方示例库下载若没有该文件代码会提示并退出。12.2.2 最优统计分类器核心思想基于概率统计理论通过计算待识别样本属于各类别的后验概率选择概率最大的类别作为结果典型如贝叶斯分类器。实战代码贝叶斯分类器识别手写数字import cv2 import numpy as np import matplotlib.pyplot as plt from sklearn.naive_bayes import GaussianNB from sklearn.metrics import accuracy_score # 设置matplotlib支持中文显示 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False def load_digits_dataset(): 手动加载并解析OpenCV digits.png数据集 替代兼容性差的cv2.ml.loadDataset函数 # 读取digits.png需确保文件在当前目录可从OpenCV官网下载 img cv2.imread(../picture/digits.png, cv2.IMREAD_GRAYSCALE) if img is None: raise FileNotFoundError(未找到digits.png文件请从OpenCV官方示例库下载后放到当前目录) # digits.png的结构每行100个数字每个数字20x20像素 rows, cols img.shape cell_rows, cell_cols 20, 20 num_cells_per_row cols // cell_cols # 存储所有数字样本和标签 samples [] labels [] # 遍历每个20x20的数字单元格 for i in range(0, rows - cell_rows 1, cell_rows): for j in range(0, cols - cell_cols 1, cell_cols): # 截取单个数字区域 digit img[i:i cell_rows, j:j cell_cols] # 展平为一维特征向量 samples.append(digit.flatten()) # 计算标签0-9循环 label (j // cell_cols) % 10 labels.append(label) # 转换为numpy数组 samples np.array(samples, dtypenp.float32) labels np.array(labels, dtypenp.int32) # 划分训练集前1000个样本和测试集后1000个样本 train_split 1000 train_data samples[:train_split] train_labels labels[:train_split] test_data samples[train_split:train_split 1000] test_labels labels[train_split:train_split 1000] return train_data, train_labels, test_data, test_labels def bayesian_classifier_demo(): # 1. 加载手写数字数据集修复后的通用方法 try: train_data, train_labels, test_data, test_labels load_digits_dataset() except FileNotFoundError as e: print(e) return # 数据预处理归一化 train_data train_data / 255.0 test_data test_data / 255.0 # 2. 训练高斯贝叶斯分类器 gnb GaussianNB() gnb.fit(train_data, train_labels) # 修复无需ravel因为load_digits_dataset返回一维标签 # 3. 预测并评估 pred_labels gnb.predict(test_data) accuracy accuracy_score(test_labels, pred_labels) # 4. 可视化效果随机选5个样本对比 plt.figure(figsize(15, 4)) np.random.seed(42) # 固定随机种子 random_idx np.random.choice(len(test_data), 5, replaceFalse) for i, idx in enumerate(random_idx): img test_data[idx].reshape(20, 20) # 还原为20x20的数字图像 true_label test_labels[idx] pred_label pred_labels[idx] plt.subplot(1, 5, i 1) plt.imshow(img, cmapgray) title f真实:{true_label}\n预测:{pred_label} # 预测正确标绿色错误标红色 plt.title(title, colorgreen if true_label pred_label else red) plt.axis(off) # 整体准确率标题 plt.suptitle(f高斯贝叶斯分类器识别效果准确率{accuracy:.2%}, fontsize14) plt.tight_layout() plt.show() # 运行贝叶斯分类器示例 if __name__ __main__: bayesian_classifier_demo()效果说明代码基于手写数字数据集训练贝叶斯分类器随机展示 5 个测试样本的识别结果绿色标题预测正确红色标题预测错误顶部显示整体准确率直观体现统计分类器的识别效果。12.2.3 神经网络核心思想模拟人脑神经元结构通过多层网络自动学习特征并完成分类比传统方法更适合复杂目标识别。实战代码CNN 识别手写数字import cv2 import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.datasets import mnist from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Input from tensorflow.keras.utils import to_categorical # 设置matplotlib支持中文显示 修复后端兼容性问题 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False # 强制使用Agg后端解决tostring_rgb报错 plt.switch_backend(Agg) def cnn_recognition_demo(): # 1. 加载MNIST手写数字数据集 (x_train, y_train), (x_test, y_test) mnist.load_data() # 2. 数据预处理 # 调整形状(样本数, 高度, 宽度, 通道数) 归一化 x_train x_train.reshape(-1, 28, 28, 1).astype(np.float32) / 255.0 x_test x_test.reshape(-1, 28, 28, 1).astype(np.float32) / 255.0 # 标签独热编码 y_train to_categorical(y_train, 10) y_test to_categorical(y_test, 10) # 3. 构建CNN模型修复Input Shape警告 model Sequential([ Input(shape(28, 28, 1)), # 推荐写法消除警告 # 卷积层1提取边缘特征 Conv2D(32, (3, 3), activationrelu), MaxPooling2D((2, 2)), # 池化层降维 # 卷积层2提取复杂特征 Conv2D(64, (3, 3), activationrelu), MaxPooling2D((2, 2)), # 全连接层分类 Flatten(), Dense(64, activationrelu), Dense(10, activationsoftmax) # 输出10类概率 ]) # 编译模型 model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy]) # 4. 训练模型 model.fit(x_train, y_train, epochs2, batch_size32, validation_split0.1, verbose1) # 5. 评估模型 test_loss, test_acc model.evaluate(x_test, y_test, verbose1) print(fCNN模型测试准确率{test_acc:.2%}) # 6. 可视化识别效果优化一次性预测选中的样本提升效率 np.random.seed(42) # 固定随机种子结果可复现 random_idx np.random.choice(len(x_test), 8, replaceFalse) # 一次性获取选中样本的预测结果避免循环内多次调用predict selected_test x_test[random_idx] pred_probs model.predict(selected_test, verbose0) # 创建画布 fig, axes plt.subplots(2, 4, figsize(15, 6)) axes axes.flatten() # 展平轴方便循环 for i, idx in enumerate(random_idx): img x_test[idx].reshape(28, 28) # 还原为28x28图像 pred_prob pred_probs[i] pred_label np.argmax(pred_prob) true_label np.argmax(y_test[idx]) # 绘制图像 axes[i].imshow(img, cmapgray) title f真实:{true_label}\n预测:{pred_label}\n概率:{pred_prob[pred_label]:.2f} axes[i].set_title(title, colorgreen if true_label pred_label else red) axes[i].axis(off) # 整体标题 fig.suptitle(fCNN手写数字识别效果准确率{test_acc:.2%}, fontsize14) plt.tight_layout() # 修复显示逻辑先保存到内存再显示避免后端兼容问题 import io from PIL import Image # 将matplotlib图转换为PIL图像 buf io.BytesIO() plt.savefig(buf, formatpng, bbox_inchestight, dpi100) buf.seek(0) img_pil Image.open(buf) # 转换为OpenCV格式并显示 img_cv cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR) cv2.imshow(CNN手写数字识别效果, img_cv) cv2.waitKey(0) # 等待按键关闭窗口 cv2.destroyAllWindows() buf.close() # 运行CNN识别示例 if __name__ __main__: cnn_recognition_demo()效果说明代码构建简单的卷积神经网络CNN实现手写数字识别训练 2 轮即可达到 98% 以上的准确率可视化展示 8 个样本的识别结果包含真实标签、预测标签和预测概率直观体现神经网络在复杂目标识别中的优势12.3 结构方法这类方法关注目标的结构特征如形状、拓扑关系通过匹配结构描述来识别目标适合具有明确形状特征的目标。12.3.1 形状数匹配核心思想形状数是基于轮廓的形状描述符通过计算目标轮廓的形状数与模板形状数对比实现识别形状数越接近形状越相似。实战代码形状数匹配识别简单形状import cv2 import numpy as np import matplotlib.pyplot as plt # 核心修复设置兼容的matplotlib后端 中文显示 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False plt.rcParams[backend] TkAgg # 改用TkAgg后端解决PyCharm兼容性问题 def calculate_shape_number(contour): 计算轮廓的形状数4阶 # 1. 计算轮廓的质心 M cv2.moments(contour) if M[m00] 0: return np.zeros(4) cx int(M[m10] / M[m00]) cy int(M[m01] / M[m00]) # 2. 计算轮廓点到质心的距离 dists [] for point in contour: x, y point[0] dist np.sqrt((x - cx) ** 2 (y - cy) ** 2) dists.append(dist) # 3. 计算4阶形状数均值、方差、最大值、最小值 shape_num [ np.mean(dists), # 均值 np.var(dists), # 方差 np.max(dists), # 最大值 np.min(dists) # 最小值 ] return np.array(shape_num) def shape_number_matching_demo(): # 1. 创建模板形状圆形、正方形、三角形 # 生成黑色背景 img_template np.zeros((200, 600, 3), dtypenp.uint8) # 绘制圆形 cv2.circle(img_template, (100, 100), 50, (255, 255, 255), -1) # 绘制正方形 cv2.rectangle(img_template, (250, 50), (350, 150), (255, 255, 255), -1) # 绘制三角形 pts np.array([[450, 150], [500, 50], [550, 150]], np.int32) cv2.fillPoly(img_template, [pts], (255, 255, 255), lineTypecv2.LINE_AA) # 抗锯齿形状更平滑 # 2. 提取模板轮廓并计算形状数 gray_template cv2.cvtColor(img_template, cv2.COLOR_BGR2GRAY) # 修复兼容OpenCV不同版本的返回值有些版本返回3个值这里用_忽略 contours_template, hierarchy cv2.findContours(gray_template, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 按面积排序过滤小轮廓 contours_template sorted(contours_template, keycv2.contourArea, reverseTrue)[:3] template_shape_nums [calculate_shape_number(cont) for cont in contours_template] template_labels [圆形, 正方形, 三角形] # 3. 创建待识别图像随机形状比如变形的圆形 img_test np.zeros((200, 200, 3), dtypenp.uint8) # 绘制略微变形的圆形椭圆模拟 cv2.ellipse(img_test, (100, 100), (50, 45), 0, 0, 360, (255, 255, 255), -1, lineTypecv2.LINE_AA) # 4. 提取测试图像轮廓并计算形状数 gray_test cv2.cvtColor(img_test, cv2.COLOR_BGR2GRAY) contours_test, hierarchy cv2.findContours(gray_test, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 增加异常处理确保找到轮廓 if len(contours_test) 0: print(错误未检测到待识别图像的轮廓) return test_shape_num calculate_shape_number(contours_test[0]) # 5. 形状数匹配计算欧氏距离距离最小为匹配结果 distances [np.linalg.norm(test_shape_num - tsn) for tsn in template_shape_nums] match_idx np.argmin(distances) match_label template_labels[match_idx] # 6. 可视化效果保留原有逻辑仅修复显示问题 plt.figure(figsize(12, 6), dpi100) # 增加dpi图像更清晰 # 子图1模板形状 plt.subplot(1, 3, 1) plt.imshow(cv2.cvtColor(img_template, cv2.COLOR_BGR2RGB)) plt.title(模板形状圆形/正方形/三角形, fontsize12) plt.axis(off) # 子图2待识别形状 plt.subplot(1, 3, 2) plt.imshow(cv2.cvtColor(img_test, cv2.COLOR_BGR2RGB)) plt.title(待识别形状变形圆形, fontsize12) plt.axis(off) # 子图3匹配结果 plt.subplot(1, 3, 3) # 优化文字显示效果 plt.text(0.5, 0.5, f匹配结果{match_label}\n f匹配距离{distances[match_idx]:.2f}\n f各模板距离\n f圆形{distances[0]:.2f} | 正方形{distances[1]:.2f} | 三角形{distances[2]:.2f}, hacenter, vacenter, fontsize14, bboxdict(boxstyleround,pad0.5, facecolorlightblue, alpha0.7)) plt.title(形状数匹配结果, fontsize12) plt.axis(off) plt.tight_layout(pad2.0) # 增加间距避免文字重叠 plt.show(blockTrue) # blockTrue确保窗口正常显示不闪退 # 运行形状数匹配示例 if __name__ __main__: # 增加异常捕获方便调试 try: shape_number_matching_demo() except Exception as e: print(f程序运行出错{e}) # 若TkAgg后端不可用自动切换到Agg并保存图片 plt.switch_backend(Agg) # 重新运行核心逻辑并保存图片 shape_number_matching_demo() plt.savefig(形状数匹配结果.png, bbox_inchestight, dpi150) print(已将结果保存为形状数匹配结果.png当前目录)效果说明代码实现简单形状的形状数匹配先创建圆形、正方形、三角形模板并计算形状数对待识别的变形圆形计算形状数通过欧氏距离匹配最相似的模板可视化展示模板、待识别形状、匹配结果直观理解形状数的作用12.3.2 字符串匹配核心思想将目标的轮廓 / 结构转换为字符串序列比如方向链码通过字符串匹配算法如编辑距离识别目标。实战代码方向链码字符串匹配import cv2 import numpy as np import matplotlib.pyplot as plt from Levenshtein import distance as lev_distance # 需安装pip install python-Levenshtein plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False def contour_to_chain_code(contour): 将轮廓转换为8方向链码字符串 # 8方向链码定义0-7顺时针 directions [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)] chain_code [] # 取轮廓第一个点作为起始点 prev_x, prev_y contour[0][0] for i in range(1, len(contour)): curr_x, curr_y contour[i][0] # 计算相对位移 dx curr_x - prev_x dy curr_y - prev_y # 匹配方向链码 for idx, (dx_dir, dy_dir) in enumerate(directions): if dx dx_dir and dy dy_dir: chain_code.append(str(idx)) break prev_x, prev_y curr_x, curr_y return .join(chain_code) def string_matching_demo(): # 1. 创建模板字母A img_template np.zeros((200, 200, 3), dtypenp.uint8) # 绘制字母A pts_a np.array([[100, 50], [50, 180], [70, 140], [130, 140], [150, 180]], np.int32) cv2.polylines(img_template, [pts_a], isClosedTrue, color(255, 255, 255), thickness2) # 2. 提取模板轮廓并转换为链码字符串 gray_template cv2.cvtColor(img_template, cv2.COLOR_BGR2GRAY) contours_template, _ cv2.findContours(gray_template, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) template_chain contour_to_chain_code(contours_template[0]) # 3. 创建待识别图像变形的A和干扰字母B # 变形的A img_test_a np.zeros((200, 200, 3), dtypenp.uint8) pts_a_test np.array([[100, 60], [55, 180], [75, 145], [125, 145], [145, 180]], np.int32) cv2.polylines(img_test_a, [pts_a_test], isClosedTrue, color(255, 255, 255), thickness2) # 字母B img_test_b np.zeros((200, 200, 3), dtypenp.uint8) cv2.ellipse(img_test_b, (100, 100), (60, 80), 0, 0, 180, (255, 255, 255), 2) cv2.line(img_test_b, (100, 40), (100, 160), (255, 255, 255), 2) # 4. 提取测试图像链码并匹配 # 变形A的链码 gray_test_a cv2.cvtColor(img_test_a, cv2.COLOR_BGR2GRAY) contours_test_a, _ cv2.findContours(gray_test_a, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) test_a_chain contour_to_chain_code(contours_test_a[0]) # B的链码 gray_test_b cv2.cvtColor(img_test_b, cv2.COLOR_BGR2GRAY) contours_test_b, _ cv2.findContours(gray_test_b, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) test_b_chain contour_to_chain_code(contours_test_b[0]) # 计算编辑距离越小越相似 dist_a lev_distance(template_chain, test_a_chain) dist_b lev_distance(template_chain, test_b_chain) # 5. 可视化效果 plt.figure(figsize(15, 6)) # 子图1模板A plt.subplot(1, 3, 1) plt.imshow(cv2.cvtColor(img_template, cv2.COLOR_BGR2RGB)) plt.title(f模板字母A\n链码长度{len(template_chain)}) plt.axis(off) # 子图2变形A plt.subplot(1, 3, 2) plt.imshow(cv2.cvtColor(img_test_a, cv2.COLOR_BGR2RGB)) plt.title(f待识别变形A\n编辑距离{dist_a}) plt.axis(off) # 子图3字母B plt.subplot(1, 3, 3) plt.imshow(cv2.cvtColor(img_test_b, cv2.COLOR_BGR2RGB)) plt.title(f干扰项字母B\n编辑距离{dist_b}) plt.axis(off) plt.suptitle(f字符串匹配结果变形A与模板更相似距离更小, fontsize14) plt.tight_layout() plt.show() # 运行字符串匹配示例 if __name__ __main__: string_matching_demo()效果说明代码将轮廓转换为方向链码字符串通过编辑距离实现匹配变形字母 A 与模板 A 的编辑距离远小于字母 B直观体现字符串匹配在结构特征识别中的作用需提前安装依赖pip install python-Levenshtein三、核心逻辑流程图四、知识点思维导图五、小结目标识别的核心是特征提取 分类决策先将目标转换为可计算的特征模式再通过特定方法判定所属类别。决策理论方法适合特征可量化的场景匹配法简单直观统计分类器基于概率神经网络适合复杂特征无需手动设计特征。结构方法适合形状 / 结构明确的目标通过形状数、字符串等描述结构特征匹配更关注目标的拓扑关系而非数值特征。实际应用中需根据目标特征选择方法简单目标用匹配法 / 统计分类器复杂目标用神经网络形状类目标用结构方法。六、运行说明所有代码均基于 Python 3.7 编写需安装依赖pip install opencv-python numpy matplotlib scikit-learn tensorflow python-Levenshtein模板匹配示例需准备digits.png可从 OpenCV 官网下载其余代码无需额外数据MNIST 数据集会自动下载。代码均包含详细注释可直接复制运行运行后会自动弹出效果对比图。