绘制纯色图片
import cv2
import numpy as np
# 512*512*3 长*宽*通道数
white_img = np.ones((512,512,3), np.uint8)
# 每个元素设置为 255 => (255,255,255) 纯白
white_img = 255*white_img
# 显示图片
cv2.imshow('white_img', white_img)
# 等待回车按键
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()

常用绘制函数
import cv2
import numpy as np
img = np.ones((512, 512, 3), np.uint8)
img = 255 * img
# 直线绘制函数 cv2.line(image, starting, ending, color, thickness, lineType)
img = cv2.line(img, (100, 100), (400, 400), (255, 0, 0), 5)
# 长方形绘制函数 cv2.rectangle(image, top-left, bottom-right, color, thickness, lineType)
img = cv2.rectangle(img, (200, 20), (400, 120), (0, 255, 0), 3)
# 圆形绘制函数 cv2.circle(image, center, radius, color, thickness, lineType)
img = cv2.circle(img, (100, 400), 50, (0, 0, 255), 2)
img = cv2.circle(img, (250, 400), 50, (0, 0, 255), 0)
# 椭圆绘制函数 cv2.circle(image, center, (major-axis-length, minor-axis-length), angle, startAngle, endAngle, color, thickness, lineType)
img = cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, (0, 255, 255), -1)
# 多边形绘制函数 cv2.polylines(image, [point-set], flag, color, thickness, lineType)
pts = np.array([[10, 5], [20, 30], [70, 20], [50, 10]], np.int32)
img = cv2.polylines(img, [pts], True, (0, 0, 0), 2)
cv2.imshow('img', img)
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()

图片简单处理
import cv2
import imutils
import numpy as np
rgb_img = cv2.imread('C:/Users/youhl002/Downloads/678702.jpg')
# 缩放图片
rgb_img = imutils.resize(rgb_img, 300)
# 原图
cv2.imshow('rgb_img', rgb_img)
# 灰度
gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray_img', gray_img)
# 灰度取反
reverse_img = 255 - gray_img
cv2.imshow('reverse_img', reverse_img)
# 线性处理
linear_img = np.zeros((gray_img.shape[0], gray_img.shape[1]), dtype=np.uint8)
for i in range(gray_img.shape[0]):
for j in range(gray_img.shape[1]):
linear_img[i, j] = gray_img[i, j] * 1.2
cv2.imshow('linear_img', linear_img)
if cv2.waitKey(0) == 27:
cv2.destroyAllWindows()

