OpenCV4.0 C++ 实战:虚拟画家(自用 代码+注释)

环境:OpenCV4.5.1 + VS2019

目录

1. 准备工作:

1.1 “资源”文件

1.2 颜色检测器

2. 主要代码

2.1 获取笔头轮廓并找出笔头顶点坐标

2.2 找出落笔位置坐标及颜色的集

2.3 在视频窗口中画出笔头运动轨迹

2.4 实现

3. 总结

  1. 准备工作:

1.1 “资源”文件

“Resources”文件下载链接:

https://pan.baidu.com/s/1uzVDwl8lD2qVTY1bFlhF1A
提取码:5n48

1.2 颜色检测器

拾色器.cpp

#include
#include
#include
#include

//  颜色检测器
using namespace cv;
using namespace std;

//      Color Picker        //

Mat imgHSV, mask, imgColor;
int hmin = 0, smin = 0, vmin = 0;
int hmax = 179, smax = 255, vmax = 255;

VideoCapture cap(0);
Mat img;

void main() {

    namedWindow("Trackbar", (640, 200));    //  Create Window
    createTrackbar("Hue Min", "Trackbar", &hmin, 179);  //参数三:初始值(当前值);
    createTrackbar("Hue Max", "Trackbar", &hmax, 179);  //参数四:最大范围值
    createTrackbar("Sat Min", "Trackbar", &smin, 255);
    createTrackbar("Sat Max", "Trackbar", &smax, 255);
    createTrackbar("Val Min", "Trackbar", &vmin, 255);
    createTrackbar("Val Max", "Trackbar", &vmax, 255);

    while (true) {

        cap.read(img);
        flip(img, img, 1);
        cvtColor(img, imgHSV, COLOR_BGR2HSV);

        Scalar lower(hmin, smin, vmin);
        Scalar upper(hmax, smax, vmax);

        inRange(imgHSV, lower, upper, mask);
        //bitwise_and(img, img, imgColor, mask = mask);

        cout << hmin << "," << smin << "," << vmin << ",";
        cout << hmax << "," << smax << "," << vmax << endl;

        imshow("Image", img);
        imshow("Image Mask", mask);
        //imshow("Image Color", imgColor);

        waitKey(1);
    }
}
  1. 主要代码

2.1 获取笔头轮廓并找出笔头顶点坐标

Point getContours(Mat imgDil) {

    vector> contours;       //轮廓组
    vector hierarchy;           // 向量内每个元素包含了4个int型的 向量

    findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);      //检测轮廓
    //  参数二:输入的轮廓组  参数三:画第几条轮廓(-1为负数表示全画)       参数五:线宽
    //  参数四:检测轮廓的方法(这里是只检测外轮廓)) 参数五:表示一条轮廓的方法(这里是只存储水平,垂直,对角直线的起始点)
    //drawContours(img, contours, -1, Scalar(255, 0, 255), 2);                          //画出轮廓

    vector> conPoly(contours.size());
    vector boundRect(contours.size());

    Point myPoint(0, 0);

    for (int i = 0; i < contours.size(); i++)
    {
        int area = contourArea(contours[i]);        //轮廓面积
        //cout << area << endl;
        //string objectType;

        //  通过面积大小过滤(去噪)
        if (area > 1000)
        {
            float peri = arcLength(contours[i], true);      //弧长(轮廓周长) (参数一:图像轮廓;参数二:是否闭合)
            approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);                   //对图像轮廓点 进行 多边形拟合
            //参数一/二:输入/输出的点集    参数三:指定精度    参数四:是否闭合

            //cout << conPoly[i].size() << endl;
            boundRect[i] = boundingRect(contours[i]);       //计算轮廓的 垂直边界最小矩形

            myPoint.x = boundRect[i].x + boundRect[i].width / 2;
            myPoint.y = boundRect[i].y;

            //drawContours(img, conPoly, i, Scalar(255, 0, 255), 2);                        //画出轮廓
            //  参数二:输入的轮廓组  参数三:画第i条轮廓(负数表示全画)      参数五:线宽
            //rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5);
        }
    }
    return myPoint;
}

2.2 找出落笔位置坐标及颜色的集

vector> findColor(Mat img) {

    Mat imgHSV;
    cvtColor(img, imgHSV, COLOR_BGR2HSV);

    for (int i = 0; i < myColors.size(); i++) {

        Scalar lower(myColors[i][0], myColors[i][1], myColors[i][2]);
        Scalar upper(myColors[i][3], myColors[i][4], myColors[i][5]);
        Mat mask;
        inRange(imgHSV, lower, upper, mask);
        //imshow(to_string(i), mask);
        Point myPoint = getContours(mask);

        if (myPoint.x != 0 && myPoint.y != 0) {
            newPoints.push_back({ myPoint.x, myPoint.y, i });
        }
    }
    return newPoints;
}

2.3 在视频窗口中画出笔头运动轨迹

void drawOnCanvas(vector> newPoints, vector myColorValues) {
    for (int i = 0; i < newPoints.size(); i++) {
        if (i == 0) {
            circle(img, Point(newPoints[i][0], newPoints[i][1]), 5, Scalar(myColorValues[newPoints[i][2]]), FILLED);
        }
        else if (i > 0) {
            line(img, Point(newPoints[i-1][0], newPoints[i-1][1]), Point(newPoints[i][0], newPoints[i][1]), myColorValues[newPoints[i][2]], 5);
        }
    }
}

