首先我们需要知道,图片及视频在计算机中都是以矩阵的形式存在的,所以下述的所有操作其实都是基于矩阵进行的。
# 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()
# 此步骤形态学变换的预处理,得到可以查找矩形的图片
# 参数:输入矩阵、输出矩阵数据类型、设置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()
# 设置膨胀和腐蚀操作的核函数
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()