Python Opencv实践 - 车牌定位(纯练手,存在失败场景,可以继续优化)

        使用传统的计算机视觉方法定位图像中的车牌,参考了部分网上的文章,实际定位效果对于我目前使用的网上的图片来说还可以。实测发现对于车身本身是蓝色、或是车牌本身上方有明显边缘的情况这类图片定位效果较差。纯练手项目,仅供参考。代码中imagePreProcess对某些图片定位率相比于imagePreProcess2做预处理的效果要好。后续可以尝试做一个如果imagePreProcess2识别无效后使用imagePreProcess再处理,或者加上阈值自适应打分的机制优化。目前对于我做的练手项目来说足够了。

        注意:以下代码是参考了网上的一些文章后,按照自己的思路写的,定位效果尚可。参考的文章有:python-opencv实战:车牌识别(一):精度还不错的车牌定位_基于阈值分割的车牌定位识别-CSDN博客

 https://www.cnblogs.com/fyunaru/p/12083856.html

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

#过滤矩形的参数
minRectW = 100
minRectH = 50
#判断车牌颜色的参数
#一般情况下,蓝色车牌H分量的值通常都在115附近徘徊
# S分量和V分量因光照不同而差异较大(opencv中H分量的取值范围是0到179,而不是图像学中的0到360;S分量和V分量的取值范围是到255)
deltaH = 15
hsvLower = np.array([115 - deltaH,60,60])
hsvUpper = np.array([115 + deltaH,255,255])

#灰度拉伸
def grayScaleStretch(img):
    maxGray = float(img.max())
    minGray = float(img.min())
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            img[i,j] = 255 / (maxGray - minGray) * (img[i,j] - minGray)
    return img

#图像二值化
def image2Binary(img):
    #选取灰度最大最小值的中间值
    maxGray = float(img.max())
    minGray = float(img.min())
    threshold = (minGray + maxGray) / 2
    ret,bin = cv.threshold(img, threshold, 255, cv.THRESH_BINARY)
    return bin

#图像预处理
def imagePreProcess(img):
    #转换为灰度图
    imgGray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    #灰度拉伸
    imgGray = grayScaleStretch(imgGray)
    #plt.imshow(imgGray, cmap='gray')
    kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (3,3))
    #做开运算
    imgOpen = cv.morphologyEx(imgGray, cv.MORPH_OPEN, kernel)
    #plt.imshow(imgOpen, cmap='gray')
    #获得差分图
    imgDiff = cv.absdiff(imgGray, imgOpen)
    #plt.imshow(imgDiff, cmap='gray')
    imgDiff = cv.GaussianBlur(imgDiff, (3,3), 5)
    #plt.imshow(imgDiff, cmap='gray')
    #图像二值化
    imgBinary = image2Binary(imgDiff)
    #plt.imshow(imgBinary, cmap='gray')
    cannyEdges = cv.Canny(imgBinary, 127, 200)
    #plt.imshow(cannyEdges, cmap='gray')
    #对Canny检测边缘结果做处理
    kernel = np.ones((3,3), np.uint8)
    imgOut = cv.morphologyEx(cannyEdges, cv.MORPH_CLOSE, kernel)
    imgOut = cv.dilate(imgOut, kernel, iterations=1)
    imgOut = cv.morphologyEx(imgOut, cv.MORPH_OPEN, kernel)
    #imgOut = cv.erode(imgOut, kernel, iterations=1)
    imgOut = cv.morphologyEx(imgOut, cv.MORPH_CLOSE, kernel)
    #plt.imshow(imgOut, cmap='gray')
    return imgOut

