参考4h上手C++版Opencv_Bilibili
OpenCV版本:4.5.5
ColorPicker.cpp
//OpenCV版本:4.5.5
#include
#include
using namespace cv;
using namespace std;
Mat imgHSV, mask, imgColor;
int hmin = 24, smin = 95, vmin = 105;
int hmax = 80, smax = 245, vmax = 255;
//24,95,105,80,245,255
VideoCapture cap(0);
Mat img;
int main()
{
namedWindow("Trackbars", (640, 200));
createTrackbar("Hue Min", "Trackbars", &hmin, 179);
createTrackbar("Hue Max", "Trackbars", &hmax, 179);
createTrackbar("Sat Min", "Trackbars", &smin, 255);
createTrackbar("Sat Max", "Trackbars", &smax, 255);
createTrackbar("Val Min", "Trackbars", &vmin, 255);
createTrackbar("Val Max", "Trackbars", &vmax, 255);
while (true)
{
//cap.read(img);
cap >> img;
cvtColor(img, imgHSV, COLOR_BGR2HSV);
Scalar lower(hmin, smin, vmin);
Scalar upper(hmax, smax, vmax);
inRange(imgHSV, lower, upper, mask);
cout << hmin << "," << smin << "," << vmin << "," << hmax << "," << smax << "," << vmax << endl;
imshow("Image", img);
imshow("Mask", mask);
waitKey(1);
}
}
VisualPaint.cpp
//OpenCV版本:4.5.5
#include
#include
#include
using namespace cv;
using namespace std;
//尽量在光照稳定的环境中运行此程序,背景最好是纯色并且与画笔的颜色差异较大
Mat img;
vector> newPoints;
//要检测的颜色(HSV模式)(顺序为hmin smin vmin hmax smax vmax)(通过ColorPicker.cpp手动调出范围)
//vector> myColors{ {21,105,125,55,230,230} };//黄色塑料壳固体胶的颜色
//140,65,110,195,150,195比较宽松的红色
vector> myColors{ {130,55,85,205,160,210} }; //更加宽松的红色
//要输出的颜色
vector myColorValues{ {0,0,255} };
Point getContours(Mat imgDil)
{
vector> contours;
vector hierarchy;
findContours(imgDil, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
vector> conPoly(contours.size());
vector boundRect(contours.size());
Point myPoint(0, 0);//笔尖坐标
int max = -1;//储存面积最大的区域的下标
for (int i = 0; i < contours.size(); i++)
{
if (contourArea(contours[i]) > 0)
{
绘制边缘
//float peri = arcLength(contours[i], true);
//approxPolyDP(contours[i], conPoly[i], 0.01 * peri, true);
//drawContours(img, conPoly, i, Scalar(255, 0, 255), 3);
cout << conPoly[i].size() << endl;
绘制矩形框
//boundRect[i] = boundingRect(conPoly[i]);
//rectangle(img, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0));
//找出面积最大的区域
if (max != -1)
{
if (contourArea(contours[i]) > contourArea(contours[max]))max = i;
}
else max = i;
}
}
if (max != -1)
{
//绘制边缘
float peri = arcLength(contours[max], true);
approxPolyDP(contours[max], conPoly[max], 0.01 * peri, true);
drawContours(img, conPoly, max, Scalar(255, 0, 255), 3);
//cout << conPoly[i].size() << endl;
//绘制矩形框
boundRect[max] = boundingRect(conPoly[max]);
rectangle(img, boundRect[max].tl(), boundRect[max].br(), Scalar(0, 255, 0));
//获取面积最大的区域(视为笔尖)的坐标
myPoint.x = boundRect[max].x + boundRect[max].width / 2;
myPoint.y = boundRect[max].y;
}
return myPoint;
}
vector> findColor(Mat img)
{
Mat imgHSV;
cvtColor(img, imgHSV, COLOR_BGR2HLS);
int max = 0;
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 });//将符合条件的笔尖坐标和相应颜色存入newPoints
}
}
return newPoints;
}
Point prepoint;//储存前一个点的坐标
void drawOnCanvas(vector> newPoints, vector myColorValues)
{
for (int i = 0; i < newPoints.size(); i++)
{
circle(img, Point(newPoints[i][0], newPoints[i][1]), 5, myColorValues[newPoints[i][2]], FILLED);
//用线段连接将前后相邻(指时间顺序的前后)且距离比较进的点连起来
//由于本程序只识别一个颜色所以可以正常运行,若要识别多个颜色需要使用一组点,如vector prepoint;
if (i >0&&sqrt((newPoints[i][0]-prepoint.x)* (newPoints[i][0] - prepoint.x)+ (newPoints[i][1] - prepoint.y) * (newPoints[i][1] - prepoint.y))<50)
line(img, prepoint, Point(newPoints[i][0], newPoints[i][1]), myColorValues[newPoints[i][2]], 10);
prepoint = Point(newPoints[i][0], newPoints[i][1]);
}
}
int main()
{
//读取视频或摄像头
VideoCapture capture(0);
while (true)
{
capture.read(img);
//capture >> img;
//newPoints = findColor(img);
findColor(img);
drawOnCanvas(newPoints,myColorValues);
imshow("读取视频", img);
waitKey(1);
}
return 0;
}