天天看点

Qt车牌识别

蓝牌,黄牌,绿牌都能准确识别,颜色识别的方法采用车牌数字识别后,再去截取车牌区域的颜色进行分类识别

Qt车牌识别
Qt车牌识别
Qt车牌识别

具体调用代码如下:

#pragma execution_character_set("utf-8")
#include "mainwindow.h"
#include "qdebug.h"
#include "qpushbutton.h"
#include "QFileDialog"
#include <QLoggingCategory>
#include "qlayout.h"
#include "qlabel.h"
#include "qfile.h"
void drawRect(cv::Mat image,cv::Rect rect)
{
    cv::Point p1(rect.x,rect.y);
    cv::Point p2(rect.x+rect.width,rect.y+rect.height);
    cv::rectangle(image,p1,p2,cv::Scalar(0,255,0),1);
}
void getMaxClass(cv::Mat &probBlob, int *classId, double *classProb)
{
    //    cv::Mat probMat = probBlob.matRefConst().reshape(1, 1); //reshape the blob to 1x1000 matrix
    cv::Point classNumber;

    cv::minMaxLoc(probBlob, NULL, classProb, NULL, &classNumber);

    *classId = classNumber.x;
}
/*
    -----------Levenshtein距离(度量车牌识别效果)------------
    编辑距离Edit Distance,又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数;
    Levenshtein距离算法可见
    @s1 : 字符串1;
    @s2 : 字符串2;
*/
template<class T>
static unsigned int levenshtein_distance(const T &s1, const T &s2){
    //获取s1、s2的字符长;
    const size_t len1 = s1.size(), len2 = s2.size();
    //声明col和prevCol辅助计算;
    //col记录的是最新的计数情况;
    //prevCol记录的是上一轮的计数情况;
    std::vector<unsigned int> col(len2 + 1), prevCol(len2 + 1);
    //迭代给prevCol赋值;
    for (unsigned int i = 0; i < prevCol.size(); i++) prevCol[i] = i;
    //迭代比较;扫描两字符串(n*m级的);
    for (unsigned int i = 0; i < len1; i++) {
        col[0] = i + 1;
        //迭代遍历s2[j] in s2;
        for (unsigned int j = 0; j < len2; j++)
            //比较是否不一样,交换代价最小方式优先;
            col[j + 1] = min(
                        min(prevCol[1 + j] + 1, col[j] + 1),
                    prevCol[j] + (s1[i] == s2[j] ? 0 : 1));
        //col与prevCol交换其内容(swap函数:prevCol的类型要与该vector一样,大小可以不同.);
        col.swap(prevCol);
    }
    //返回结果;
    return prevCol[len2];
}