银行卡号识别
import cv2
import numpy as np
def get_contours_rets(contours):
rects = []
for i, cnt in enumerate(contours):
x1, y1, w1, h1 = cv2.boundingRect(cnt)
rects.append([x1, y1, w1, h1])
rects.sort(key=lambda x: x[0])
return rects
# 归一化数字
def number_normalize(img, rect, pad=0, size=(57, 88)):
x, y, w, h = rect
original = img[y - pad:y + h + pad, x - pad:x + w + pad]
return cv2.resize(original, size)
# 计算分数
def get_scores(targets, source):
scores = []
for t in targets:
result = cv2.matchTemplate(source, t, cv2.TM_CCOEFF)
(min_val, max_val, min_loc, max_loc) = cv2.minMaxLoc(result)
scores.append(max_val)
return scores
class Ocr:
def __init__(self, ot_img: np.ndarray, src_img: np.ndarray):
self.ot_img: np.ndarray = ot_img
self.src_img: np.ndarray = src_img
self.src_gray: np.ndarray = None
self.labels = []
self.rects = []
print(f"图片尺寸 {src_img.shape}")
def parse(self):
self.parse_template()
self.parse_src()
card = []
for rect in self.rects:
x, y, w, h = rect
# 标记识别的数字轮廓
cv2.rectangle(self.src_img, (x - 10, y - 5), (x + w + 3, y + h + 2), (0, 0, 255), 1)
# 搜索单个数字轮廓
box = self.src_gray[y - 5:y + h + 5, x - 5:x + w + 5]
box_thresh = cv2.threshold(box, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
contours = cv2.findContours(box_thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(box_thresh, contours, -1, (127, 255,), 3)
num_boxes = get_contours_rets(contours)
numbers = []
for num_box in num_boxes:
roi = number_normalize(box_thresh, num_box, 1)
scores = get_scores(self.labels, roi)
# 返回最大值的索引, 因为模板是0-9所以索引就是目标值, 否则还需要进一步获取原始数据值
index = np.argmax(scores)
numbers.append(index)
card.append(index)
# 在图中标记数字
cv2.putText(src_img, "".join([str(v) for v in numbers]), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 2)
print(f"识别的银行卡号 => {card}")
def parse_template(self):
# 灰度图片
ot_gray = cv2.cvtColor(self.ot_img, cv2.COLOR_BGR2GRAY)
# 模板灰度图片二值化
ot_bit = cv2.threshold(ot_gray, 10, 255, cv2.THRESH_BINARY_INV)[1]
# 根据二值图找轮廓
contours = cv2.findContours(ot_bit, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
labels = get_contours_rets(contours)
print(f"模板轮廓 {labels}")
# 绘制轮廓
# ot_bit_rect = ot_bit.copy()
# cv2.drawContours(ot_bit_rect, contours, -1, (127, 255,), 3)
# cv2.imshow('ot_img', ot_img)
# cv2.imshow('template', np.vstack([ot_gray, ot_bit, ot_bit_rect]))
self.labels = [number_normalize(ot_bit, r) for r in labels]
def parse_src(self):
src_card = self.src_img.copy()
# 将 [0:0.5h] 和 [0.66h,1h] 范围的像素设置为0
src_card[0:src_card.shape[0] // 2] = 0
src_card[2 * src_card.shape[0] // 3:] = 0
print(f"截取高度范围 ({src_card.shape[0] // 2}:{2 * src_card.shape[0] // 3})")
# 转换为灰度图片
self.src_gray = cv2.cvtColor(src_card, cv2.COLOR_BGR2GRAY)
# sobel化 (索贝尔算子主要用作边缘检测), ksize=-1相当于用3*3的
src_sobel = cv2.Sobel(self.src_gray, ddepth=cv2.CV_64F, dx=1, dy=0, ksize=-1)
# 对每个元素求绝对值
src_sobel = np.absolute(src_sobel)
(minVal, maxVal) = (np.min(src_sobel), np.max(src_sobel))
# 全局按照 255的区间重新格式化
src_sobel = (255 * ((src_sobel - minVal) / (maxVal - minVal)))
# 重新转换为整形
src_sobel = np.uint8(src_sobel)
# 创建内核矩阵
# 利用 morphologyEx 形态学变化函数进行滤波操作 (cv2.MORPH_CLOSE 闭运算,先膨胀后腐蚀)
# 利用 threshold 固定阈值操作, 去除噪声, 过滤掉像素值很小或很大的图像点。(THRESH_BINARY|THRESH_OTSU:使用最大类间差分法(THRESH_OTSU)获取阈值,然后再用该阈值进行二分。)
# 再次利用 morphologyEx 形态学变化函数进行滤波操作
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20, 3))
src_close = cv2.morphologyEx(src_sobel, cv2.MORPH_CLOSE, kernel)
src_thresh = cv2.threshold(src_close, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
src_close = cv2.morphologyEx(src_thresh, cv2.MORPH_CLOSE, kernel)
# 在处理好的图片上寻找轮廓 并 绘制
contours = cv2.findContours(src_close.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
src_card_1 = src_card.copy()
cv2.drawContours(src_card_1, contours, -1, (0, 0, 255), 3)
# 记录抓取的轮库
rects = []
for cnt in contours:
if cv2.contourArea(cnt) > 1000: # 防止抓取的区域过小
L = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * L, True)
x, y, w, h = cv2.boundingRect(approx)
rects.append([x, y, w, h])
rects.sort(key=lambda v: v[0])
print(f"图片轮廓 {rects}")
# cv2.imshow('src_card', np.vstack([src_img, src_card, src_card_1]))
# cv2.imshow('src_gray', np.vstack([self.src_gray, src_sobel]))
# cv2.imshow('src_thresh', np.vstack([src_thresh, src_close]))
self.rects = rects
if __name__ == '__main__':
ot_img = cv2.imread('ocr_a_reference.png')
src_img = cv2.imread('bank.png')
ocr = Ocr(ot_img, src_img)
ocr.parse()
cv2.imshow('ocr', np.vstack([ot_img]))
cv2.imshow('out', np.vstack([src_img]))
cv2.waitKey(0)
cv2.destroyAllWindows()
