C++ OpenCV实现之实现红绿灯识别

目录
  • 前言
  • 一、轮廓识别相关原理
    • 什么是轮廓检测
    • 轮廓提取函数findContours
  • 二、案例实现
    • Step1:初始化配置
    • Step2:进行帧处理
    • Step3:膨胀腐蚀处理
    • Step4:红绿灯提示判断
    • Step5:轮廓提取
    • Step6:判断是否相交
    • 完整代码
  • 三、总结

前言

本文以实现行车过程当中的红绿灯识别为目标,核心的内容包括:OpenCV轮廓识别原理以及OpenCV红绿灯识别的实现具体步骤

一、轮廓识别相关原理

什么是轮廓检测

目前轮廓检测方法有两类,一类是利用传统的边缘检测算子检测目标轮廓,另一类是从人类视觉系统中提取可以使用的数学模型完成目标轮廓检测

轮廓提取函数findContours

函数原型: 

findContours( InputOutputArray image, OutputArrayOfArrays contours,
                              OutputArray hierarchy, int mode,
                              int method, Point offset=Point());

参数:

image:单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像

contours:  定义为“vector<vector<Point>> contours”,是一个向量,并且是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素

hierarchy:  也是一个向量,向量内每个元素保存了一个包含4个int整型的数组。向量内的元素和轮廓向量contours内的元素是一一对应的,向量的容量相同

int mode: 

取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到 contours向量内

取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留

取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

Point: Point偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值!

参数详解引用出处:findContours函数参数详解

二、案例实现

这是本案例所用到的素材,如下图所示:

PS:视频的效果比较好,如果方便的话可以自行外出拍摄取材

Step1:初始化配置

做好准备工作,创建我们需要的内容,设置亮度参数,以及我们导入的视频路径

    int redCount = 0;
    int greenCount = 0;

    Mat frame;
    Mat img;
    Mat imgYCrCb;
    Mat imgGreen;
    Mat imgRed;

    // 亮度参数
    double a = 0.3;
    double b = (1 - a) * 125;

    VideoCapture capture("C:/Users/86177/Desktop/image/123.mp4");//导入视频的路径
    if (!capture.isOpened())
    {
        cout << "Start device failed!\n" << endl;//启动设备失败!
        return -1;
    }

Step2:进行帧处理

调整视频亮度,分解YCrCb的三个成分,拆分红色和绿色,方便对红绿两种颜色进行特征提取

    // 帧处理
    while (1)
    {
        capture >> frame;
        //调整亮度
        frame.convertTo(img, img.type(), a, b);

        //转换为YCrCb颜色空间
        cvtColor(img, imgYCrCb, CV_BGR2YCrCb);

        imgRed.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);
        imgGreen.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);

        //分解YCrCb的三个成分
        vector<Mat> planes;
        split(imgYCrCb, planes);
        // 遍历以根据Cr分量拆分红色和绿色
        MatIterator_<uchar> it_Cr = planes[1].begin<uchar>(),
                it_Cr_end = planes[1].end<uchar>();
        MatIterator_<uchar> it_Red = imgRed.begin<uchar>();
        MatIterator_<uchar> it_Green = imgGreen.begin<uchar>();

        for (; it_Cr != it_Cr_end; ++it_Cr, ++it_Red, ++it_Green)
        {
            // RED, 145<Cr<470 红色
            if (*it_Cr > 145 && *it_Cr < 470)
                *it_Red = 255;
            else
                *it_Red = 0;

            // GREEN 95<Cr<110 绿色
            if (*it_Cr > 95 && *it_Cr < 110)
                *it_Green = 255;
            else
                *it_Green = 0;
        }

Step3:膨胀腐蚀处理

去除其他噪点,提高我们需要的红绿灯的特征

        //膨胀和腐蚀
        dilate(imgRed, imgRed, Mat(15, 15, CV_8UC1), Point(-1, -1));
        erode(imgRed, imgRed, Mat(1, 1, CV_8UC1), Point(-1, -1));
        dilate(imgGreen, imgGreen, Mat(15, 15, CV_8UC1), Point(-1, -1));
        erode(imgGreen, imgGreen, Mat(1, 1, CV_8UC1), Point(-1, -1));

        redCount = processImgR(imgRed);
        greenCount = processImgG(imgGreen);
        cout << "red:" << redCount << ";  " << "green:" << greenCount << endl;

