这是一篇OpenCv4 C++版本入门的个人笔记,是B站课程30讲的部分笔记。代码中创建一个QuickDemo类,类中的每一个公有成员函数对应一个知识点。
分别有:1、将原图转为HSV和GRAY图像显示并保存;2、进行像素操作,加减乘除;3、滚动条调整亮度;4、键盘输入响应;5、改变图像颜色风格;6、像素逻辑运算;7、通道分离与合并;8、图像色彩空间转换;9、图像像素统计,最大最小值,均值方差;10、在图像中绘制几何图形;11、绘制多边形;12、鼠标响应,绘制矩形;13、像素类型转换与归一化;14、图像放缩;15、图像翻转;16、图像旋转;17、调用摄像头。
具体程序代码:
main.cpp
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
#include
#include "quickopencv.h"
using namespace std;
using namespace cv;
Mat img;
int main(int argc,char** argv)
{
img = imread("D:/exercise/opencv4/dog.jpeg");// 图像色彩空间转换用pig.jpg
if (img.empty())
{
cout << "请确认图像名称是否正确!" << endl;
return -1;
}
namedWindow("Original drawing", WINDOW_FREERATIO);
imshow("Original drawing", img);
QuickDemo qd;
//qd.colorSpace_Demo(img);//将原图转为HSV和GRAY图像显示并保存
//qd.operator_demo(img);//进行像素操作
//qd.teacking_bar_demo(img);//滚动条调整亮度
//qd.key_demo(img);//键盘输入响应
//qd.color_style_demo(img);//改变图像颜色风格
//qd.bitwise_demo(img);//图像像素逻辑操作
//qd.channels_demo(img);//图像分离与合并
//qd.inrange_demo(img); // 图像色彩空间转换
//qd.pixel_static_demo(img);//图像像素统计,最大最小值,均值方差
//qd.drawing_demo(img);//在图像中绘制几何图形
//qd.polyline_drawing_demo();//绘制多边形
//qd.mouse_drawing(img);使用鼠标绘制矩形
//qd.norm_demo(img);//像素类型转换与归一化
//qd.resize_demo(img);//图像放缩
//qd.flip_demo(img);//图像翻转
//qd.rotate_demo(img);//图像旋转
qd.video_demo(img);//使用摄像头
waitKey(0);
}
(注意:图片路径根据具体实际进行导入),可逐个调用各个类成员函数,进行OpenCv的学习。
quickopencv.cpp
#include "quickopencv.h"
#include
void QuickDemo::colorSpace_Demo(Mat& image)
{
Mat gray, hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);//HSV分别表示色度、饱和度和亮度
cvtColor(image, gray, COLOR_BGR2GRAY);
imshow("HSV drawing", hsv);
imshow("GRAY drawing", gray);
imwrite("D:/exercise/opencv4/HSVdog.jpeg", hsv);
imwrite("D:/exercise/opencv4/GRAYdog.jpeg", gray);
}
void QuickDemo::operator_demo(Mat& image)
{
//加减乘除可以用,add()、subtract()、multiply()、divide()
Mat dst;
dst = image + Scalar(50, 50, 50);//这种情况下,对每个像素进行操作,像素值超过255会截断,值就为255
imshow("加法操作",dst);//减法同理,在这不做展示了
dst = image / Scalar(2, 2, 2);
imshow("除法操作", dst);
multiply(image, Scalar(2, 2, 2), dst);
imshow("乘法操作", dst);//乘法,像素值超过255会截断,值就为255
}
//滑动条改变图像亮度--------------------------------------------------------------
int lightness;
static void callBack(int b, void* usedata)
{
Mat img = *((Mat*)usedata);
float a = lightness / 100.0;
Mat img1 = img * a;
imshow("滑动条改变亮度", img1);
}
void QuickDemo::teacking_bar_demo(Mat& image)
{
namedWindow("滑动条改变亮度",WINDOW_AUTOSIZE);
int max_value = 100;//亮度最大值为100
int contrast_value = 2;
lightness = 50;//当前亮度默认值
//创建亮度滑动条
createTrackbar("亮度百分比", "滑动条改变亮度", &lightness, max_value, callBack, (void*)(&image));
//callBack(0, (void*)&image);
}
//----------------------------------------------------------------------------------
void QuickDemo::key_demo(Mat& image)
{
Mat dst;
while (true)
{
int c = waitKey(100);//Waitkey函数会有一个返回值,是返回ascii码值的
if (c == 27)//按esc键退出
{
break;
}
//键盘按1时,转换为灰度图像并显示
if (c == 49)
{
std::cout << "You enyer key #1,Convert image to grayscale" << std::endl;
cvtColor(image, dst, COLOR_BGR2GRAY);
imshow("按1转换为灰度",dst);
}
}
}
//利用ColormapTypes,进行颜色风格变化
void QuickDemo::color_style_demo(Mat& image)
{
int colormap[] = { COLORMAP_AUTUMN ,COLORMAP_BONE ,COLORMAP_JET ,COLORMAP_WINTER ,COLORMAP_RAINBOW ,
COLORMAP_OCEAN ,COLORMAP_SUMMER ,COLORMAP_SPRING ,COLORMAP_COOL ,COLORMAP_HSV, COLORMAP_PINK ,COLORMAP_HOT ,
COLORMAP_PARULA ,COLORMAP_MAGMA ,COLORMAP_INFERNO ,COLORMAP_PLASMA ,COLORMAP_VIRIDIS ,COLORMAP_CIVIDIS ,
COLORMAP_TWILIGHT ,COLORMAP_TWILIGHT_SHIFTED ,COLORMAP_TURBO ,COLORMAP_DEEPGREEN };
Mat dst;
int index = 0;
while (true)
{
int c = waitKey(2000);//Waitkey函数会有一个返回值,是返回ascii码值的
if (c == 27)//按esc键退出
{
break;
}
applyColorMap(image,dst, colormap[index++ % 21]);
imshow("颜色风格变化", dst);
}
}
void QuickDemo::bitwise_demo(Mat& image)
{
Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1,LINE_8,0);//-1小于0是填充
rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
imshow("m1", m1);
imshow("m2", m2);
//进行逻辑运算
Mat myAnd, myOr, myXor, myNot;
bitwise_not(m1, myNot);
bitwise_and(m1, m2, myAnd);
bitwise_or(m1, m2, myOr);
bitwise_xor(m1, m2, myXor);
imshow("myAnd", myAnd);
imshow("myOr", myOr);
imshow("myXor", myXor);
imshow("myNot", myNot);
}
void QuickDemo::channels_demo(Mat& image)
{
std::vector imgv;
split(image, imgv);
imshow("分离蓝色", imgv.at(0)); //或者用imgv[0],显示分离后B
imshow("分离绿色", imgv.at(1)); //或者用imgv[1],显示分离后G
imshow("分离红色", imgv.at(2)); //或者用imgv[2],显示分离后R
Mat dst;
imgv.at(1) = 0;
imgv.at(2) = 0;
merge(imgv, dst); //合并图像
imshow("合并蓝色", dst);
}
void QuickDemo::inrange_demo(Mat& image)
{
Mat hsv;
cvtColor(image, hsv, COLOR_BGR2HSV);
Mat mask;
inRange(hsv,Scalar(35,43,46),Scalar(77,255,255),mask);
imshow("mask", mask);
Mat redback = Mat::zeros(image.size(), image.type());
redback = Scalar(40, 40, 200);
bitwise_not(mask, mask);
imshow("mask", mask);
image.copyTo(redback, mask);
imshow("roi区域提取", redback);
}
void QuickDemo::pixel_static_demo(Mat& image)
{
double minVal, maxVal; //用于存放矩阵中的最大值和最小值
Point minIdx, maxIdx; //用于存放矩阵中的最大值和最小值在矩阵中的位置
Mat imgs_re = image.reshape(1, 0); //将多通道矩阵变成单通道矩阵
minMaxLoc(imgs_re, &minVal, &maxVal, &minIdx, &maxIdx);
std::cout << "img中最大值是:" << maxVal << " " << "在矩阵中的位置:" << maxIdx << std::endl;
std::cout << "img中最小值是:" << minVal << " " << "在矩阵中的位置:" << minIdx << std::endl;
std::cout << "/* 用meanStdDev同时求取图像的均值和标准差 */" << std::endl;
Mat myMeanMat, myStddevMat;
meanStdDev(image, myMeanMat, myStddevMat);
std::cout << "img均值=" << myMeanMat << " " << std::endl;
std::cout << "img标准差=" << myStddevMat << std::endl ;
}
void QuickDemo::drawing_demo(Mat& image)
{
//绘制矩形
//rectangle(image, Point(200, 200), Point(300, 300), Scalar(125, 125, 125), -1);//-1为填充
rectangle(image,Rect(400,450,100,150), Scalar(0, 125, 125), 2);//2为线宽,不填充
Mat bg = Mat::zeros(image.size(), image.type());
rectangle(bg, Point(200, 200), Point(300, 300), Scalar(0, 0, 255), -1);
Mat dst;
addWeighted(image, 0.7, bg, 0.3, 0, dst);
imshow("dst", dst);
//绘制圆
circle(image, Point(100, 100), 50, Scalar(255, 255, 255), 3);
//绘制直线
line(image, Point(50, 50), Point(50, 200),Scalar(255,0,0), 2, LINE_4, 0);
//绘制椭圆
//这里的RotatedRect参数表示,中心点,长轴短轴,旋转角度
ellipse(image, RotatedRect(Point2f(300, 300), Size2f(200, 100), 0), Scalar(0, 255, 255), 2);
imshow("形状绘制", image);
}
void QuickDemo::polyline_drawing_demo()
{
//绘制多边形
Mat img = Mat::zeros(Size(512, 512), CV_8UC3); //生成一个黑色图像用于绘制几何图形
Point pp[2][6];
pp[0][0] = Point(72, 200);
pp[0][1] = Point(142, 204);
pp[0][2] = Point(226, 263);
pp[0][3] = Point(172, 310);
pp[0][4] = Point(117, 319);
pp[0][5] = Point(15, 260);
pp[1][0] = Point(359, 339);
pp[1][1] = Point(447, 351);
pp[1][2] = Point(504, 349);
pp[1][3] = Point(484, 433);
pp[1][4] = Point(418, 449);
pp[1][5] = Point(354, 402);
Point pp2[5];
pp2[0] = Point(350, 83);
pp2[1] = Point(463, 90);
pp2[2] = Point(500, 171);
pp2[3] = Point(421, 194);
pp2[4] = Point(338, 141);
const Point* pts[3] = { pp[0],pp[1],pp2 }; //pts变量的生成
int npts[] = { 6,6,5 }; //顶点个数数组的生成
fillPoly(img, pts, npts, 3, Scalar(125, 125, 125), 8); //绘制3个多边形,填充
//---------------------------------------------------------
Point p1(100, 100);
Point p2(350, 100);
Point p3(450, 280);
Point p4(320, 450);
Point p5(80, 400);
std::vector ptt;
ptt.push_back(p1);
ptt.push_back(p2);
ptt.push_back(p3);
ptt.push_back(p4);
ptt.push_back(p5);
polylines(img, ptt, true, Scalar(0, 0, 255), 2, 8, 0);
imshow("绘制多边形", img);
}
//鼠标响应,绘制矩形------------------------------------------------------
Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void on_draw(int event,int x,int y,int flags,void* userdata)
{
Mat img = *((Mat*)userdata);
if (event == EVENT_LBUTTONDOWN)
{
sp.x = x;
sp.y = y;
std::cout << "start point." << sp << std::endl;
}
else if (event == EVENT_LBUTTONUP)
{
ep.x = x;
ep.y = y;
std::cout << "start point." << ep << std::endl;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0)
{
Rect box(sp.x, sp.y, dx, dy);
rectangle(img, box, Scalar(0, 125, 125), 2,8,0);//2为线宽,不填充
imshow("鼠标绘制矩形", img);
//imshow("ROI区域",img(box));
//为下一次绘制做准备
sp.x = -1;
sp.y = -1;
}
}
else if (event == EVENT_MOUSEMOVE)
{
if (sp.x > 0 && sp.y > 0)
{
ep.x = x;
ep.y = y;
std::cout << "start point." << ep << std::endl;
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
if (dx > 0 && dy > 0)
{
Rect box(sp.x, sp.y, dx, dy);
temp.copyTo(img);
rectangle(img, box, Scalar(0, 0, 255), 2, 8, 0);//2为线宽,不填充
imshow("鼠标绘制矩形", img);
}
}
}
}
void QuickDemo::mouse_drawing(Mat& image)
{
temp = image.clone();
namedWindow("鼠标绘制矩形",WINDOW_AUTOSIZE);
setMouseCallback("鼠标绘制矩形", on_draw,(void *)(&image));
imshow("鼠标绘制矩形", image);
}
//---------------------------------------------------------------------
void QuickDemo::norm_demo(Mat& image)
{
Mat dst;
std::cout << image.type() << std::endl;
image.convertTo(image, CV_32F);
std::cout << image.type() << std::endl;
normalize(image, dst, 1.0, 0, NORM_MINMAX);
std::cout << dst.type() << std::endl;
imshow("图像数据归一化", dst);
}
void QuickDemo::resize_demo(Mat& image)
{
Mat zoomin, zoomout;
int h = image.rows;
int w = image.cols;
resize(image, zoomin,Size(w/2,h/2),0,0,INTER_LINEAR);
imshow("zoomin", zoomin);
resize(image, zoomout, Size(w*1.2, h*1.2), 0, 0, INTER_LINEAR);
imshow("zoomout", zoomout);
}
void QuickDemo::flip_demo(Mat& image)
{
Mat img_x, img_y, img_xy;
//数值大于0,表示绕 y 轴进行翻转;数值等于 0 ,表示绕 x 轴进行翻转;数值小于 0 ,表示绕两个轴旋转
flip(image, img_x, 0); //沿x轴对称
flip(image, img_y, 1); //沿y轴对称
flip(image, img_xy, -1); //先x轴对称,再y轴对称
imshow("img_x", img_x);
imshow("img_y", img_y);
imshow("img_xy", img_xy);
}
void QuickDemo::rotate_demo(Mat& image)
{
Mat rotation0, rotation1, img_warp0, img_warp1, dst;
double angle = 30; //设置图像旋转的角度
Size dst_size(image.rows, image.cols); //设置输出图像的尺寸
Point2f center(image.rows / 2.0, image.cols / 2.0); //设置图像的旋转中心
rotation0 = getRotationMatrix2D(center, angle, 1); //计算仿射变换矩阵
warpAffine(image, img_warp0, rotation0, dst_size, INTER_LINEAR, 0, Scalar(255, 0, 0)); //进行仿射变换
imshow("旋转演示", img_warp0);
//计算变换后的矩阵大小
double cosx = abs(rotation0.at(0,0));
double sinx = rotation0.at(0, 1);
int nw = cosx * image.cols + sinx * image.rows;
int nh = sinx * image.cols + cosx * image.rows;
rotation0.at(0, 2) = rotation0.at(0, 2)+(nw/2- image.cols /2);
rotation0.at(1, 2) = rotation0.at(1, 2) + (nh / 2 - image.rows / 2);
warpAffine(image, dst, rotation0, Size(nw, nh), INTER_LINEAR, 0, Scalar(225, 125, 0)); //进行仿射变换
imshow("旋转演示(计算变换后尺寸)", dst);
}
void QuickDemo::video_demo(Mat& image)
{
Mat frame;
VideoCapture capture(0);
while (true)
{
if (!capture.isOpened()) //判断是否调用成功
{
std::cout << "打开摄像头失败,请确认摄像头是否安装成功";
break;
}
capture.read(frame);
if (frame.empty()) //判断读取图像是否成功
{
std::cout << "没有获取到图像" << std::endl;
break;
}
imshow("frame", frame);
char c = waitKey(10);
if (c == 27) //ESC键退出
{
break;
}
}
}
上述文件是对类中各个成员函数的实现,一个知识点对应一个成员函数。
quickopencv.h
#pragma once
#include
using namespace cv;
class QuickDemo
{
public:
void colorSpace_Demo(Mat& image);//将原图转为HSV和GRAY图像显示并保存
void operator_demo(Mat& image);//进行像素操作,加减乘除
void teacking_bar_demo(Mat& image);//滚动条调整亮度
void key_demo(Mat &image);//键盘输入响应
void color_style_demo(Mat& image);//改变图像颜色风格
void bitwise_demo(Mat& image);//像素逻辑运算
void channels_demo(Mat& image);//通道分离与合并
void inrange_demo(Mat& image);//图像色彩空间转换
void pixel_static_demo(Mat& image);//图像像素统计,最大最小值,均值方差
void drawing_demo(Mat& image);//在图像中绘制几何图形
void polyline_drawing_demo();//绘制多边形
void mouse_drawing(Mat& image);//鼠标响应,绘制矩形
void norm_demo(Mat& image);//像素类型转换与归一化
void resize_demo(Mat& image);//图像放缩
void flip_demo(Mat& image);//图像翻转
void rotate_demo(Mat& image);//图像旋转
void video_demo(Mat& image);
private:
};
上述文件主要内容是QuickDemo类的声明。
OpenCv C++目前网上的视频课程质量均较差,最好的学习还是结合OpenCv官方文档和百度,进行学习。