用KNN實現手寫數字識別:基于 OpenCV 和 scikit-learn 的實戰教學 (超級超級超級簡單)

用KNN實現手寫數字識別:基于 OpenCV 和 scikit-learn 的實戰教學

在這篇文章中,我們將使用 KNN(K-Nearest Neighbors)算法對手寫數字進行分類識別。我們會用 OpenCV 讀取圖像并預處理數據,用 scikit-learn 構建并訓練模型,最終識別新的數字圖像。

為什么像素可以被代碼讀取為數據:

圖像的本質:像素的數字矩陣

任何數字圖像(如照片、截圖、手寫數字圖片)都是由無數個微小的 “像素點”(Pixel)組成的

  • 每個像素點的數值含義

    • 對于灰度圖(如代碼中的手寫數字),每個像素用一個 0-255 的整數表示亮度:0 代表純黑,255 代表純白,中間值表示不同深淺的灰色。
    • 對于彩色圖(如 RGB 格式),每個像素由三個數值(R、G、B)組成,分別對應紅、綠、藍三種顏色的亮度,組合后呈現出各種顏色。

(可以在調試時看一看代碼里的‘gray’參數里面 單個數字圖像的矩陣)

此20×20 像素的數字圖像就是一個數字矩陣顯示出的一個大大的 0

使用的數據集

我們使用的是一個包含 5000 個手寫數字(0-9) 的圖像文件(digits5000.png),每種數字500個,總共10類。圖像被排布成了一個 50 行 × 100 列 的網格,每個小格是一個 20×20 像素的數字圖像

數據圖像:

保存下面代碼所需的三張圖片:

?

上面的 ‘3’,‘6’ 圖片可在‘開始’里的‘畫圖’中,可以創建我們想要自定義的數字圖片:


然后使用畫筆寫一個數字后(筆粗一點):

把比例調到? ?20×20 像素

即可得到。

?完整代碼:

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
import cv2# 讀取包含5000個手寫數字的大圖,每個數字為20x20像素
img = cv2.imread('digits5000.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 轉換為灰度圖# 將大圖分割為50行100列的小單元格,每個單元格包含一個手寫數字
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]# 將單元格列表轉換為四維數組: (50行, 100列, 20像素高, 20像素寬)
x = np.array(cells)# 準備訓練集和測試集數據
# 前50列作為訓練集,后50列作為測試集
# 數據重塑為: (樣本數, 特征數),每個樣本包含400個像素值
train = x[:,:50].reshape(-1,400)
test = x[:,50:].reshape(-1,400)# 創建標簽數據
n = np.arange(10)  # 創建數字0-9的數組
# 每個數字對應250個樣本(50行×5列),生成訓練標簽
tags = np.repeat(n,250)
tag = tags[:,np.newaxis]  # 轉換為二維數組,形狀為(2500, 1)# 創建并訓練KNN分類器,使用k=5最近鄰
knn = KNeighborsClassifier(n_neighbors=5)    #給初學者的建議:在此處設置斷點 或 直接在import處設置斷點,開啟調試一行一行地運行,更好的看到每一個參數的變化
knn.fit(train, tag)# 評估模型在訓練集上的準確率
predictions_train = knn.predict(train)    #此行結果沒有運行,建議在開啟調試,可看到
accuracy_train = knn.score(train, tag)
print(f"訓練集準確率: {accuracy_train:.4f}")# 評估模型在測試集上的準確率
predictions_test = knn.predict(test)
accuracy_test = knn.score(test, tag)
print(f"測試集準確率: {accuracy_test:.4f}")# 預測外部數字3的圖像
digit3 = cv2.imread('digit3.png')
digit3gray = cv2.cvtColor(digit3, cv2.COLOR_BGR2GRAY)
digit3test = digit3gray.reshape(-1,400)  # 重塑為模型期望的輸入格式
predictions_digit3 = knn.predict(digit3test)
print(f"預測數字3的結果: {predictions_digit3}")# 預測外部數字6的圖像
digit6 = cv2.imread('digit6.png')
digit6gray = cv2.cvtColor(digit6, cv2.COLOR_BGR2GRAY)
digit6test = digit6gray.reshape(-1,400)  # 重塑為模型期望的輸入格式
predictions_digit6 = knn.predict(digit6test)
print(f"預測數字6的結果: {predictions_digit6}")

紅色斷點:

調試:

點擊 單步執行 或 其他? ?,多嘗試嘗試

點擊“作為...查看”即可清晰查看


所需庫導入

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
import cv2
  • numpy: 用于矩陣操作。

  • sklearn.neighbors.KNeighborsClassifier: 實現KNN分類器。

  • cv2: OpenCV庫,用于圖像讀取與處理。


圖像加載與預處理

