OpenCV——总结《车牌识别》

1.图片中的hsv

hsv提取蓝色部分

# hsv提取蓝色部分
def hsv_color_find(img):
    img_copy = img.copy()
    cv2.imshow('img_copy', img_copy)
    """
    提取图中的蓝色部分 hsv范围可以自行优化
    cv2.inRange()
    参数介绍:
    第一个参数:hsv指的是原图
    第二个参数:在图像中低于这个数值的全部变为0
    第二个参数:在图像中高于这个数值的全部变为0
    在之间的变为255
    图像中0-255。是变得越来越亮的
    """
    hsv = cv2.cvtColor(img_copy, cv2.COLOR_BGR2HSV)
    cv2.imshow('hsv',hsv)
    low_hsv = np.array([100, 80, 80])#这里的阈值是自己进行设置的
    high_hsv = np.array([124, 255, 255])
    # 设置HSV的阈值
    mask = cv2.inRange(hsv, lowerb=low_hsv, upperb=high_hsv)
    cv2.imshow('mask',mask)
    #show_pic('hsv_color_find', mask)#这里是得到黑白颜色的图片
    # 将掩膜与图像层逐像素相加
    #cv2.bitwise_and()是对二进制数据进行“与”操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制“与”操作,1&1=11&0=00&1=00&0=0
    res = cv2.bitwise_and(img_copy, img_copy, mask=mask)
    cv2.imshow('res',res)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    #show_pic('hsv_color_find2',res)#在这里得到蓝底黑字的照片
    print('hsv提取蓝色部分完毕')

    return res

请添加图片描述

2.对图片大小进行调整设置

但是在次张测试图片当中并未使用到这个代码,故不做过多的解释。

def resize_photo(imgArr,MAX_WIDTH = 1000):
    """
    这个函数的作用就是来调整图像的尺寸大小,当输入图像尺寸的宽度大于阈值(默认1000),我们会将图像按比例缩小
    输入: imgArr是输入的图像数字矩阵
    输出:  经过调整后的图像数字矩阵
    拓展:OpenCV自带的cv2.resize()函数可以实现放大与缩小,函数声明如下:
            cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) → dst
        其参数解释如下:
            src 输入图像矩阵
            dsize 二元元祖(宽,高),即输出图像的大小
            dst 输出图像矩阵
            fx 在水平方向上缩放比例,默认值为0
            fy 在垂直方向上缩放比例,默认值为0
            interpolation 插值法,如INTER_NEAREST,INTER_LINEAR,INTER_AREA,INTER_CUBIC,INTER_LANCZOS4等
    """
    img = imgArr
    rows, cols= img.shape[:2]     #获取输入图像的高和宽
    if cols >  MAX_WIDTH:
        change_rate = MAX_WIDTH / cols
        img = cv2.resize(img ,( MAX_WIDTH ,int(rows * change_rate) ), interpolation = cv2.INTER_AREA)
    return img

3.在此主要进行高级形态的转换

找到一些可能是车牌的一些距形区域,主要运用的是开运算和闭运算的来切换。

请添加图片描述

4.画出来轮廓