QImage MatToQImage(const Mat& mat)
{
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        // qDebug() << "CV_8UC4";
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        //qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}

/*
    -----------测试函数:测试识别准确率------------

*/
void TEST_ACC(){
    //声明PipelinePR实例;
    pr::PipelinePR prc("model/cascade.xml",
                       "model/HorizonalFinemapping.prototxt","model/HorizonalFinemapping.caffemodel",
                       "model/Segmentation.prototxt","model/Segmentation.caffemodel",
                       "model/CharacterRecognization.prototxt","model/CharacterRecognization.caffemodel",
                       "model/SegmenationFree-Inception.prototxt","model/SegmenationFree-Inception.caffemodel"
                       );
    //申明文件流;
    ifstream file;
    //图片路径;
    string imagename;
    //声明计数变量;
    int n = 0,correct = 0,j = 0,sum = 0;
    //图片名文本文件路径;
    char filename[] = "1.txt";
    //图片文件根目录;
    string pathh = "/";
    //打开图片名文本文件;
    file.open(filename, ios::in);
    //读取图片名文本文件;
    while (!file.eof())
    {
        //读取一个图片名到imagename;
        file >> imagename;
        //该图片绝对路径;
        string imgpath = pathh + imagename;
        //输出信息;
        std::cout << "------------------------------------------------" << endl;
        cout << "图片名:" << imagename << endl;
        //读入图片;
        cv::Mat image = cv::imread(imgpath);
        //显示图片;
        //cv::imshow("image", image);
        //cv::waitKey(0);
        //申明一个存储该图片车牌信息检测结果的列表,读取结果;
        std::vector<pr::PlateInfo> res = prc.RunPiplineAsImage(image,pr::SEGMENTATION_FREE_METHOD);

        //置信度变量;
        float conf = 0;
        //置信度列表;
        vector<float> con ;
        //车牌名列表;
        vector<string> name;
        //遍历结果res;
        for (auto st : res) {
            //置信度大于0.1;
            if (st.confidence > 0.1) {
                //输出检测信息及置信度;
                //std::cout << st.getPlateName() << " " << st.confidence << std::endl;
                //加入置信度列表con;
                con.push_back(st.confidence);
                //加入车牌名列表name;
                name.push_back(st.getPlateName());
                //置信度综述累计;
                //conf += st.confidence;
            }
            //置信度小于0.1;
            else
                cout << "no string" << endl;
        }
        //输出置信度总数;
        //std::cout << conf << std::endl;
        //置信度列表大小;
        int num = con.size();
        //置信度最大值变量;
        float max = 0;
        //声明存储车牌字符、车牌前两个字符、车牌正确的前两个字符的变量;
        string platestr, chpr, ch;
        //声明度量车牌识别误差的变量;
        int diff = 0,dif = 0;
        //遍历置信度列表;
        for (int i = 0; i < num; i++) {
            //寻找最大的置信度下标;
            if (con.at(i) > max)
            {
                //最大置信度max;
                max = con.at(i);
                //platestr取"最可信"(最大置信度)的结果;
                platestr = name.at(i);
            }

        }
        //输出最大置信度;
        //cout << "max:"<<max << endl;
        //输出车牌字符;
        cout << "string:" << platestr << endl;
        //车牌前两个字符;
        chpr = platestr.substr(0, 2);
        //车牌正确的前两个字符的变量;
        ch = imagename.substr(0, 2);
        //度量距离;
        diff = levenshtein_distance(imagename, platestr);
        //dif值;
        dif = diff - 4;
        //输出;
        cout << "差距:" <<dif << endl;
        //累计;
        sum += dif;
        //错误计数;
        if (ch != chpr) n++;
        //正确计数;
        if (diff == 0) correct++;
        //总数计数;
        j++;
    }
    //计算汉字识别准确率;
    float cha = 1 - float(n) / float(j);
    //输出;
    std::cout << "------------------------------------------------" << endl;
    //输出车牌总数;
    cout << "车牌总数:" << j << endl;
    //输出汉字识别准确率;
    cout << "汉字识别准确率:"<<cha << endl;
    //计算字符识别准确率;
    float chaccuracy = 1 - float(sum - n * 2) /float(j * 8);
    //输出;
    cout << "字符识别准确率:" << chaccuracy << endl;
}

/*
    -----------测试函数:画框------------

*/
PlateInfo TEST_PIPELINE(QString filename){
    //声明PipelinePR实例;
    pr::PipelinePR prc("model/cascade.xml",
                       "model/HorizonalFinemapping.prototxt","model/HorizonalFinemapping.caffemodel",
                       "model/Segmentation.prototxt","model/Segmentation.caffemodel",
                       "model/CharacterRecognization.prototxt","model/CharacterRecognization.caffemodel",
                       "model/SegmenationFree-Inception.prototxt","model/SegmenationFree-Inception.caffemodel"
                       );
    //读取一张图片;
    PlateInfo retPi;
    double confidence=0;
    cv::Mat image = cv::imread(filename.toUtf8().data());
    //申明一个存储该图片车牌信息检测结果的列表,读取结果;
    std::vector<pr::PlateInfo> res = prc.RunPiplineAsImage(image,pr::SEGMENTATION_FREE_METHOD);
    //遍历结果;
    for(auto st:res) {
        //选择置信度大于0.75的结果;
        if(st.confidence>0.75) {
            //输出结果;
            qDebug()<<st.getColorType()<<QString::fromStdString(st.getPlateName()) << "," << st.confidence ;
            //矩形框位置;
            cv::Rect region = st.getPlateRect();

            //绘制框;
            cv::rectangle(image,cv::Point(region.x,region.y),cv::Point(region.x+region.width,region.y+region.height),cv::Scalar(255,255,0),2);
            if(st.confidence>confidence)
            {
                //cv::imwrite("carnum.jpg",st.getPlateImage());
                confidence=st.confidence;
                st.setSrcImage(image);
                retPi=st;
            }
        }
    }
    //显示结果;
    // cv::imshow("image",image);
    return  retPi ;
}



/*
    -----------测试函数:视频流------------

*/
void TEST_CAM()
{
    //获取视频;
    cv::VideoCapture capture("test1.mp4");
    //申明帧变量;
    cv::Mat frame;
    //声明PipelinePR实例;
    pr::PipelinePR prc("model/cascade.xml",
                       "model/HorizonalFinemapping.prototxt","model/HorizonalFinemapping.caffemodel",
                       "model/Segmentation.prototxt","model/Segmentation.caffemodel",
                       "model/CharacterRecognization.prototxt","model/CharacterRecognization.caffemodel",
                       "model/SegmenationFree-Inception.prototxt","model/SegmenationFree-Inception.caffemodel"
                       );
    //循环读取帧;
    while(1) {
        //读取下一帧
        //异常处理;
        if (!capture.read(frame)) {
            std::cout << "读取视频失败" << std::endl;
            exit(1);
        }
        //图像旋转;
        //cv::transpose(frame,frame);
        //图像翻转;
        //cv::flip(frame,frame,2);
        //大小调整;
        //cv::resize(frame,frame,cv::Size(frame.cols/2,frame.rows/2));
        //识别结果;
        std::vector<pr::PlateInfo> res = prc.RunPiplineAsImage(frame,pr::SEGMENTATION_FREE_METHOD);
        //遍历识别结果
        for(auto st:res) {
            if(st.confidence>0.75) {
                //输出结果;
                std::cout << st.getPlateName() << " " << st.confidence << std::endl;
                //矩形框位置;
                cv::Rect region = st.getPlateRect();
                //绘制框;
                cv::rectangle(frame,cv::Point(region.x,region.y),cv::Point(region.x+region.width,region.y+region.height),cv::Scalar(255,255,0),2);
            }
        }
        //显示;
        cv::imshow("image",frame);
        //等待;
        cv::waitKey(1);
    }
}

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
    setMinimumSize(960,600);
    QLoggingCategory::setFilterRules(QStringLiteral("qt.speech.tts=true \n qt.speech.tts.*=true"));

    QPushButton *btn=new QPushButton(this);
    btn->setText("打开图像");
    btn->setFixedSize(80,24);
    btn->move(100,100);
    btn->show();
    connect(btn,SIGNAL(clicked()),this,SLOT(slot_openFile()));
    m_carImage=new ImageWidget(this);
    m_carNumImage=new ImageWidget(this);
    m_carNumImage->setFixedSize(140,36);
    m_carNum=new QLineEdit(this);
    m_carNum->setFixedWidth(100);
    m_carType=new QLineEdit(this);
    m_carType->setFixedWidth(100);
    QVBoxLayout *vl=new QVBoxLayout();
    setLayout(vl);
    QHBoxLayout *hl=new QHBoxLayout();
    hl->addStretch();
    hl->addWidget(btn);
    QLabel *lab1=new QLabel("车牌号码:",this);
    QLabel *lab2=new QLabel("车牌类型:",this);
    hl->addWidget(lab1);
    hl->addWidget(m_carNum);
    hl->addWidget(lab2);
    hl->addWidget(m_carType);
    hl->addWidget(m_carNumImage);
    hl->addStretch();
    vl->addLayout(hl);
    vl->addWidget(m_carImage,Qt::AlignHCenter);
}
void MainWindow::slot_openFile()
{
    qDebug()<<"slot_openFile";
    QString filename=QFileDialog::getOpenFileName(this, QString("选择图片文件"),  "", QString("图片文件格式(*.jpg *.png *.jpeg *. bmp)"));
   qDebug()<<"filename == "<<filename;
    if(filename.length()>0)
    {
        m_carNum->setText("");
        m_carType->setText("");
        m_carImage->setImage(QImage());
        m_carNumImage->setImage(QImage());

        PlateInfo pi=  TEST_PIPELINE(filename);
         qDebug()<<"PlateInfo == ";
        if(pi.getPlateName().length()>0)
        {
            //输出结果;
            QString txt=QString::fromStdString(pi.getPlateName());
            m_carNum->setText(txt);
            m_carType->setText(pi.getColorType());
            m_carImage->setImage(MatToQImage(pi.getSrcImage()));
            m_carNumImage->setImage(MatToQImage(pi.getPlateImage()));
        }
    }
}
MainWindow::~MainWindow()
{
}
      
Qt车牌识别
Qt车牌识别
Qt车牌识别