Step4:红绿灯提示判断

加入红绿灯识别结果显示,方便我们查看效果

        if(redCount == 0 && greenCount == 0)
        {
            cv::putText(frame, "lights out", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(255, 255, 255), 8, 8, 0);
        }else if(redCount > greenCount)
        {
            cv::putText(frame, "red light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 0, 255), 8, 8, 0);
        }else{
            cv::putText(frame, "green light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 255, 0), 8, 8, 0);
        }

Step5:轮廓提取

分别对红灯和绿灯进行轮廓特征提取,提高辨识度

int processImgR(Mat src)
{
    Mat tmp;

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    vector<Point> hull;

    CvPoint2D32f tempNode;
    CvMemStorage* storage = cvCreateMemStorage();
    CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);

    Rect* trackBox;
    Rect* result;
    int resultNum = 0;

    int area = 0;
    src.copyTo(tmp);

    //提取轮廓
    findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

    if (contours.size() > 0)
    {
        trackBox = new Rect[contours.size()];
        result = new Rect[contours.size()];

        //确定要跟踪的区域
        for (int i = 0; i < contours.size(); i++)
        {
            cvClearSeq(pointSeq);
            // 获取凸包的点集
            convexHull(Mat(contours[i]), hull, true);
            int hullcount = (int)hull.size();
            // 凸包的保存点
            for (int j = 0; j < hullcount - 1; j++)
            {
                tempNode.x = hull[j].x;
                tempNode.y = hull[j].y;
                cvSeqPush(pointSeq, &tempNode);
            }

            trackBox[i] = cvBoundingRect(pointSeq);
        }

        if (isFirstDetectedR)
        {
            lastTrackBoxR = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
                lastTrackBoxR[i] = trackBox[i];
            lastTrackNumR = contours.size();
            isFirstDetectedR = false;
        }
        else
        {
            for (int i = 0; i < contours.size(); i++)
            {
                for (int j = 0; j < lastTrackNumR; j++)
                {
                    if (isIntersected(trackBox[i], lastTrackBoxR[j]))
                    {
                        result[resultNum] = trackBox[i];
                        break;
                    }
                }
                resultNum++;
            }
            delete[] lastTrackBoxR;
            lastTrackBoxR = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
            {
                lastTrackBoxR[i] = trackBox[i];
            }
            lastTrackNumR = contours.size();
        }

        delete[] trackBox;
    }
    else
    {
        isFirstDetectedR = true;
        result = NULL;
    }
    cvReleaseMemStorage(&storage);

    if (result != NULL)
    {
        for (int i = 0; i < resultNum; i++)
        {
            area += result[i].area();
        }
    }
    delete[] result;

    return area;
}

int processImgG(Mat src)
{
    Mat tmp;

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    vector< Point > hull;

    CvPoint2D32f tempNode;
    CvMemStorage* storage = cvCreateMemStorage();
    CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);

    Rect* trackBox;
    Rect* result;
    int resultNum = 0;

    int area = 0;

    src.copyTo(tmp);
    //提取轮廓
    findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

    if (contours.size() > 0)
    {
        trackBox = new Rect[contours.size()];
        result = new Rect[contours.size()];

        // 确定要跟踪的区域
        for (int i = 0; i < contours.size(); i++)
        {
            cvClearSeq(pointSeq);
            // 获取凸包的点集
            convexHull(Mat(contours[i]), hull, true);
            int hullcount = (int)hull.size();
            // 保存凸包的点
            for (int j = 0; j < hullcount - 1; j++)
            {
                tempNode.x = hull[j].x;
                tempNode.y = hull[j].y;
                cvSeqPush(pointSeq, &tempNode);
            }

            trackBox[i] = cvBoundingRect(pointSeq);
        }

        if (isFirstDetectedG)
        {
            lastTrackBoxG = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
                lastTrackBoxG[i] = trackBox[i];
            lastTrackNumG = contours.size();
            isFirstDetectedG = false;
        }
        else
        {
            for (int i = 0; i < contours.size(); i++)
            {
                for (int j = 0; j < lastTrackNumG; j++)
                {
                    if (isIntersected(trackBox[i], lastTrackBoxG[j]))
                    {
                        result[resultNum] = trackBox[i];
                        break;
                    }
                }
                resultNum++;
            }
            delete[] lastTrackBoxG;
            lastTrackBoxG = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
            {
                lastTrackBoxG[i] = trackBox[i];
            }
            lastTrackNumG = contours.size();
        }

        delete[] trackBox;
    }
    else
    {
        isFirstDetectedG = true;
        result = NULL;
    }
    cvReleaseMemStorage(&storage);

    if (result != NULL)
    {
        for (int i = 0; i < resultNum; i++)
        {
            area += result[i].area();
        }
    }
    delete[] result;

    return area;
}