#图像预处理2 - 对于某些
def imagePreProcess2(img):
    imgGray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
    #灰度拉伸
    imgGray = grayScaleStretch(imgGray)
    imgGray = cv.GaussianBlur(imgGray, (3,3), 5)
    #进行边缘检测
    cannyEdges = cv.Canny(imgGray, 180, 230)
    #二值化
    imgBinary = image2Binary(cannyEdges)
    #plt.imshow(imgBinary, cmap='gray')
    #先做闭运算再做开运算
    kernel = np.ones((3,3), np.uint8)
    imgOut = cv.morphologyEx(imgBinary, cv.MORPH_CLOSE, kernel)
    imgOut = cv.morphologyEx(imgOut, cv.MORPH_OPEN, kernel)
    imgOut = cv.absdiff(imgBinary, imgOut)
    imgOut = cv.morphologyEx(imgOut, cv.MORPH_CLOSE, kernel)
    imgOut = cv.dilate(imgOut, kernel, iterations=1)
    plt.imshow(imgOut, cmap='gray')
    return imgOut

#debug
def printHSV(hsvSrc):
    for i in range(hsvSrc.shape[0]):
        for j in range(hsvSrc.shape[1]):
            (h,s,v) = hsvSrc[i][j]
            print(h,s,v)

#定位车牌
def locate_plate(imgProcessing, imgOriginal):
    contours,hierarchy = cv.findContours(imgProcessing, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    carPlateCandidates = []
    for contour in contours:
        (x,y,w,h) = cv.boundingRect(contour)
        #过滤掉一些小的矩形
        if (w < minRectW or h < minRectH):
            continue
        #cv.rectangle(imgOriginal, (int(x), int(y)), (int(x + w),int(y + h)), (0,255,0), 2)
        carPlateCandidates.append([int(x),int(y),int(x + w),int(y + h)])
    
    #plt.imshow(imgOriginal[:,:,::-1])
    maxMean = 0
    target = []
    target_mask = []
    #依次检查候选车牌列表,用HSV颜色空间判别是否是车牌
    for candidate in carPlateCandidates:
        (x0,y0,x1,y1) = candidate
        candidateROI = imgOriginal[y0:y1,x0:x1]
        hsvROI = cv.cvtColor(candidateROI, cv.COLOR_BGR2HSV)
        mask = cv.inRange(hsvROI, hsvLower, hsvUpper)
        #print(mask)
        #plt.imshow(mask, cmap='gray')
        #使用均值找出蓝色最多的区域
        mean = cv.mean(mask)
        #print(mean)
        if mean[0] > maxMean:
            maxMean = mean[0]
            target = candidate
            target_mask = mask
    #对target的范围进行缩小,找出蓝色刚开始和结束的坐标
    print(target_mask)
    nonZeroPoints = cv.findNonZero(target_mask)
    #print(nonZeroPoints)
    sortByX = np.sort(nonZeroPoints, axis=0)
    xMin = sortByX[0][0][0]
    xMax = sortByX[-1][0][0]
    print(sortByX)
    sortByY = np.sort(nonZeroPoints, axis=1)
    yMin = sortByY[0][0][1]
    yMax = sortByY[-1][0][1]
    print(sortByY)


    print("X min:" + str(xMin) + " X max:" + str(xMax) + " Y min:" + str(yMin) + " Y max:" + str(yMax))
    (x0,y0,x1,y1) = target
    print("Original:" + str(x0) + "," + str(y0) + "," + str(x1) + "," + str(y1))
    #target = (x0 + xMin, y0 + yMin, x0 + (xMax - xMin), y0 + yMax - yMin)
    target = [x0 + xMin, y0 + yMin, x0 + xMax, y0 + yMax]
    return target

#读取图像
imgCarPlate = cv.imread("../../SampleImages/carplate/carplate_chongqing.jpg", cv.IMREAD_COLOR)
#plt.imshow(imgCarPlate[:,:,::-1])
img4locate = imagePreProcess2(imgCarPlate)
target = locate_plate(img4locate, imgCarPlate)
(x0,y0,x1,y1) = target
cv.rectangle(imgCarPlate, (x0,y0), (x1,y1), (0,255,0), 2)
plt.imshow(imgCarPlate[:,:,::-1])

成功的例子: 

 

 

 

 

 

不太成功的例子(轮廓检测的不太好,并且轮廓中蓝色的值过早出现,可以优化判断为连续的蓝色而不是零散的蓝色)

失败的例子(没能检测出小轮廓,车身本身为蓝色,替换为imagePreProcess后能够成功):

         

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

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

相关文章

学之思开源考试系统部署至Centos7

学之思开源考试系统部署至Centos7 1、下载源码 源码下载&#xff1a; https://gitee.com/mindskip/xzs-mysql 数据库脚本下载&#xff1a; https://www.mindskip.net:999/ 2、项目打包 分别在\source\vue\xzs-student目录和source\vue\xzs-admin目录&#xff0c;执行前端打…

【遮天】叶凡首次高燃时刻,暴打姜峰逼其下跪,故事逐渐燃情

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析国漫资讯。 深度爆料&#xff0c;《遮天》国漫30集剧情最新内容解析&#xff0c;前面剧情中&#xff0c;叶凡被姜峰如疯狗一般追杀&#xff0c;他像一只被狼群追逐的鹿&#xff0c;在山林中亡命逃窜。身后是姜峰那歇斯底…

KaiOS APN配置文件apn.json调试验证方法(无需项目全编)

1、KaiOS 的应用就类似web应用&#xff0c;结合文件夹路径webapp字面意思理解。 2、KaiOS APN配置文件源代码在apn.json&#xff0c; &#xff08;1&#xff09;apn.json可以自定义路径&#xff0c;通过配置脚本实现拷贝APN在编译时动态选择路径在机器中生效。 &#xff08;…

Ubuntu22.04安装MySql

在Ubuntu上安装mysql就比较简单了 1、常规操作&#xff0c;更新软件包列表 apt update 至少安装之前看一眼版本吧 apt list mysql-server 嗯&#xff0c;是8.0.35版本的 2、安装mysql apt install mysql-server 3、给root用户设置密码 # 第一次安装完无需密码,让你输入…

【C语言】嵌套结构体初始化 - 一个有趣的结论

0. 前言 A. 嵌套结构体&#xff08;比如双链表&#xff09;的初始化一般是什么流程&#xff1f; B. 嵌套结构体的内存是如何分布的&#xff1f; C. 结构体中的结构体指针是否需要再次分配内存&#xff1f;不分配会怎么样&#xff1f; 关于嵌套结构体的初始化问题&#xff0c;我…

华为H12-831题库

单选&#xff09;当IS-IS网络中有多条冗余链路时&#xff0c;可能会出现多条等价路由。关于IS-IS网络内的等价路由&#xff0c;以下哪个描述是错误的? A、当组网中存在的等价路由数量大于通过命令配置的数量&#xff0c;且这些路由优先级相同时&#xff0c;优选下一跳设备Sys…

基于springboot 停车场管理系统-计算机毕设 附源码 39315

spring boot停车场管理系统的设计与实现 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。…

外包干了2个月,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

Linux - 进程程序替换 - C/C++ 如何实现与各个语言之间的相互调用 - 替换环境变量

前言 我们之前利用 fork&#xff08;&#xff09;函数来创建子进程&#xff0c;这种方式是 父子进程 共用一个代码&#xff0c;只是在代码当中使用了 if-else 语句来分流&#xff0c;达到父子进程运行不同的代码块的目的。但是其实本质上&#xff0c;还是父子共用一个代码和数…

前端-第一部分-HTML

一.初识HTML 1.1 HTML 简介 HTML 全称为 HyperText Mark-up Language&#xff0c;翻译为超文本标签语言&#xff0c;标签也称作标记或者元素。HTML 是目前网络上应用最为广泛的技术之一&#xff0c;也是构成网页文档的主要基石之一。HTML文本是由 HTML 标签组成的描述性文本&a…

spring 中 @Validated/@Valid

超级好的链接 添加链接描述

Linux 下最主流的文件系统格式——ext

硬盘分成相同大小的单元&#xff0c;我们称为块&#xff08;Block&#xff09;。一块的大小是扇区大小的整数倍&#xff0c;默认是 4K。在格式化的时候&#xff0c;这个值是可以设定的。 一大块硬盘被分成了一个个小的块&#xff0c;用来存放文件的数据部分。这样一来&#xf…

01-PostgreSQL安装与远程连接

一、windows安装PostgreSQL ①&#xff1a;下载 1. 官网下载 地址&#xff1a;https://www.postgresql.org/download/ 选择对应系统 点击下载 选择下载的版本&#xff08;我这里下载14.X版本&#xff09; 下载完成 2. 网盘下载 链接&#xff1a;https://pan.baidu.com/s/1u3Z…

深入解析 Redis 分布式锁原理

一、实现原理 1.1 基本原理 JDK 原生的锁可以让不同线程之间以互斥的方式来访问共享资源&#xff0c;但如果想要在不同进程之间以互斥的方式来访问共享资源&#xff0c;JDK 原生的锁就无能为力了。此时可以使用 Redis 来实现分布式锁。 Redis 实现分布式锁的核心命令如下&am…

阿里云e实例服务器3M固定带宽40G ESSD entry系统盘99元/年

阿里云99元服务器新老用户均可以买&#xff0c;你没看错&#xff0c;老用户可以买&#xff0c;活动页面 aliyunfuwuqi.com/go/aliyun 配置为云服务器ECS经济型e实例、2核2G、3M固定带宽、40G ESSD Entry云盘&#xff0c;并且续费不涨价&#xff0c;原价99元即可续费&#xff0c…

如何用sklearn对随机森林调参

文章目录 一、概述二、实操1、导入相关包2、导入乳腺癌数据集&#xff0c;建立模型3、调参 三、总结 Link&#xff1a;https://zhuanlan.zhihu.com/p/126288078 Author&#xff1a;陈罐头 一、概述 sklearn是目前python中十分流行的用来实现机器学习的第三方包&#xff0c;其中…

【ChatGPT】人工智能的下一个前沿

&#x1f38a;专栏【ChatGPT】 &#x1f33a;每日一句&#xff1a;慢慢变好,我是,你也是 ⭐欢迎并且感谢大家指出我的问题 文章目录 一、引言 二、ChatGPT的工作原理 三、ChatGPT的主要特点 四、ChatGPT的应用场景 五、结论与展望 ​​​​​​​ 一、引言 随着人工智能技…

【QEMU-tap-windows-Xshell】QEMU 创建 aarch64虚拟机(附有QEMU免费资源)

“从零开始&#xff1a;在Windows上创建aarch64&#xff08;ARM64&#xff09;虚拟机” 前言 aarch64&#xff08;ARM64&#xff09;架构是一种现代的、基于 ARM 技术的计算架构&#xff0c;具有诸多优点&#xff0c;如低功耗、高性能和广泛应用等。为了在 Windows 平台上体验…

界面控件DevExpress WPF PDF Viewer,更快实现应用的PDF文档浏览

DevExpress WPF PDF Viewer控件可以轻松地直接在Windows应用程序中显示PDF文档&#xff0c;而无需在最终用户的机器上安装外部PDF查看器。 P.S&#xff1a;DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress…

1995-2020年全国各省二氧化碳排放量面板数据

1995-2020年全国各省二氧化碳排放面板数据 1、时间&#xff1a;1995-2020 2、范围&#xff1a;全国、30省 3、来源&#xff1a;中国能源统计NJ 4、指标&#xff1a; 统计年度、地区代码、地区名称、煤炭二氧化碳排放量、焦炭二氧化碳排放量、原油二氧化碳排放量、汽油二氧…