文章目錄
- 前言
- 一、攝像頭調用通用方法
- 1、導入必要的庫
- 2、創建攝像頭接口
- 二、攝像頭OCR
- 1.引入庫
- 2、定義函數
- (1)定義顯示opencv顯示函數
- (2)保持寬高比的縮放函數
- (3)坐標點排序函數
- (4) 四點透視變換實現
- 3、讀取攝像頭顯示攝像頭畫面并做灰度處理
- 4、做中值濾波并使用canny邊緣檢測
- 5、輪廓檢測
- 6、遍歷輪廓
- 7、透視變換
- 完整代碼展示
- 總結
- 應用
- 文檔處理
- 車牌識別
- 身份證識別
- 場景文字識別
前言
攝像頭 OCR 是指利用攝像頭采集圖像信息,然后通過光學字符識別(OCR)技術對圖像中的文字進行識別和處理的一種技術手段。
一、攝像頭調用通用方法
1、導入必要的庫
import cv2
import numpy as np
2、創建攝像頭接口
讀取本地的視頻文件或者攝像頭,接收的參數為視頻文件的地址,或者攝像頭的名稱(一般0指的是電腦自身的攝像頭,1則是外接的攝像頭)
video_capture=cv2.VideoCapture('../data/test.avi')#判斷視頻文件或者攝像頭是否正常讀取,如果讀取失敗則返回提示信息
if not video_capture.isOpened():print("視頻打開失敗")exit()
視頻以及攝像頭文件我們都可以把它理解成老式的電影,一段視頻以及攝像頭讀取的畫面都可以看成是一張圖片一張圖片的播放,只是視頻和攝像頭的播放速度很快,導致我們視覺上認為動作是連貫的,幀率也就是一秒播放多少張圖片。
因此,在使用opencv讀取攝像頭和視頻文件時我們采用循環的方法來不斷獲取攝像頭讀取的畫面。
當我們要使用opencv來做視覺方向的問題時,我們就可以調用攝像頭,對對讀取到的每一幀畫面做視覺方面的處理,來達到與攝像頭結合的動態效果。
while True:ret,frame=video_capture.read()#ret是一個標志,檢測攝像頭是否讀取成功,frame則是接收到的畫面,是一張一張的圖片if not ret:break#設置這個if判斷,是為了手動控制跳出循環,當我們按下ESC鍵時跳出循環停止讀取畫面。if cv2.waitKey(100)==27:break#釋放攝像頭資源
video_capture.release()
cv2.destroyAllWindows()
二、攝像頭OCR
簡單處理文字,將不正的文檔扶正并使文檔的字跡更清晰。
1.引入庫
import numpy as np
import cv2
2、定義函數
(1)定義顯示opencv顯示函數
def cv_show(name,value):cv2.imshow(name,value)cv2.waitKey(50)
(2)保持寬高比的縮放函數
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 image # 無縮放直接返回if 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 resized
(3)坐標點排序函數
def order_points(pts):rect = np.zeros((4, 2), dtype="float32") # 初始化4x2矩陣#按順序找到對應的坐標0123,分別是左上右上右下、左下# 計算坐標點x+y的和s = pts.sum(axis=1) # 形狀:(4,) ,對矩陣的每一行進行求和操作rect[0] = pts[np.argmin(s)] # 左上角:x+y最小rect[2] = pts[np.argmax(s)] # 右下角:x+y最大# 計算坐標點x-y的差diff = np.diff(pts, axis=1) # 形狀:(4,1)rect[1] = pts[np.argmin(diff)] # 右上角:x-y最小(即y相對較大)rect[3] = pts[np.argmax(diff)] # 左下角:x-y最大(即y相對較小)return rect # 返回有序坐標:[左上, 右上, 右下, 左下]
(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], # 寬度方向預留1像素邊界[maxWidth - 1, maxHeight - 1],[0, maxHeight - 1]], dtype="float32")# 計算透視變換矩陣(核心數學操作)M = cv2.getPerspectiveTransform(rect, dst)# 執行透視變換warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))return warped
3、讀取攝像頭顯示攝像頭畫面并做灰度處理
#讀取輸入
cap=cv2.VideoCapture(0)
if not cap.isOpened():print("攝像頭打開失敗")exit()while True:flag=0 #是否檢測到文檔的標志ret,frame=cap.read()orig=frame.copy()if not ret: #讀取失敗則退出循環print("不能讀取攝像頭")breakcv_show('iamge',frame)gray=cv2.cvtColor(frame,cv2.COLOR_BGRA2GRAY)
4、做中值濾波并使用canny邊緣檢測
gray=cv2.medianBlur(gray,3)
edged=cv2.Canny(gray,75,200)
cv_show('i',edged)
中值濾波核大小 3 適用于720p分辨率
Canny閾值可改為自適應算法(如基于圖像亮度百分比)
5、輪廓檢測
#輪廓檢測cnts=cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]cnts=sorted(cnts,key=cv2.contourArea,reverse=True)[:3]# 取面積前三的輪廓image_contours=cv2.drawContours(orig,cnts,-1,(0,255,0),2) # 多邊形近似cv_show('image_contours',image_contours)
RETR_EXTERNAL 只檢測最外層輪廓(假設文檔無嵌套)
面積閾值 20000 需根據攝像頭分辨率調整(例如:1280x720下約為2%畫面占比)
6、遍歷輪廓
#遍歷輪廓做透視變換for c in cnts:peri=cv2.arcLength(c,True)#做輪廓近似approx=cv2.approxPolyDP(c,0.01*peri,True)area=cv2.contourArea(approx)#做透視變換要求輪廓近似滿足是4個點,挑選出符合要求的結果if area>20000 and len(approx)==4:screenCnt=approxflag=1 #標識找到了文檔print(peri,area)print('檢測到文檔')break
7、透視變換
if flag==1:image_contours=cv2.drawContours(frame,[screenCnt],0,(0,255,0),2)cv_show('image',image_contours)#左四點轉換,扶正后的坐標warped=four_point_transform(orig,screenCnt.reshape(4,2))cv_show('warped',warped)cap.release()
cv2.destroyAllWindows()
完整代碼展示
import numpy as np
import cv2def cv_show(name,value):cv2.imshow(name,value)cv2.waitKey(50)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))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#讀取輸入
cap=cv2.VideoCapture(0)
if not cap.isOpened():print("攝像頭打開失敗")exit()while True:flag=0 #是否檢測到文檔的標志ret,frame=cap.read()orig=frame.copy()if not ret: #讀取失敗則退出循環print("不能讀取攝像頭")breakcv_show('iamge',frame)gray=cv2.cvtColor(frame,cv2.COLOR_BGRA2GRAY)gray=cv2.medianBlur(gray,3)edged=cv2.Canny(gray,75,200)cv_show('i',edged)#輪廓檢測cnts=cv2.findContours(edged,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]cnts=sorted(cnts,key=cv2.contourArea,reverse=True)[:3]image_contours=cv2.drawContours(orig,cnts,-1,(0,255,0),2)cv_show('image_contours',image_contours)#遍歷輪廓做透視變換for c in cnts:peri=cv2.arcLength(c,True)#做輪廓近似approx=cv2.approxPolyDP(c,0.01*peri,True)area=cv2.contourArea(approx)#做透視變換要求輪廓近似滿足是4個點,挑選出符合要求的結果if area>20000 and len(approx)==4:screenCnt=approxflag=1 #標識找到了文檔print(peri,area)print('檢測到文檔')breakif flag==1:image_contours=cv2.drawContours(frame,[screenCnt],0,(0,255,0),2)cv_show('image',image_contours)#左四點轉換,扶正后的坐標warped=four_point_transform(orig,screenCnt.reshape(4,2))cv_show('warped',warped)cap.release()
cv2.destroyAllWindows()
總結
應用
文檔處理
快速將紙質文檔中的文字轉換為電子文本,方便編輯、存儲和檢索,提高文字處理效率。
車牌識別
在智能交通系統中,通過攝像頭拍攝車牌圖像,利用 OCR 技術自動識別車牌號碼,實現車輛的自動管理和收費等功能。
身份證識別
在一些需要身份驗證的場合,如銀行開戶、酒店入住等,通過攝像頭 OCR 快速識別身份證上的文字信息,提高信息錄入效率和準確性。
場景文字識別
在圖像和視頻內容分析中,識別場景中的文字,如街道標志、廣告招牌等,為圖像理解和信息檢索提供支持。