[Python]OpenCV学习总结及文字检测

最近我学习了OpenCV,了解到OpenCV是图像处理的一个强大工具包,将简单介绍下OpenCV的几个用途。

首先我们需要知道,图片及视频在计算机中都是以矩阵的形式存在的,所以下述的所有操作其实都是基于矩阵进行的。

  • 几何变换:有放缩、旋转、投影变换等,实际上是乘一个矩阵使图片上整体的值左右上下移动。
  • 对比度增强。该部分一般要将图片处理为灰度图后处理,通过对灰度值进行线性变换等操作,调整对比度。
  • 图像平滑:平滑的作用即为去除噪声,如一个卷积核每次取平均值(均值平滑)等,这样的作用相当于将局部图片给抹匀。在除去噪声的同时降低了对比度
  • 阈值分割:不同的方法选取不同的一个值,高低这个值的点被处理为最大值(255)和最小值(0)最后形成二值图。
  • 形态学处理:对二值图的黑白部分进行处理,原理和卷积类似,代表操作为膨胀和腐蚀。
  • 边缘检测:图像的边缘是指灰度值发生剧烈变化的位置,利用各种算子可以对边界处理达到不同的效果。 比如美图软件中有将图片转为素描画这种功能,其实使用边缘检测做的。
  • 几何形状的检测和拟合:此部分主要内容为直线、圆的检测,点集的最小外包和轮廓等概念。结合前部分处理后的二值图,可以圈出区域。
  • 颜色空间:RGB、HSV(色调、饱和度、亮度)、HLS(色调、光亮度、饱和度),不同颜色空间的转换可以处理亮度及饱和度等问题。
下面程序将纯粹使用OpenCV对一个白底图片进行文字检测
# coding:utf8
import numpy as np
import cv2
import sys
import os
import matplotlib.pyplot as plt
from PIL import Image

读取原文件并显示

# 读取文件
imagePath = os.getcwd()+"\\test.png"
img = cv2.imread(imagePath)
plt.imshow(img,'brg')
plt.show()

原图

转化成灰度图并显示

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray,'gray')
plt.show()

 灰度图

利用Sobel边缘检测生成二值图

原理:边缘检测的原理是利用灰度变化剧烈的位置,即梯度变化剧烈的位置,Sobel算子利用差分的方法检测出边缘的位置,本质是一个卷积核乘一个矩阵
# 此步骤形态学变换的预处理,得到可以查找矩形的图片
# 参数:输入矩阵、输出矩阵数据类型、设置1、0时差分方向为水平方向的核卷积,设置0、1为垂直方向,ksize:核的尺寸
sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, ksize = 3)  
# 二值化
ret, binary = cv2.threshold(sobel, 0, 255, cv2.THRESH_OTSU+cv2.THRESH_BINARY)
plt.imshow(binary,'gray')
plt.show()

二值图

利用膨胀和腐蚀处理二值图使白色区域更方正

原理:腐蚀和膨胀很像卷积神经网络的池化层,不过腐蚀膨胀左右移动步长为1(为保证图大小不变),腐蚀是取一个核中最小值、膨胀是取最大值。
所以对一个二值图来说,腐蚀作用是让黑色区域变多,膨胀作用是让白色区域变多。由腐蚀、膨胀作为基本操作可结合出闭运算(先膨胀后腐蚀)、开运算(先腐蚀后膨胀)、顶帽运算(图像减去开运算结果)、底帽运算(图像减去闭运算的结果)
# 设置膨胀和腐蚀操作的核函数
element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 9))
element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (24, 6))

# 膨胀一次,让轮廓突出
dilation = cv2.dilate(binary, element2, iterations = 1)

# 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
erosion = cv2.erode(dilation, element1, iterations = 1)

# aim = cv2.morphologyEx(binary, cv2.MORPH_CLOSE,element1, 1 )   #此函数可实现闭运算和开运算
# 以上膨胀+腐蚀称为闭运算,具有填充白色区域细小黑色空洞、连接近邻物体的作用

# 再次膨胀,让轮廓明显一些
dilation2 = cv2.dilate(erosion, element2, iterations = 3)
# 显示膨胀一次后的图像处理效果
plt.imshow(dilation2,'gray')
plt.show()

膨胀一次

# 显示一次闭运算后的效果
plt.imshow(erosion,'gray')
plt.show()

闭运算一次

# 显示连续膨胀3次后的效果
plt.imshow(dilation2,'gray')
plt.show()

再膨胀三次

#  查找和筛选文字区域
region = []
#  查找轮廓
img2, contours, hierarchy = cv2.findContours(dilation2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  
# 利用以上函数可以得到多个轮廓区域,存在一个列表中。
#  筛选那些面积小的
for i in range(len(contours)):
    # 遍历所有轮廓
    # cnt是一个点集
    cnt = contours[i]
    
    # 计算该轮廓的面积
    area = cv2.contourArea(cnt) 
    
    # 面积小的都筛选掉、这个1000可以按照效果自行设置
    if(area < 1000):
        continue
    
#     # 将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定
#     # 轮廓近似,作用很小
#     # 计算轮廓长度
#     epsilon = 0.001 * cv2.arcLength(cnt, True)
   
#     # 
# #     approx = cv2.approxPolyDP(cnt, epsilon, True)

    # 找到最小的矩形,该矩形可能有方向
    rect = cv2.minAreaRect(cnt)
    # 打印出各个矩形四个点的位置
    print ("rect is: ")
    print (rect)

    # box是四个点的坐标
    box = cv2.boxPoints(rect)
    box = np.int0(box)

    # 计算高和宽
    height = abs(box[0][1] - box[2][1])
    width = abs(box[0][0] - box[2][0])

    # 筛选那些太细的矩形,留下扁的
    if(height > width * 1.3):
        continue

    region.append(box)
rect is: 
((322.5, 673.5), (645.0, 37.0), -0.0)
rect is: 
((326.5, 618.0), (653.0, 38.0), -0.0)
rect is: 
((303.99993896484375, 564.4999389648438), (607.9998779296875, 36.99999237060547), 0.0)
rect is: 
((369.5, 498.0), (739.0, 42.0), -0.0)
rect is: 
((362.5, 426.0), (725.0, 42.0), -0.0)
rect is: 
((376.0, 364.0), (752.0, 42.0), -0.0)
rect is: 
((336.0, 305.0), (672.0, 42.0), -0.0)
rect is: 
((369.0, 246.5), (738.0, 41.0), -0.0)
rect is: 
((370.49993896484375, 186.99998474121094), (740.9998779296875, 41.99999237060547), -0.0)
rect is: 
((361.0, 126.5), (722.0, 45.0), -0.0)
rect is: 
((651.9999389648438, 41.99999237060547), (223.99996948242188, 39.99999237060547), -0.0)
rect is: 
((129.49998474121094, 34.499996185302734), (190.99996948242188, 44.99999237060547), 0.0)
# 用绿线画出这些找到的轮廓
for box in region:
    cv2.drawContours(img, [box], 0, (0, 255, 0), 2)

    
plt.imshow(img,'brg')
plt.show()

识别区域

# 弹窗显示
cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.imshow("img", img)

    # 带轮廓的图片
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 11
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值