opencv与c++实现车牌轮廓提取

opencv实现车牌提取

主要实现对整张图片中.将车牌分割出来.
需要进行

  1. 转换为灰度值
  2. 阈值分割,去除部分区域
  3. 连通域分析
  4. 分割出车牌所在轮廓
#include<opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int argc,char** argv)
{
    Mat image;
    image = imread("./demo10/02.jpeg",1);   //读取原图像
    imshow("原图像",image);
    Mat gray;
    cvtColor(image,gray,COLOR_BGR2GRAY);    //转换为灰度图
    
    threshold(gray,gray,151,0,THRESH_TOZERO);           //阈值分割,去除无关的内容,低于下限置0
    threshold(gray,gray,255,255,THRESH_TOZERO_INV);     //高于上限置0
    Mat element = getStructuringElement(MORPH_RECT,Size(3,3));      //形态学滤波 3*3的核
    morphologyEx(gray,gray,MORPH_CLOSE,element);                    //进行闭运算
    Mat stats,centroids;                            //连通域分析结果stats:对应各个轮廓的x,y,width,height和面积,centroids:中心点
    Mat labels = Mat::zeros(image.size(),CV_32S);   //表示当前像素是第几个轮廓
    int num_label = connectedComponentsWithStats(gray, labels, stats, centroids,8,4);   //连通域分析,num_label对于连通域个数

    for(int i=0;i<num_label;i++)        //筛选车牌所在连通域,去除其他区域
    {
        int area = stats.at<int>(i, CC_STAT_AREA);      //当前连通域区域的面积
        int width = stats.at<int>(i, CC_STAT_WIDTH);    //宽度
        int height = stats.at<int>(i,CC_STAT_HEIGHT);   //高度
        //筛选出车牌所在区域的以外的区域,均不赋予彩色显示,并将其连通域区域的中心点去除
        //面积,宽度,高度的数值,根据实际车牌的尺寸,加上相机内参数等数据可获得,应保证范围适中;
        //不知各参数的,可通过理由该图进行估计
        if((area <6000)|(area >10000)| (width <170)|(width >230) |(height <50) | (height>100))
        {
            centroids.at<Vec2d>(i, 0) =0;       //将车牌以外区域的中心点去除,即取消连通域标记
            continue;
        }
    }
    int w = image.cols;     //原图像像素的列数
    int h = image.rows;     //原图像像素的行数

    Mat ROI = Mat::ones(image.size(),image.type());     //车牌提取结果值定义为全黑
    for (int i = 1; i < num_label; i++) {
		Vec2d pt = centroids.at<Vec2d>(i, 0);           //各轮廓的中心点
		int x = stats.at<int>(i, CC_STAT_LEFT);         //各轮廓的左上角x坐标
		int y = stats.at<int>(i, CC_STAT_TOP);          //各轮廓的左上角y坐标
		int width = stats.at<int>(i, CC_STAT_WIDTH);    //各轮廓的宽度(x,y)点开始到右下角
		int height = stats.at<int>(i, CC_STAT_HEIGHT);  //各轮廓的高度(x,y)点开始到右下角
		int area = stats.at<int>(i, CC_STAT_AREA);      //各轮廓的面积(x,y)点开始到右下角
        if(pt[0] != 0)          //车牌轮廓的中心点非0
        {  
            cout<<pt<<endl;     //打印坐标值
            //将车牌区域像素提取到ROI(结果图像)中
            //如车牌图像倾斜,可利用椭圆拟合函数,获得图像角度再进行计算后分割
            for(int xx = x; xx < x+width; xx++)    
                for(int yy =y; yy < y+height; yy++)
                    ROI.at<Vec3b>(yy,xx) = image.at<Vec3b>(yy,xx);
        }
    }
    imshow("车牌提取结果",ROI); //显示结果
    waitKey(0);
    return 0;
}

在这里插入图片描述

  • 此为结果程序,具体调试我们需要获取:
  • 最佳的阈值范围
  • 车牌面积的最大范围
  • 车牌宽度,高度的最大范围
  • 可通过链接: opencv与c++ 阈值操作显示窗口.
    等操作来获取.但范围需尽量大,太过局限的范围并没有什么意义
车牌定位与分割是计算机视觉中的一个重要应用,可以应用于交通管理、车辆管理等领域。下面是一个基于C++OpenCV车牌定位与分割的代码实现。 1. 车牌定位 采用基于颜色的车牌定位方法,步骤如下: 1)将图像转换为HSV空间,提取出蓝色色调的区域; 2)对提取出的区域进行形态学操作(膨胀、腐蚀),消除噪声; 3)使用轮廓查找算法,找到符合车牌形状的轮廓; 4)利用矩形包围框框出车牌区域。 代码如下: ```c++ Mat image = imread("car.jpg"); Mat hsv; cvtColor(image, hsv, COLOR_BGR2HSV); Mat mask; inRange(hsv, Scalar(100, 43, 46), Scalar(124, 255, 255), mask); Mat kernel = getStructuringElement(MORPH_RECT, Size(19, 5)); morphologyEx(mask, mask, MORPH_CLOSE, kernel); vector<vector<Point>> contours; findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); vector<RotatedRect> rects; for (auto contour : contours) { RotatedRect rect = minAreaRect(contour); if (rect.size.width > image.cols / 2 && rect.size.height > 10) { float ratio = rect.size.width / rect.size.height; if (ratio > 2 && ratio < 5) { rects.push_back(rect); } } } for (auto rect : rects) { Point2f points[4]; rect.points(points); for (int i = 0; i < 4; i++) { line(image, points[i], points[(i + 1) % 4], Scalar(0, 0, 255), 2); } } imshow("result", image); waitKey(); ``` 2. 车牌分割 采用基于垂直投影的车牌分割方法,步骤如下: 1)将车牌区域图像转换为灰度图; 2)对图像进行二值化处理; 3)计算垂直投影直方图; 4)根据垂直投影直方图确定字符的位置,并进行分割。 代码如下: ```c++ Mat gray; cvtColor(image, gray, COLOR_BGR2GRAY); threshold(gray, gray, 0, 255, THRESH_BINARY | THRESH_OTSU); Mat hist = Mat::zeros(Size(gray.cols, 1), CV_32SC1); for (int j = 0; j < gray.cols; j++) { for (int i = 0; i < gray.rows; i++) { if (gray.at<uchar>(i, j) == 0) { hist.at<int>(j)++; } } } int left = 0, right = 0; bool flag = false; vector<Rect> chars; for (int j = 0; j < hist.cols; j++) { if (!flag && hist.at<int>(j) > 0) { flag = true; left = j; } else if (flag && hist.at<int>(j) == 0) { flag = false; right = j; if (right - left > 10) { chars.push_back(Rect(left, 0, right - left, gray.rows)); } } } for (auto rect : chars) { rectangle(image, rect, Scalar(0, 0, 255), 2); } imshow("result", image); waitKey(); ``` 以上就是车牌定位与分割的C++OpenCV实现代码。需要注意的是,对于不同的车牌颜色和形状,可能需要调整代码中的阈值和参数,才能得到较好的效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值