Step6:判断是否相交

//确定两个矩形区域是否相交
bool isIntersected(Rect r1, Rect r2)
{
    int minX = max(r1.x, r2.x);
    int minY = max(r1.y, r2.y);
    int maxX = min(r1.x + r1.width, r2.x + r2.width);
    int maxY = min(r1.y + r1.height, r2.y + r2.height);

    if (minX < maxX && minY < maxY)
        return true;
    else
        return false;
}

案例效果

完整代码

#include "opencv2/opencv.hpp"
#include "opencv2/imgproc.hpp"
#include <windows.h>
#include <iostream>

using namespace std;
using namespace cv;

// Function headers
int processImgR(Mat);
int processImgG(Mat);
bool isIntersected(Rect, Rect);

// Global variables
bool isFirstDetectedR = true;
bool isFirstDetectedG = true;
Rect* lastTrackBoxR;
Rect* lastTrackBoxG;
int lastTrackNumR;
int lastTrackNumG;

//主函数
int main()
{
    int redCount = 0;
    int greenCount = 0;

    Mat frame;
    Mat img;
    Mat imgYCrCb;
    Mat imgGreen;
    Mat imgRed;

    // 亮度参数
    double a = 0.3;
    double b = (1 - a) * 125;

    VideoCapture capture("C:/Users/86177/Desktop/image/123.mp4");//导入视频的路径
    if (!capture.isOpened())
    {
        cout << "Start device failed!\n" << endl;//启动设备失败!
        return -1;
    }

    // 帧处理
    while (1)
    {
        capture >> frame;
        //调整亮度
        frame.convertTo(img, img.type(), a, b);

        //转换为YCrCb颜色空间
        cvtColor(img, imgYCrCb, CV_BGR2YCrCb);

        imgRed.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);
        imgGreen.create(imgYCrCb.rows, imgYCrCb.cols, CV_8UC1);

        //分解YCrCb的三个成分
        vector<Mat> planes;
        split(imgYCrCb, planes);
        // 遍历以根据Cr分量拆分红色和绿色
        MatIterator_<uchar> it_Cr = planes[1].begin<uchar>(),
                it_Cr_end = planes[1].end<uchar>();
        MatIterator_<uchar> it_Red = imgRed.begin<uchar>();
        MatIterator_<uchar> it_Green = imgGreen.begin<uchar>();

        for (; it_Cr != it_Cr_end; ++it_Cr, ++it_Red, ++it_Green)
        {
            // RED, 145<Cr<470 红色
            if (*it_Cr > 145 && *it_Cr < 470)
                *it_Red = 255;
            else
                *it_Red = 0;

            // GREEN 95<Cr<110 绿色
            if (*it_Cr > 95 && *it_Cr < 110)
                *it_Green = 255;
            else
                *it_Green = 0;
        }

        //膨胀和腐蚀
        dilate(imgRed, imgRed, Mat(15, 15, CV_8UC1), Point(-1, -1));
        erode(imgRed, imgRed, Mat(1, 1, CV_8UC1), Point(-1, -1));
        dilate(imgGreen, imgGreen, Mat(15, 15, CV_8UC1), Point(-1, -1));
        erode(imgGreen, imgGreen, Mat(1, 1, CV_8UC1), Point(-1, -1));

        redCount = processImgR(imgRed);
        greenCount = processImgG(imgGreen);
        cout << "red:" << redCount << ";  " << "green:" << greenCount << endl;

        if(redCount == 0 && greenCount == 0)
        {
            cv::putText(frame, "lights out", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(255, 255, 255), 8, 8, 0);
        }else if(redCount > greenCount)
        {
            cv::putText(frame, "red light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 0, 255), 8, 8, 0);
        }else{
            cv::putText(frame, "green light", Point(40, 150), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 255, 0), 8, 8, 0);
        }

        imshow("video", frame);
        imshow("Red", imgRed);
        imshow("Green", imgGreen);

        // Handle with the keyboard input
        if (cvWaitKey(20) == 'q')
            break;
    }

    return 0;
}