# 根据findContours返回的contours 画出轮廓
def draw_contours(img, contours):
    for c in contours:
        x, y, w, h = cv2.boundingRect(c)#这个函数就是用来返回值使用的。
        """
        传入一个轮廓图像,返回 x y 是左上角的点, w和h是矩形边框的宽度和高度
        """
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)#进行画图使用
        """
        画出矩形
            img 是要画出轮廓的原图
            (x, y) 是左上角点的坐标
            (x+w, y+h) 是右下角的坐标
            0,255,0)是画线对应的rgb颜色
            2 是画出线的宽度
        """

        # 获得最小的矩形轮廓 可能带旋转角度
        rect = cv2.minAreaRect(c)
        # 计算最小区域的坐标
        box = cv2.boxPoints(rect)
        # 坐标规范化为整数
        box = np.int0(box)
        # 画出轮廓
        cv2.drawContours(img, [box], 0, (0, 255, 0), 3)


    #show_pic('contours', img)
    cv2.imshow("contours", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

请添加图片描述

5.根据车牌的一些物理特征(面积等)对所得的矩形进行过滤

def chose_licence_plate(contours, Min_Area=2000):
    """
    这个函数根据车牌的一些物理特征(面积等)对所得的矩形进行过滤
    输入:contours是一个包含多个轮廓的列表,其中列表中的每一个元素是一个N*1*2的三维数组
    输出:返回经过过滤后的轮廓集合

    拓展:
    (1) OpenCV自带的cv2.contourArea()函数可以实现计算点集(轮廓)所围区域的面积,函数声明如下:
            contourArea(contour[, oriented]) -> retval
        其中参数解释如下:
            contour代表输入点集,此点集形式是一个n*2的二维ndarray或者n*1*2的三维ndarray
            retval 表示点集(轮廓)所围区域的面积
    (2) OpenCV自带的cv2.minAreaRect()函数可以计算出点集的最小外包旋转矩形,函数声明如下:
             minAreaRect(points) -> retval
        其中参数解释如下:
            points表示输入的点集,如果使用的是Opencv 2.X,则输入点集有两种形式:一是N*2的二维ndarray,其数据类型只能为 int32
                                    或者float32, 即每一行代表一个点;二是N*1*2的三维ndarray,其数据类型只能为int32或者float32
            retval是一个由三个元素组成的元组,依次代表旋转矩形的中心点坐标、尺寸和旋转角度(根据中心坐标、尺寸和旋转角度
                                    可以确定一个旋转矩形)
    (3) OpenCV自带的cv2.boxPoints()函数可以根据旋转矩形的中心的坐标、尺寸和旋转角度,计算出旋转矩形的四个顶点,函数声明如下:
             boxPoints(box[, points]) -> points
        其中参数解释如下:
            box是旋转矩形的三个属性值,通常用一个元组表示,如((3.05.0),(8.04.0),-60)
            points是返回的四个顶点,所返回的四个顶点是42列、数据类型为float32的ndarray,每一行代表一个顶点坐标
    """
    temp_contours = []
    for contour in contours:
        if cv2.contourArea(contour) > Min_Area:
            temp_contours.append(contour)
    car_plate1 = []
    car_plate2 = []
    car_plate3 = []
    for temp_contour in temp_contours:
        rect_tupple = cv2.minAreaRect(temp_contour)
        rect_width, rect_height = rect_tupple[1]
        if rect_width < rect_height:
            rect_width, rect_height = rect_height, rect_width
        aspect_ratio = rect_width / rect_height
        # 中国:蓝牌和黑牌是440×140,黄牌前牌尺寸同,后牌为440×220;摩托车及轻便摩托车前牌是220×95,后牌是220×140。
        # 车牌正常情况下宽高比在2 - 3.15之间 稍微放宽点范围
        if aspect_ratio > 1.5 and aspect_ratio < 4.65:
            car_plate1.append(temp_contour)
            rect_vertices = cv2.boxPoints(rect_tupple)
            rect_vertices = np.int0(rect_vertices)
            # print(temp_contour)
    print('一次筛查后,符合比例的矩形有' + str(len(car_plate1)) + '个')

    # 二次筛查 如果符合尺寸的矩形大于1,则缩小宽高比
    if len(car_plate1) > 1:
        for temp_contour in car_plate1:
            rect_tupple = cv2.minAreaRect(temp_contour)
            rect_width, rect_height = rect_tupple[1]
            if rect_width < rect_height:
                rect_width, rect_height = rect_height, rect_width
            aspect_ratio = rect_width / rect_height
            # 中国:蓝牌和黑牌是440×140,黄牌前牌尺寸同,后牌为440×220;摩托车及轻便摩托车前牌是220×95,后牌是220×140。
            # 车牌正常情况下宽高比在2 - 3.15之间 稍微放宽点范围
            if aspect_ratio > 1.6 and aspect_ratio < 4.15:
                car_plate2.append(temp_contour)
                rect_vertices = cv2.boxPoints(rect_tupple)
                rect_vertices = np.int0(rect_vertices)
    print('二次筛查后,符合比例的矩形还有' + str(len(car_plate2)) + '个')

    # 三次筛查 如果符合尺寸的矩形大于1,则缩小宽高比
    if len(car_plate2) > 1:
        for temp_contour in car_plate2:
            rect_tupple = cv2.minAreaRect(temp_contour)
            rect_width, rect_height = rect_tupple[1]
            if rect_width < rect_height:
                rect_width, rect_height = rect_height, rect_width
            aspect_ratio = rect_width / rect_height
            # 中国:蓝牌和黑牌是440×140,黄牌前牌尺寸同,后牌为440×220;摩托车及轻便摩托车前牌是220×95,后牌是220×140。
            # 车牌正常情况下宽高比在2 - 3.15之间 稍微放宽点范围
            if aspect_ratio > 1.8 and aspect_ratio < 3.35:
                car_plate3.append(temp_contour)
                rect_vertices = cv2.boxPoints(rect_tupple)
                rect_vertices = np.int0(rect_vertices)
    print('三次筛查后,符合比例的矩形还有' + str(len(car_plate3)) + '个')

    if len(car_plate3) > 0:
        return car_plate3
    if len(car_plate2) > 0:
        return car_plate2
    return car_plate1

# 根据得到的车牌定位,将车牌从原始图像中截取出来,并存在指定目录中。
def license_segment(car_plates, out_path):
    """
    此函数根据得到的车牌定位,将车牌从原始图像中截取出来,并存在指定目录中。
    输入: car_plates是经过初步筛选之后的车牌轮廓的点集
    输出:   out_path是车牌的存储路径
    """
    i = 0
    if len(car_plates) == 1:
        for car_plate in car_plates:
            row_min, col_min = np.min(car_plate[:, 0, :], axis=0)
            row_max, col_max = np.max(car_plate[:, 0, :], axis=0)
            cv2.rectangle(img, (row_min, col_min), (row_max, col_max), (0, 255, 0), 2)
            card_img = img[col_min:col_max, row_min:row_max, :]
            cv2.imwrite(out_path + "/card_img" + str(i) + ".jpg", card_img)
            #cv2.imshow("card_img" + str(i) + ".jpg", card_img)
            i += 1
            # cv2.waitKey(0)
            # cv2.destroyAllWindows()

    print('共切出' + str(i) + '张车牌图。')

    return out_path + "/card_img0.jpg"

6.此函数根据得到的车牌定位,将车牌从原始图像中截取出来,并存在指定目录中。

def license_segment(car_plates, out_path):
    """
    此函数根据得到的车牌定位,将车牌从原始图像中截取出来,并存在指定目录中。
    输入: car_plates是经过初步筛选之后的车牌轮廓的点集
    输出:   out_path是车牌的存储路径
    """
    i = 0
    if len(car_plates) == 1:
        for car_plate in car_plates:
            row_min, col_min = np.min(car_plate[:, 0, :], axis=0)
            row_max, col_max = np.max(car_plate[:, 0, :], axis=0)
            cv2.rectangle(img, (row_min, col_min), (row_max, col_max), (0, 255, 0), 2)#hauchu画出来外接矩形
            card_img = img[col_min:col_max, row_min:row_max, :]
            cv2.imwrite(out_path + "/card_img" + str(i) + ".jpg", card_img)

            i += 1
            #显示图片所用
            # cv2.imshow("card_img" + str(i) + ".jpg", card_img)
            # cv2.waitKey(0)
            # cv2.destroyAllWindows()

    print('共切出' + str(i) + '张车牌图。')

    return out_path + "/card_img0.jpg"

请添加图片描述

7.

请添加图片描述

参考链接:
https://blog.csdn.net/lukas_ten/article/details/115149086
https://blog.csdn.net/sunny2038/article/details/9137759
https://blog.csdn.net/wzh191920/article/details/79589506
https://blog.csdn.net/weixin_41695564/article/details/79712393
https://blog.csdn.net/Ikaros_521/article/details/121516173

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/39032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytest 结合logging输出日志保存至文件

API_log.py import loggingclass loger():def logering(self):# 创建logger对象logger logging.getLogger(test_logger)# 设置日志等级logger.setLevel(logging.DEBUG)# 追加写入文件a &#xff0c;设置utf-8编码防止中文写入乱码test_log logging.FileHandler(test.log, a,…

11、动手学深度学习——语言模型和数据集:代码详解

我们了解了如何将文本数据映射为词元&#xff0c;以及将这些词元可以视为一系列离散的观测&#xff0c;例如单词或字符。 假设长度为 T T T的文本序列中的词元依次为 x 1 , x 2 , … , x T x_1, x_2, \ldots, x_T x1​,x2​,…,xT​。于是&#xff0c; x t x_t xt​&#xff08…

初识C++(上)——“C++”

各位CSDN的uu们你们好呀&#xff0c;小雅兰的全新专栏又来啦&#xff0c;这次的专栏主要介绍的是C&#xff0c;下面&#xff0c;让我们进入C的世界吧&#xff01;&#xff01;&#xff01; 什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的…

【MySQL】根据MVCC和Read View分析事务的四种隔离级别在读写场景分别是如何体现其隔离性的

目录 一、数据库并发的三种场景 二、读写场景的MVCC 1、3个&#xff08;4个&#xff09;记录隐藏列字段 2、undo log&#xff08;撤销日志&#xff09; 3、模拟MVCC场景 3.1update场景 3.2delete场景 3.3insert 3.4select场景 4、Read View 5、RR和RC的区别 5.1当…

AI制图工具丨Midjourney产品功能介绍

了解如何使用Discord上的Midjourney Bot通过简单的文本提示创建自定义图像 Midjourney是一款AI制图工具&#xff0c;只要关键字&#xff0c;就能透过AI算法生成相对应的图片&#xff0c;只需要不到一分钟。 可以选择不同画家的艺术风格&#xff0c;例如安迪华荷、达芬奇、达利…

H3C-Cloud Lab实验-OSPF配置实验

一、实验拓扑图 实验需求&#xff1a; 1、按照图示配置 IP 地址 2、按照图示分区域配置 OSPF &#xff0c;实现全网互通 3、为了路由结构稳定&#xff0c;要求路由器使用环回口作为 Router-id&#xff0c;ABR 的环回口宣告进骨干区域 4、掌握OSPF初始化流程、路由表学习的过…

react和vue2/3父子组件的双向绑定

目录 Vue .sync&#xff08;2.3.0&#xff09; $emit &#xff08;2.3后&#xff09; 自定义组件的 v-model 2.2.0 v-modelemits(3.0取消了.sync) React 父组件回调函数 相关基础 框架 MVC &#xff08;Model View Controller&#xff09;/MVP&#xff08;Model View…

西安丨高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测技术应用

目录 ​第一章 预测平台讲解及安装 第二章 一体化预测工具详解与数据获取及制备 第三章 风资源预测自动化技术 第四章 太阳能资源自动化预测技术 第五章 水资源自动化预测技术 第六章 后处理自动化技术 更多推荐 能源是国民经济发展和人民生活必须的重要物质基础。在过去…

大数据存储架构详解:数据仓库、数据集市、数据湖、数据网格、湖仓一体

前言 本文隶属于专栏《大数据理论体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据理论体系 思维导图 数据仓库 数据仓库是一个面向主题的&…

Python自动化之pytest常用插件

目录 1、失败重跑 pytest-rerunfailures 2、多重校验 pytest-assume 3、设定执行顺序 pytest-ordering 4、用例依赖&#xff08;pytest-dependency&#xff09; 5.分布式测试(pytest-xdist) 6.生成报告&#xff08;pytest-html&#xff09; 1、失败重跑 pytest-rerunfailu…

华夏ERP在虚拟机Ubuntu上的安装(测试实例)

1.虚拟机软件VirtualBOX 7.0 2.Ubuntu 版本 3.宝塔面板安装 百度搜索宝塔面板&#xff0c;按官网提示进行安装。下面截图是官网示例。 if [ -f /usr/bin/curl ];then curl -sSO download.cnnbt.net/install_panel.sh;else wget -O install_panel.sh download.cnnbt.net/install…

EasyCVR告警类型设置后首页需要刷新才能更新的问题优化

EasyCVR视频融合平台基于云边端一体化架构&#xff0c;可支持多协议、多类型设备接入&#xff0c;包括&#xff1a;NVR、IPC、视频编码器、无人机、车载设备、智能手持终端、移动执法仪等。平台具有强大的数据接入、处理及分发能力&#xff0c;可在复杂的网络环境中&#xff0c…

【C++初阶】构造函数和析构函数

文章目录 一、类的六个默认成员函数二、构造函数三、析构函数 一、类的六个默认成员函数 &#x1f4d6;默认成员函数 用户没有显式实现&#xff0c;编译器会自动生成的成员函数&#xff0c;称为默认成员函数。 构造函数&#xff1a;完成对象的初始化工作。析构函数&#xff…

动态sql语句

1.1 动态sql语句概述 Mybatis 的映射文件中&#xff0c;业务逻辑复杂时&#xff0c; SQL是动态变化的&#xff0c;此时在前面的学习中 SQL 就不能满足要求了。 参考的官方文档&#xff1a; 1.2 动态 SQL 之<if> 根据实体类的不同取值&#xff0c;使用不同的 SQL语句…

园区能源控制管理系统

园区能源控制管理系统是一种能够实现对园区内能源消耗、供应和分配进行实时监控、管理和控制的系统。该系统通过对园区内各种能源设备的数据采集、处理和分析&#xff0c;为管理者提供实时的能源使用情况和数据分析&#xff0c;从而帮助管理者制定科学的能源管理策略和节能措施…

3Ds max图文教程:高精度篮球3D建模

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 第 1 步。使用以下设置在顶部视口上创建球体&#xff1a; 第 2 步。将球体转换为可编辑的多边形&#xff1a; 第 3 步。转到 Edge 子对象级别并剪切以下边缘&#xff1a; 第 4 步。选择以下边&#xff0c;然…

github 最简单的使用步骤(个人学习记录~)

github 使用步骤&#xff1a; (11条消息) github新手用法详解&#xff08;建议收藏&#xff01;&#xff01;&#xff01;&#xff09;_github详解_怪 咖的博客-CSDN博客 1.获取ssh密钥 打开输入&#xff1a;ssh-keygen -t rsa -C “git账号” 输入之后一路Enter&#xff08…

Kubernetes Service的过程

文章目录 Kubernetes Service的实现基础内容1. 命令 ip route show table all2. DNAT3. IPVS和iptables4. Service Service的实现简述 Kubernetes Service的实现 基础内容 在了解Service之前,需要先了解一些额外的知识: 命令: ip route show table allDNATIPVS和iptables基础…

【云原生】K8S单节点搭建

Kubernetes Kubernetes基础概念架构1、基础环境2、安装kubelet、kubeadm、kubectl 2、使用kubeadm引导集群1、下载各个机器需要的镜像2、初始化主节点 Kubernetes核心实战Pod Kubernetes基础概念 kubernetes具有以下特性&#xff1a; ● 服务发现和负载均衡 Kubernetes 可以使…

EasyCVR录像阈值配置未生效,是什么原因?

有用户反馈&#xff0c;在平台中设置了录像阈值不生效&#xff0c;导致磁盘爆满。针对该反馈&#xff0c;我们立即进行了排查。 EasyCVR基于云边端一体化架构&#xff0c;可支持多协议、多类型设备接入&#xff0c;在视频能力上&#xff0c;平台可实现视频直播、录像、回放、检…