img = cv2.imread('digits5000.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

  • cv2.imread() 讀取圖像。

  • cv2.cvtColor() 將圖像從彩色(BGR)轉換為灰度(GRAY),便于處理。


圖像分割成小數字圖塊

cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
x = np.array(cells)
  • 使用 np.vsplit() 將圖像豎直切成50行(每行包含100個數字)。

  • 對每行使用 np.hsplit() 水平切分成100列,最終每個小格是一個20x20的數字圖像。

  • 得到的 x 是一個形狀為 (50, 100, 20, 20) 的數組。


構建訓練集與測試集

train = x[:,:50].reshape(-1,400)
test = x[:,50:].reshape(-1,400)
  • 將每個 20×20 圖像展開為 1×400 的一維向量。

  • 前 50 列作為訓練集,后 50 列作為測試集。

  • traintest 的形狀均為 (2500, 400)


構造標簽

n = np.arange(10)                   #(0123456789)
tags = np.repeat(n,250)            #每個數字重復250次 -> [0,...0,1,...,1,...9,...9]
tag = tags[:,np.newaxis]           #添加新維度,變成列向量
# test_tag = np.repeat(n,250)[:np.newaxis]   
  • tags 是長度為 2500 的一維標簽數組。

  • tag 是形狀為 (2500, 1) 的列向量,作為訓練和測試的真實標簽。

為什么重復250次,因為我們把數據從中間對半切開,每個數字有500個,左二百五十為訓練集,右二百五十個為測試集。

所以其實訓練集和測試集的標簽是一樣的,標簽就是每一個20x20數字圖像所顯示的數字。


訓練模型并評估準確率

knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(train, tag)predictions_train = knn.predict(train)
accuracy_train = knn.score(train, tag)
print(accuracy_train)predictions_test = knn.predict(test)
accuracy_test = knn.score(test, tag)
print(accuracy_test)
  • 初始化一個 KNN 分類器,選擇 k=5

  • 使用 .fit() 訓練模型。

  • 使用 .predict().score() 對訓練集和測試集進行預測和評分。

  • 打印準確率:理論上訓練集精度應很高,測試集略低(但通常也超過 97%)。


識別自定義手寫數字

digit3 = cv2.imread('digit3.png')   #圖片中的數字是3
digit3gray = cv2.cvtColor(digit3, cv2.COLOR_BGR2GRAY)
digit3test = digit3gray.reshape(-1,400)
predictions_digit3 = knn.predict(digit3test)
print(predictions_digit3)digit6 = cv2.imread('digit6.png')   #圖片中的數字是6
digit6gray = cv2.cvtColor(digit6, cv2.COLOR_BGR2GRAY)
digit6test = digit6gray.reshape(-1,400)
predictions_digit6 = knn.predict(digit6test)
print(predictions_digit6)
  • 讀取兩張額外圖像 digit3.pngdigit6.png

  • 將其轉換為灰度、再reshape成與訓練數據一致的 (1, 400) 形狀。

  • 使用模型預測數字類別。


總結

我們用 KNN 成功實現了手寫數字的分類識別,關鍵步驟包括:

  1. 圖像預處理和切分

  2. 標簽構造與數據 reshape

  3. 使用 KNeighborsClassifier 建模

  4. 預測未知圖像的數字類別

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90964.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90964.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90964.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構自學Day15 -- 非比較排序--計數排序

一、計數排序(Counting Sort)計數排序是一種非比較型的排序算法,它的核心思想是:利用“元素的值”來確定它在結果數組中的位置,通過“統計每個數出現的次數”來完成排序。二、如何實現計數排序(核心步驟&am…

k8s的權限

來自博客:25-k8s集群中-RBAC用戶角色資源權限_權限 資源 角色-CSDN博客 一.RBAC概述(基于角色的訪問控制) 1.圖解 用戶: 1.user 2.serviceAccount 3.Group 用戶角色 1.Role:局部資源角色 2.clusterRole:全局資源角色額 角色綁…

C++ - 仿 RabbitMQ 實現消息隊列--服務端核心模塊實現(三)

目錄 隊列數據管理 代碼實現 測試代碼 綁定信息(交換機-隊列)管理 代碼實現 測試代碼 隊列數據管理 當前隊列數據的管理,本質上是隊列描述信息的管理,描述當前服務器上有哪些隊列。 定義隊列描述數據類 隊列名稱是否持久化標志是否獨占標志是否自…

51c自動駕駛~合集9

自己的原文哦~ https://blog.51cto.com/whaosoft/11627386 #端到端1 說起端到端,每個從業者可能都覺得會是下一代自動駕駛量產方案繞不開的點!特斯拉率先吹響了方案更新的號角,無論是完全端到端,還是專注于planner的模…

時間長了忘記jupyter的環境是哪個了

有這些但是忘記是哪個了jupyter kernelspec list查看內核路徑,這個內核是用來告訴jupyter 去哪找內核配置的到這個路徑下打開json文件查看使用的python環境從而確定是哪個conda環境為jupyter使用的python環境jupyter的工作原理:在創建conda環境后會安裝j…

PYTHON從入門到實踐-15數據可視化

數據可視化是數據分析中不可或缺的一環,它能夠將抽象的數據轉化為直觀的圖形,幫助我們更好地理解數據特征和發現潛在規律。本文將介紹如何使用Python中的Matplotlib和Plotly庫進行數據可視化,并通過擲骰子的概率模擬案例展示可視化的實際應用…

Spring IOC 容器 **默認注冊 Bean** 的 8 條規則

Spring IOC 容器 默認注冊 Bean 的 8 條規則 (Spring Framework 6.x 源碼級總結)閱讀提示:把下面 8 條規則背下來,再讀 Spring 源碼時,你會在任何一行代碼里立刻知道「這個 BeanDefinition 是從哪兒來的」。1?? 環境…

29.【.NET8 實戰--孢子記賬--從單體到微服務--轉向微服務】--單體轉微服務--用戶配置服務

用戶配置服務是孢子記賬中最簡單的部分。簡單說,用戶配置服務就是用戶自定義的配置項存儲服務,用于我們的APP根據用戶的配置實現指定的功能。它提供了一個簡單的接口,允許用戶存儲和檢索他們的配置數據。就目前來說,用戶配置只有一…

Python實現PDF按頁分割:靈活拆分文檔的技術指南

Python實現PDF按頁分割:靈活拆分文檔的技術指南 PDF文件處理是日常工作中的常見需求,特別是當我們需要將大型PDF文檔拆分為多個部分時。本文將介紹如何使用Python創建一個靈活的PDF分割工具,能夠根據用戶指定的頁數范圍任意分割文檔。 需求分…

「iOS」——GCD其他方法詳解

GCD學習GCD其他方法dispatch_semaphore (信號量)**什么是信號量**dispatch_semaphore主要作用dispatch_semaphore主要作用異步轉同步設置一個最大開辟的線程數加鎖機制dispatch_time_t 兩種形式GCD一次性代碼(只執行一次)dispatch_barrier_async/sync柵欄…

【圖像處理基石】如何實現一個車輛檢測算法?

基于AI的車牌檢測和識別算法 問題描述、應用場景與難點 問題描述 車牌檢測和識別是計算機視覺領域的一個特定任務,主要包含兩個核心步驟: 車牌檢測:從圖像中準確定位車牌的位置和區域車牌識別:對檢測到的車牌區域進行字符識別&…

計算機學報 2025年 區塊鏈論文 錄用匯總 附pdf下載

計算機學報 Year:2025 2024請看 1 Title: 基于區塊鏈的動態多云多副本數據完整性審計方法研究 Authors: Key words: 區塊鏈;云存儲;多云多副本存儲;數據完整性審計 Abstract: 隨著云計算技術的快速發展和云存儲服務的日益…

計算機網絡-UDP協議

UDP(用戶數據報協議)是傳輸層的一種無連接、不可靠、輕量級的協議,適用于對實時性要求高、能容忍少量數據丟失的場景(如視頻流、DNS查詢等)。以下是UDP的詳細解析:1. UDP的核心特點特性說明無連接通信前無需…

子域名收集和c段查詢

子域名收集方法一、sitesite: 要查詢的域名可以查到相關網站二、oneforall (子域名查找工具)下載后解壓的文件夾在當前文件夾打開終端然后運行命令 python oneforall.py --target xxxxxxxx(這里放你要查的網址) run最…

計網-TCP擁塞控制

TCP的擁塞控制(Congestion Control)是核心機制之一,用于動態調整發送方的數據傳輸速率,避免網絡因過載而出現性能急劇下降(如丟包、延遲激增)。其核心思想是探測網絡可用帶寬,并在擁塞發生時主動…

依賴倒置原則 Dependency Inversion Principle - DIP

基本知識 1.依賴倒置原則(DIP)是面向對象設計(OOD)中的五個基本原則之一,通常被稱為 SOLID 原則中的 D 2.核心思想: 高層模塊不應該依賴低層模塊,兩者都應該依賴抽象。 (High-level modules sho…

原生input添加刪除圖標類似vue里面移入顯示刪除[jquery]

<input type"text" id"servicer-search" class"form-control" autocomplete"off" />上面是剛開始的input <div class"servicer-search-box"><input type"text" id"servicer-search" cla…

整理分享 | Photoshop 2025 (v26.5) 安裝記錄

導語&#xff1a; 最近整理資源時&#xff0c;發現有朋友在找新版 Photoshop。正好手邊有 Photoshop 2025年7月的版本&#xff08;v26.5&#xff09;&#xff0c;就記錄下來分享給大家&#xff0c;供有需要的朋友參考。關于這個版本&#xff1a;這個 Photoshop v26.5 安裝包&am…

【Redis】Redis 數據存儲原理和結構

一、Redis 存儲結構 1.1 KV結構 Redis 本質上是一個 Key-Value&#xff08;鍵值對&#xff0c;KV&#xff09;數據庫&#xff0c;在它豐富多樣的數據結構底層&#xff0c;都基于一種統一的鍵值對存儲結構來進行數據的管理和操作 Redis 使用一個全局的哈希表來管理所有的鍵值對…

【RAG優化】深度剖析OCR錯誤,從根源修復RAG應用的識別問題

1. 引言:OCR——RAG系統中的關鍵問題 當我們將一個包含掃描頁面的PDF或一張報告截圖扔給RAG系統時,我們期望它能“讀懂”里面的內容。這個“讀懂”的第一步,就是OCR。然而,OCR過程并非100%準確,它受到圖像質量、文字布局、字體、語言等多種因素的影響。 一個看似微不足道…