int processImgR(Mat src)
{
    Mat tmp;

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    vector<Point> hull;

    CvPoint2D32f tempNode;
    CvMemStorage* storage = cvCreateMemStorage();
    CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);

    Rect* trackBox;
    Rect* result;
    int resultNum = 0;

    int area = 0;
    src.copyTo(tmp);

    //提取轮廓
    findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

    if (contours.size() > 0)
    {
        trackBox = new Rect[contours.size()];
        result = new Rect[contours.size()];

        //确定要跟踪的区域
        for (int i = 0; i < contours.size(); i++)
        {
            cvClearSeq(pointSeq);
            // 获取凸包的点集
            convexHull(Mat(contours[i]), hull, true);
            int hullcount = (int)hull.size();
            // 凸包的保存点
            for (int j = 0; j < hullcount - 1; j++)
            {
                tempNode.x = hull[j].x;
                tempNode.y = hull[j].y;
                cvSeqPush(pointSeq, &tempNode);
            }

            trackBox[i] = cvBoundingRect(pointSeq);
        }

        if (isFirstDetectedR)
        {
            lastTrackBoxR = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
                lastTrackBoxR[i] = trackBox[i];
            lastTrackNumR = contours.size();
            isFirstDetectedR = false;
        }
        else
        {
            for (int i = 0; i < contours.size(); i++)
            {
                for (int j = 0; j < lastTrackNumR; j++)
                {
                    if (isIntersected(trackBox[i], lastTrackBoxR[j]))
                    {
                        result[resultNum] = trackBox[i];
                        break;
                    }
                }
                resultNum++;
            }
            delete[] lastTrackBoxR;
            lastTrackBoxR = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
            {
                lastTrackBoxR[i] = trackBox[i];
            }
            lastTrackNumR = contours.size();
        }

        delete[] trackBox;
    }
    else
    {
        isFirstDetectedR = true;
        result = NULL;
    }
    cvReleaseMemStorage(&storage);

    if (result != NULL)
    {
        for (int i = 0; i < resultNum; i++)
        {
            area += result[i].area();
        }
    }
    delete[] result;

    return area;
}

int processImgG(Mat src)
{
    Mat tmp;

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    vector< Point > hull;

    CvPoint2D32f tempNode;
    CvMemStorage* storage = cvCreateMemStorage();
    CvSeq* pointSeq = cvCreateSeq(CV_32FC2, sizeof(CvSeq), sizeof(CvPoint2D32f), storage);

    Rect* trackBox;
    Rect* result;
    int resultNum = 0;

    int area = 0;

    src.copyTo(tmp);
    //提取轮廓
    findContours(tmp, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);

    if (contours.size() > 0)
    {
        trackBox = new Rect[contours.size()];
        result = new Rect[contours.size()];

        // 确定要跟踪的区域
        for (int i = 0; i < contours.size(); i++)
        {
            cvClearSeq(pointSeq);
            // 获取凸包的点集
            convexHull(Mat(contours[i]), hull, true);
            int hullcount = (int)hull.size();
            // 保存凸包的点
            for (int j = 0; j < hullcount - 1; j++)
            {
                tempNode.x = hull[j].x;
                tempNode.y = hull[j].y;
                cvSeqPush(pointSeq, &tempNode);
            }

            trackBox[i] = cvBoundingRect(pointSeq);
        }

        if (isFirstDetectedG)
        {
            lastTrackBoxG = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
                lastTrackBoxG[i] = trackBox[i];
            lastTrackNumG = contours.size();
            isFirstDetectedG = false;
        }
        else
        {
            for (int i = 0; i < contours.size(); i++)
            {
                for (int j = 0; j < lastTrackNumG; j++)
                {
                    if (isIntersected(trackBox[i], lastTrackBoxG[j]))
                    {
                        result[resultNum] = trackBox[i];
                        break;
                    }
                }
                resultNum++;
            }
            delete[] lastTrackBoxG;
            lastTrackBoxG = new Rect[contours.size()];
            for (int i = 0; i < contours.size(); i++)
            {
                lastTrackBoxG[i] = trackBox[i];
            }
            lastTrackNumG = contours.size();
        }

        delete[] trackBox;
    }
    else
    {
        isFirstDetectedG = true;
        result = NULL;
    }
    cvReleaseMemStorage(&storage);

    if (result != NULL)
    {
        for (int i = 0; i < resultNum; i++)
        {
            area += result[i].area();
        }
    }
    delete[] result;

    return area;
}

