文章目录
前言
摄像头 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("不能读取摄像头")
break
cv_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=approx
flag=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 cv2
def 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 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
def 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 rect
def 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("不能读取摄像头")
break
cv_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=approx
flag=1 #标识找到了文档
print(peri,area)
print('检测到文档')
break
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()
总结
应用
文档处理
快速将纸质文档中的文字转换为电子文本,方便编辑、存储和检索,提高文字处理效率。
车牌识别
在智能交通系统中,通过摄像头拍摄车牌图像,利用 OCR 技术自动识别车牌号码,实现车辆的自动管理和收费等功能。
身份证识别
在一些需要身份验证的场合,如银行开户、酒店入住等,通过摄像头 OCR 快速识别身份证上的文字信息,提高信息录入效率和准确性。
场景文字识别
在图像和视频内容分析中,识别场景中的文字,如街道标志、广告招牌等,为图像理解和信息检索提供支持。