东方耀AI技术分享

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 3212|回复: 2
打印 上一主题 下一主题

[课堂笔记] 车牌照图片识别预处理(核心技巧)

[复制链接]

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14429
QQ
跳转到指定楼层
楼主
发表于 2019-1-23 17:12:48 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式


车牌照图片识别预处理(核心技巧):
1、图像重置大小 变成正方形 并转换为单通道的黑白图片
2、通过卷积操作 对轮廓信息提取
3、二值化操作 让轮廓信息像素变成纯白 其他位置纯黑
4、最大池化操作(多次) 让白色区域扩大或膨胀(将这些白色区域的周边也变成白色的,连成一片)
5、将有一些膨胀不太好的地方,还原成黑色 乘以-1之后的最大池化
6、继续最大池化操作(多次) 继续膨胀



  1. # -- encoding:utf-8 --
  2. """
  3. 车牌照图片识别预处理(核心技巧):
  4. 1、图像重置大小 变成正方形 并转换为单通道的黑白图片
  5. 2、通过卷积操作 对轮廓信息提取
  6. 3、二值化操作 让轮廓信息像素变成纯白 其他位置纯黑
  7. 4、最大池化操作(多次) 让白色区域扩大或膨胀(将这些白色区域的周边也变成白色的,连成一片)
  8. 5、将有一些膨胀不太好的地方,还原成黑色 乘以-1之后的最大池化
  9. 6、继续最大池化操作(多次) 继续膨胀
  10. """

  11. import matplotlib.pyplot as plt
  12. import tensorflow as tf


  13. def show_image_tensor(image_tensor):
  14.     # 要求:使用交互式会话
  15.     # 获取图像tensor对象对应的image对象,image对象时一个[h,w,c]
  16.     # print(image_tensor)
  17.     image = image_tensor.eval()
  18.     # print(image)
  19.     print("图像大小为:{}".format(image.shape))
  20.     if len(image.shape) == 3 and image.shape[2] == 1:
  21.         # 黑白图像
  22.         plt.imshow(image[:, :, 0], cmap='Greys_r')
  23.         plt.show()
  24.     elif len(image.shape) == 3:
  25.         # 彩色图像
  26.         plt.imshow(image)
  27.         plt.show()


  28. sess = tf.InteractiveSession()
  29. path = '0.jpg'

  30. # 读取图像数据并转换为[height, width, channels]的格式
  31. img = tf.image.decode_jpeg(tf.read_file(path), channels=3)
  32. # # 图像重置大小
  33. img = tf.image.resize_images(img, size=(300, 300), method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
  34. # # 将图像转换为黑白的图像
  35. img = tf.image.rgb_to_grayscale(img)
  36. # old_img = img

  37. # 边缘/轮廓信息提取(卷积操作)
  38. img = tf.cast(img, dtype=tf.float32)
  39. # (300, 300, 1) --->变成 (1, 300, 300, 1) [NHWC]
  40. img = tf.expand_dims(img, 0)

  41. for i in range(1):
  42.     sobel_gx = [-1, 0, +1, 0, 0, 0, -1, 0, +1]
  43.     # [filter_height, filter_width, in_channels, out_channels]
  44.     filter = tf.constant(value=sobel_gx, dtype=tf.float32, shape=[3, 3, 1, 1])

  45.     img = tf.nn.conv2d(img, filter=filter, strides=[1, 1, 1, 1], padding='SAME', data_format='NHWC')

  46. img = img[0]

  47. #
  48. # 二值化,小于等于170的设置为0,大于170设置为255
  49. # condition? True : False
  50. img = tf.where(tf.less_equal(img, 170), tf.zeros_like(img), tf.ones_like(img) * 255)
  51. #
  52. # 将白色的区域(车牌区域就是白色的),扩大/膨胀 ==> 将这些白色区域的周边也变成白色的 ==> 只需要做一个maxpool
  53. # 变成 (1, 300, 300, 1) [NHWC]
  54. img = tf.expand_dims(img, 0)
  55. # 膨胀
  56. for i in range(2):
  57.     # 池化核大小: 2*3
  58.     img = tf.nn.max_pool(img, ksize=(1, 2, 3, 1), strides=(1, 1, 1, 1), padding='SAME', data_format="NHWC")

  59. # # 将有一些膨胀不太好的地方,还原成黑色
  60. img = tf.nn.max_pool(img * -1, ksize=(1, 3, 1, 1), strides=(1, 1, 1, 1), padding='SAME', data_format="NHWC")
  61. img = img * -1
  62. #
  63. # # 继续膨胀一次
  64. for i in range(5):
  65.     img = tf.nn.max_pool(img, ksize=(1, 1, 5, 1), strides=(1, 1, 1, 1), padding='SAME', data_format="NHWC")

  66. # 维度还原:(300, 300, 1)
  67. img = img[0]

  68. print(img)
  69. print(img.get_shape())
  70. show_image_tensor(img)
复制代码

  1. # -- encoding:utf-8 --
  2. """
  3. 提取车牌号(使用OpenCV的方式)
  4. OpenCV 图像处理 封装得非常好

  5. 下载opencv:https://www.lfd.uci.edu/~gohlke/pythonlibs/
  6. 通过whl文件安装 比较好
  7. opencv_python-4.0.1-cp36-cp36m-win_amd64.whl

  8. pip install wheel
  9. pip install xxx.whl

  10. opencv-python      4.0.1

  11. """

  12. import cv2
  13. import numpy as np


  14. def preprocess(gray):
  15.     """
  16.     对灰度对象进行形态转换(预处理)
  17.     :param gray:
  18.     :return:
  19.     """
  20.     # 高斯平滑
  21.     gaussian = cv2.GaussianBlur(gray, (3, 3), 0, 0, cv2.BORDER_DEFAULT)

  22.     # 中值滤波
  23.     median = cv2.medianBlur(gaussian, 5)

  24.     # Sobel算子,对边缘进行处理(获取边缘信息,其实就是卷积过程 3*3)
  25.     # x:[-1, 0, +1, -2, 0, +2, -1, 0, +1]
  26.     # y:[-1, -2, -1, 0, 0, 0, +1, +2, +1]
  27.     sobel = cv2.Sobel(median, cv2.CV_8U, 1, 0, ksize=3)

  28.     # 二值化 170作为分界值 0或255
  29.     ret, binary = cv2.threshold(sobel, 170, 255, cv2.THRESH_BINARY)

  30.     # 膨胀&腐蚀
  31.     element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 1))
  32.     element2 = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 7))
  33.     # 膨胀一次,让轮廓突出
  34.     dilation = cv2.dilate(binary, element2, iterations=1)
  35.     # 腐蚀一次,去掉细节
  36.     erosion = cv2.erode(dilation, element1, iterations=1)
  37.     # 再次膨胀,让轮廓明显一些
  38.     dilation2 = cv2.dilate(erosion, element2, iterations=3)

  39.     # cv2.imshow('dfy', dilation2)
  40.     # cv2.waitKey(0)

  41.     return dilation2


  42. def find_plate_number_region(img):
  43.     """
  44.     寻找可能是车牌区域的轮廓
  45.     :param img:
  46.     :return:
  47.     """
  48.     # 查找轮廓(img: 原始图像,contours:矩形坐标点,hierarchy:图像层次)
  49.     #  contours, hierarchy
  50.     # img, contours, hierarchy = cv2.findContours(img, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)
  51.     contours, hierarchy = cv2.findContours(img, mode=cv2.RETR_TREE, method=cv2.CHAIN_APPROX_SIMPLE)

  52.     # 查找矩形
  53.     max_ratio = -1
  54.     max_box = None
  55.     ratios = []
  56.     number = 0
  57.     for i in range(len(contours)):
  58.         cnt = contours[i]

  59.         # 计算轮廓面积
  60.         area = cv2.contourArea(cnt)
  61.         # 面积太小的过滤掉 1000是阈值 自己给定
  62.         if area < 1000:
  63.             continue

  64.         # 找到最小的矩形
  65.         rect = cv2.minAreaRect(cnt)

  66.         # 矩形的四个坐标(顺序不定,但是一定是一个左下角、左上角、右上角、右下角这种循环顺序(开始是哪个点未知))
  67.         box = cv2.boxPoints(rect)
  68.         # 转换为long类型
  69.         box = np.int0(box)

  70.         # 计算长宽高
  71.         height = abs(box[0][1] - box[2][1])
  72.         weight = abs(box[0][0] - box[2][0])
  73.         ratio = float(weight) / float(height)
  74.         # 正常的车牌宽高比在2.7~5之间
  75.         if ratio > max_ratio:
  76.             max_box = box

  77.         if ratio > 5.5 or ratio < 2:
  78.             continue

  79.         # 将结果添加到序列中
  80.         number += 1
  81.         ratios.append((box, ratio))

  82.     # 根据找到的图像矩阵数量进行数据输出
  83.     if number == 1:
  84.         # 直接返回
  85.         return ratios[0][0]
  86.     elif number > 1:
  87.         # 有多个满足条件的
  88.         # 如果存在多个,这里不做太多考虑,直接返回一个最可能的(也就是ratio在2.7~5之间的中间数字的那个图像)
  89.         # TODO: 实际上可以在这里训练一个模型,用于判断图片中是否有车牌照(就一个简单的神经网络即可)
  90.         filter_ratios = list(filter(lambda t: t[1] >= 2.7 and t[1] <= 5, ratios))
  91.         size_filter_ratios = len(filter_ratios)
  92.         if size_filter_ratios == 1:
  93.             return filter_ratios[0][1]
  94.         elif size_filter_ratios > 1:
  95.             r = [filter_ratios[i][1] for i in range(size_filter_ratios)]
  96.             sort_r = np.argsort(r)
  97.             return filter_ratios[int(len(sort_r) / 2)][0]
  98.         else:
  99.             # 直接返回最大值
  100.             max_index = np.argmax(ratios, 0)
  101.             return ratios[max_index[1]][1]
  102.     else:
  103.         # 直接返回最大值
  104.         return max_box


  105. def cut(img_or_img_path):
  106.     """
  107.     截取车牌区域
  108.     :param img:
  109.     :return:
  110.     """
  111.     if isinstance(img_or_img_path, str):
  112.         img = cv2.imread(img_or_img_path)
  113.     else:
  114.         img = img_or_img_path

  115.     # 将图像转换为灰度图
  116.     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

  117.     # 图像预处理
  118.     dilation = preprocess(gray)

  119.     # 查找车牌区域(只会有一个)
  120.     box = find_plate_number_region(dilation)

  121.     # 返回区域对应的图像
  122.     # 因为不知道,点的顺序,所以对左边点坐标排序
  123.     ys = [box[0, 1], box[1, 1], box[2, 1], box[3, 1]]
  124.     xs = [box[0, 0], box[1, 0], box[2, 0], box[3, 0]]
  125.     ys_sorted_index = np.argsort(ys)
  126.     xs_sorted_index = np.argsort(xs)

  127.     # 获取x上的坐标
  128.     x1 = box[xs_sorted_index[0], 0]
  129.     x2 = box[xs_sorted_index[3], 0]

  130.     # 获取y上的坐标
  131.     y1 = box[ys_sorted_index[0], 1]
  132.     y2 = box[ys_sorted_index[3], 1]

  133.     # 截取图像
  134.     img_plate = img[y1:y2, x1:x2]

  135.     return img_plate


  136. if __name__ == '__main__':
  137.     path = '0.jpg'
  138.     cut_img = cut(path)
  139.     print(cut_img.shape)
  140.     cv2.imwrite('test.jpg', cut_img)
  141.     cv2.imshow('wx:dfy_88888', cut_img)
  142.     cv2.waitKey(0)

复制代码


车牌照识别1.png (497.44 KB, 下载次数: 269)

车牌照识别1.png

车牌照识别2.png (125.64 KB, 下载次数: 270)

车牌照识别2.png

车牌照识别3.png (113.71 KB, 下载次数: 271)

车牌照识别3.png

车牌照识别4.png (10.39 KB, 下载次数: 269)

车牌照识别4.png

车牌照识别5.png (11.14 KB, 下载次数: 270)

车牌照识别5.png

车牌照识别6.png (11.66 KB, 下载次数: 268)

车牌照识别6.png

车牌照识别7.png (9.61 KB, 下载次数: 264)

车牌照识别7.png

test.jpg (19.71 KB, 下载次数: 271)

test.jpg
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

0

主题

96

帖子

198

积分

注册会员

Rank: 2

积分
198
沙发
发表于 2019-7-2 13:56:38 | 只看该作者
多谢分享
回复

使用道具 举报

0

主题

13

帖子

36

积分

新手上路

Rank: 1

积分
36
板凳
发表于 2021-4-2 17:03:34 | 只看该作者
学习了333
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|人工智能工程师的摇篮 ( 湘ICP备2020019608号-1 )

GMT+8, 2024-4-20 00:21 , Processed in 0.199540 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表