//确定两个矩形区域是否相交
bool isIntersected(Rect r1, Rect r2)
{
    int minX = max(r1.x, r2.x);
    int minY = max(r1.y, r2.y);
    int maxX = min(r1.x + r1.width, r2.x + r2.width);
    int maxY = min(r1.y + r1.height, r2.y + r2.height);

    if (minX < maxX && minY < maxY)
        return true;
    else
        return false;
}

三、总结

本文主要讲解OpenCV轮廓识别原理以及OpenCV红绿灯识别的实现具体步骤OpenCV还是有很多识别的库函数可以用,接下来继续探索,结合生活实际继续做一些有意思的案例

到此这篇关于C++ OpenCV实现之实现红绿灯识别的文章就介绍到这了,更多相关C++ OpenCV红绿灯识别内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ OpenCV实战之形状识别

    目录 前言 一.图像预处理 二.形状识别 三.源码 四.结果显示 总结 前言 本案例通过使用OpenCV中的approxPolyDP进行多边形近似,进而进行基础形状识别(圆.三角形.矩形.星形…).下面就一起来看看具体是如何实现的吧. 一.图像预处理 原图如图所示: 首先第一步先进行图像预处理,得到二值图像. Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); Mat gaussian; GaussianBlur(gray, gaussian, Size

  • OpenCV3实现车牌识别(C++版)

    本文实例为大家分享了OpenCV3实现车牌识别的具体代码,供大家参考,具体内容如下 车牌识别(基于OpenCV3.4.7+VS2017) 视频识别 蓝色车牌识别 视觉入坑的第一个Demo(注释很详细),因为本人之前拖延,一直没能写详细实现博客,先将代码贴出来供大家交流,个人认为精华部分在字符切割(直接用指针遍历像素加限制条件切割),车牌模板已上传,整个工程也已上传,后续完善各环节实现步骤详解. 头文件:Global.h #ifdef GLOBAL extern int flag_1; exter

  • C++ opencv实现车道线识别

    本文实例为大家分享了C++ opencv实现车道线识别的具体代码,供大家参考,具体内容如下 先上图 1. 2. (一)目前国内外广泛使用的车道线检测方法主要分为两大类: (1) 基于道路特征的车道线检测: (2) 基于道路模型的车道线检测. 基于道路特征的车道线检测作为主流检测方法之一,主要是利用车道线与道路环境的物理特征差异进行后续图像的分割与处理,从而突出车道线特征,以实现车道线的检测.该方法复杂度较低,实时性较高,但容易受到道路环境干扰. 基于道路模型的车道线检测主要是基于不同的二维或三维

  • C++ OpenCV实战之手势识别

    目录 前言 一.手部关键点检测 1.1 功能源码 1.2 功能效果 二.手势识别 2.1算法原理 2.2功能源码 三.结果显示 3.1功能源码 3.2效果显示 四.源码 总结 前言 本文将使用OpenCV C++ 实现手势识别效果.本案例主要可以分为以下几个步骤: 1.手部关键点检测 2.手势识别 3.效果显示 接下来就来看看本案例具体是怎么实现的吧!!! 一.手部关键点检测 如图所示,为我们的手部关键点所在位置.第一步,我们需要检测手部21个关键点.我们使用深度神经网络DNN模块来完成这件事.

  • C++ OpenCV技术实战之身份证离线识别

    目录 总体思路 图像的预处理 主要代码 实现效果 OpenCV身份证离线识别技术的主要技术就是通过OpenCV找到身份证号码区域,然后通过OCR进行数字识别该区域的截图即可得到身份证号码.本地ORC使用tess-two来完成,Tesseract是C++实现的OCR引擎,在Android中使用不是很方便,需要封装JavaAPI才能在Android平台中进行调用,然而tess-two已经帮我们做好了这些事情,通过集成tess-two就可以很方便的完成文字识别. 总体思路 图像的预处理 1.无损压缩

  • C++基于OpenCV实现手势识别的源码

    先给大家上效果图: 源码在下面 使用 RGB 值分割手部区域,即手部的 GB 值将与背景不同 或者使用边缘检测 或者 背景减法. 我这里使用了背景减法模型.OpenCV为我们提供了不同的背景减法模型,codebook   它的作用是对某些帧进行一段时间的精确校准.其中对于它获取的所有图像:它计算每个像素的平均值和偏差,并相应地指定框. 在前景中它就像一个黑白图像,只有手是白色的 用 Convex Hull 来找到指尖.Convex hull 基本上是包围手部区域的凸集. 包围手的红线是凸包.基本

  • C++ OpenCV实现银行卡号识别功能

    目录 前言 一.获取模板图像 1.1 功能效果 1.2 功能源码 二.银行卡号定位 2.1 将银行卡号切割成四块 2.2 字符切割 三.字符识别 3.1.读取文件 3.2.字符匹配 3.3.功能源码 四.效果显示 4.1 功能源码 4.2 效果显示 五.源码 5.1 hpp文件 5.2 cpp文件 5.3 main文件 总结 前言 本文将使用OpenCV C++ 进行银行卡号识别.主要步骤可以细分为: 1. 获取模板图像 2.银行卡号区域定位 3.字符切割 4.模板匹配 5.效果显示 接下来就具

  • C++ OpenCV实现之实现红绿灯识别

    目录 前言 一.轮廓识别相关原理 什么是轮廓检测 轮廓提取函数findContours 二.案例实现 Step1:初始化配置 Step2:进行帧处理 Step3:膨胀腐蚀处理 Step4:红绿灯提示判断 Step5:轮廓提取 Step6:判断是否相交 完整代码 三.总结 前言 本文以实现行车过程当中的红绿灯识别为目标,核心的内容包括:OpenCV轮廓识别原理以及OpenCV红绿灯识别的实现具体步骤 一.轮廓识别相关原理 什么是轮廓检测 目前轮廓检测方法有两类,一类是利用传统的边缘检测算子检测目标

  • python+opencv实现的简单人脸识别代码示例

    # 源码如下: #!/usr/bin/env python #coding=utf-8 import os from PIL import Image, ImageDraw import cv def detect_object(image): '''检测图片,获取人脸在图片中的坐标''' grayscale = cv.CreateImage((image.width, image.height), 8, 1) cv.CvtColor(image, grayscale, cv.CV_BGR2GR

  • OpenCV+face++实现实时人脸识别解锁功能

    本文实例为大家分享了OpenCV+face++实现实时人脸识别解锁功能的具体代码,供大家参考,具体内容如下 1.背景 最近做一个小东西,需要登录功能,一开始做的就是普通的密码登录功能,但是之前看到过python可以做人脸识别,所以我就开了下脑洞,能不能实现一个自己的刷脸解锁功能. 2.知识储备 python基础语法 opencv face++文档 requests库 3.基本思路 准备一张你想要被识别出的人脸照片,后面刷脸就是按照这张照片来识别,如果和照片中是同一个人就解锁,刷脸就是打开摄像头获

  • Python基于OpenCV库Adaboost实现人脸识别功能详解

    本文实例讲述了Python基于OpenCV库Adaboost实现人脸识别功能.分享给大家供大家参考,具体如下: 以前用Matlab写神经网络的面部眼镜识别算法,研究算法逻辑,采集大量训练数据,迭代,计算各感知器的系数...相当之麻烦~而现在运用调用pythonOpenCV库Adaboost算法,无需知道算法逻辑,无需进行模型训练,人脸识别变得相当之简单了. 需要用到的库是opencv(open source computer vision),下载安装方式如下: 使用pip install num

  • python opencv实现信用卡的数字识别

    本项目利用python以及opencv实现信用卡的数字识别 前期准备 导入工具包 定义功能函数 模板图像处理 读取模板图像 cv2.imread(img) 灰度化处理 cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 二值化 cv2.threshold() 轮廓 - 轮廓 信用卡图像处理 读取信用卡图像 cv2.imread(img) 灰度化处理 cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 礼帽处理 cv2.morphologyEx(gray

  • Python 使用Opencv实现目标检测与识别的示例代码

    在上章节讲述到图像特征检测与匹配 ,本章节是讲述目标检测与识别.后者是在前者的基础上进一步完善. 在本章中,我们使用HOG算法,HOG和SIFT.SURF同属一种类型的描述符.功能代码如下: import cv2 def is_inside(o, i): ox, oy, ow, oh = o ix, iy, iw, ih = i # 如果符合条件,返回True,否则返回False return ox > ix and oy > iy and ox + ow < ix + iw and o

  • Python OpenCV招商银行信用卡卡号识别的方法

    学在前面 从本篇博客起,我们将实际完成几个小案例,第一个就是银行卡号识别,预计本案例将写 5 篇左右的博客才可以完成,一起加油吧. 本文的目标是最终获取一套招商银行卡,0~9 数字的图,对于下图的数字,我们需要提取出来,便于后续模板匹配使用.不过下图中找到的数字不完整,需要找到尽量多的卡片,然后补齐这些数字. 提取卡片相关数字 先对上文中卡片中的数字进行相关提取操作,加载图片的灰度图,获取目标区域.在画板中模拟一下坐标区域,为了便于进行后续的操作. 具体代码如下: import cv2 as c

  • 基于python3+OpenCV实现人脸和眼睛识别

    基于python3+OpenCV的人脸和眼睛识别,供大家参考,具体内容如下 一.OpenCV人脸检测的xml文件下载 人脸检测和眼睛检测要用到haarcascade_eye.xml和haarcascade_frontalface_default.xml这两个文件,这两个文件可以在OpenCV的官网下载,具体下载方法如下: 1.打开要下载的xml文件,如下图: 2.点击Raw: 3.在新打开的网页中右击,选择另存为,最后保存就可以了. 二.人脸检测文件的导入以及图片的处理 接下来就可以在代码中载入

  • 如何基于opencv实现简单的数字识别

    目录 前言 要解决的问题 解决问题的思路 总结 前言 由于自己学识尚浅,不能用python深度学习来识别这里的数字,所以就完全采用opencv来识别数字,然后在这里分享.记录一下自己在学习过程中的一些所见所得和所想 要解决的问题 这是一个要识别的数字,我这里首先是对图像进行一个ROI的提取,提取结果就仅仅剩下数字,把其他的一些无关紧要的要素排除在外, 这是ROI图片,我们要做的就是识别出该照片中的数字, 解决问题的思路 1.先把这个图片中的数字分割,分割成为5张小图片,每张图片包含一个数字,为啥

  • 基于opencv和pillow实现人脸识别系统(附demo)

    目录 一.人脸检测和数据收集 二.训练识别器 三.人脸识别和显示 本文不涉及分类器.训练识别器等算法原理,仅包含对其应用(未来我也会写自己对机器学习算法原理的一些观点和了解) 首先我们需要知道的是利用现有框架做一个人脸识别系统并不难,然后就开始我们的系统开发吧. 我们的系统主要分为三个部分,然后我还会提出对补获图片不能添加中文的解决方案.我们需要完成的任务:1.人脸检测和数据收集2.训练识别器3.人脸识别和显示 在读此篇文章之前我相信你已经做了python环境部署和opencv模块的下载安装工作

随机推荐