2.4 实现

Project 1.cpp

//#include
//#include
//#include
#include
#include

//项目一:虚拟画笔
using namespace cv;
using namespace std;

        Virtual Painter     //

Mat img;
vector> newPoints;

    //  hmin, smin, vmin, hmax, smax, vmax
vector> myColors{ {169,183,0,179,255,255},      // Red
                                {32,83,53,79,255,255},          //  Green
                                {106,174,0,121,255,255} };      //  Blue

vector myColorValues{ {0,0,255},        // Red
                                {0,255,0},          //  Green
                                {255,0,0} };        //  Blue

Point getContours(Mat imgDil) {

    vector> contours;       //轮廓组
    vector hierarchy;           // 向量内每个元素包含了4个int型的 向量

    findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);      //检测轮廓
    //  参数二:输入的轮廓组  参数三:画第几条轮廓(-1为负数表示全画)       参数五:线宽
    //  参数四:检测轮廓的方法(这里是只检测外轮廓)) 参数五:表示一条轮廓的方法(这里是只存储水平,垂直,对角直线的起始点)
    //drawContours(img, contours, -1, Scalar(255, 0, 255), 2);                          //画出轮廓

    vector> conPoly(contours.size());
    vector boundRect(contours.size());

    Point myPoint(0, 0);

    for (int i = 0; i < contours.size(); i++)
    {
        int area = contourArea(contours[i]);        //轮廓面积
        //cout << area << endl;
        //string objectType;

        //  通过面积大小过滤(去噪)
        if (area > 1000)
        {
            float peri = arcLength(contours[i], true);      //弧长(轮廓周长) (参数一:图像轮廓;参数二:是否闭合)
            approxPolyDP(contours[i], conPoly[i], 0.02 * peri, true);                   //对图像轮廓点 进行 多边形拟合
            //参数一/二:输入/输出的点集    参数三:指定精度    参数四:是否闭合

            //cout << conPoly[i].size() << endl;
            boundRect[i] = boundingRect(contours[i]);       //计算轮廓的 垂直边界最小矩形

            myPoint.x = boundRect[i].x + boundRect[i].width / 2;
            myPoint.y = boundRect[i].y;

            //drawContours(img, conPoly, i, Scalar(255, 0, 255), 2);                        //画出轮廓
            //  参数二:输入的轮廓组  参数三:画第i条轮廓(负数表示全画)      参数五:线宽
            //rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 5);
        }
    }
    return myPoint;
}

vector> findColor(Mat img) {

    Mat imgHSV;
    cvtColor(img, imgHSV, COLOR_BGR2HSV);

    for (int i = 0; i < myColors.size(); i++) {

        Scalar lower(myColors[i][0], myColors[i][1], myColors[i][2]);
        Scalar upper(myColors[i][3], myColors[i][4], myColors[i][5]);
        Mat mask;
        inRange(imgHSV, lower, upper, mask);
        //imshow(to_string(i), mask);
        Point myPoint = getContours(mask);

        if (myPoint.x != 0 && myPoint.y != 0) {
            newPoints.push_back({ myPoint.x, myPoint.y, i });
        }
    }
    return newPoints;
}

void drawOnCanvas(vector> newPoints, vector myColorValues) {
    for (int i = 0; i < newPoints.size(); i++) {
        if (i == 0) {
            circle(img, Point(newPoints[i][0], newPoints[i][1]), 5, Scalar(myColorValues[newPoints[i][2]]), FILLED);
        }
        else if (i > 0) {
            line(img, Point(newPoints[i-1][0], newPoints[i-1][1]), Point(newPoints[i][0], newPoints[i][1]), myColorValues[newPoints[i][2]], 5);
        }
    }
}

void main() {

    VideoCapture cap(0);

    while (true) {

        cap.read(img);
        flip(img, img, 1);

        newPoints = findColor(img);
        drawOnCanvas(newPoints, myColorValues);

        imshow("Image", img);
        int c = waitKey(1);
        if (c == 27) {          //按 esc 退出应用程序
            break;
        }
        else if (c == 32) {     //按 空格 清屏
            newPoints = {};
        }
    }

}
  1. 总结

实现功能:

通过颜色检测器检测出笔头颜色后,调用电脑摄像头可实时检测出笔头顶点中心的运动轨迹并将该运动轨迹用设置好的相应颜色绘制出来。

OpenCV4.0 C++ 实战:虚拟画家(自用 代码+注释)

OpenCV4.0 C++ 实战:虚拟画家(自用 代码+注释)

OpenCV4.0 C++ 实战:虚拟画家(自用 代码+注释)

未完善地方:

同一时间只能使用一种颜色绘制,若同时使用两种或以上颜色进行绘制会出现绘制错乱的情况。

OpenCV4.0 C++ 实战:虚拟画家(自用 代码+注释)

OpenCV4.0 C++ 实战:虚拟画家(自用 代码+注释)

Original: https://blog.csdn.net/weixin_47059239/article/details/122915633
Author: chxin14160
Title: OpenCV4.0 C++ 实战:虚拟画家(自用 代码+注释)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/704937/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球