OpenCV基础应用20例
Posted 啥都想干好&&啥都干不好
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV基础应用20例相关的知识,希望对你有一定的参考价值。
本人呢,是一位大二的学生,前几天参加全国大学生智能制造挑战赛——企业命题方向,有幸取得全国初赛第一名,本来在8月15号就要进行比赛了。但是为了响应国家疫情防控,赛方也是决定延期比赛。于是现在我就在家休息了;闲暇之余呢就看了一下Opencv的教程,之前呢我其实没有涉及人工智能这一块,主要一直在学习linux系统开发,和驱动开发这一块,但是由于比赛需要,并且最近人工智能实在太火。我就也来学习了。本人菜鸡一名,还望CSDN上的大佬们多发文章,让我们菜鸟们也能学习学习。
本人仅仅是把CSDN当作自己的笔记,同时也鼓励一下自己的学习,同时也能帮助需要帮助的人。
/*********************************************************
* Mat的基本用法
**********************************************************/
void my_test01(void) {
//一切图像皆Mat
Mat src = imread("D:/图片/519期/my_prc.jpg");
Mat mat1 = src.clone(); //深拷贝
Mat mat2;
src.copyTo(mat2); //深拷贝
Mat mat3 = src; //赋值只是让mat3指向src,并没有拷贝一份,应该是引用;
Mat mat4 = Mat::zeros(src.size(),src.type());
Mat mat5 = Mat::zeros(Size(512,512), CV_8UC3); //CV_8UC3无符号的八位三通道的图片,每一个像素点由三个8位无符号的数表示
Mat mat6 = Mat::ones(Size(512, 512), CV_8UC3); //初始化每个像素点为一
Mat kernel = (Mat_<char>(3,3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0); //以矩阵的方式创建图片
std::cout << "width:"<<mat5.cols<<std::endl; //获取图片的宽度
std::cout << "height:" << mat5.rows << std::endl; //获取图片的高度
std::cout << "channels:" << mat5.channels() << std::endl; //获取图片的通道数
mat5 = Scalar(100,100,100); //分别给每个通道赋值100;
}
/*********************************************************
* Mat对象的遍历方法
**********************************************************/
void my_test02(void) {
Mat mat = Mat::zeros(Size(512, 512), CV_8UC1);
mat = Scalar(100); //分别给每个通道赋值100;
imshow("test02", mat);
int w = mat.cols;
int h = mat.rows;
int ch = mat.channels();
#if 0
//使用数组的方法进行操作,效率更高
for (int row = 0; row < h; row++){
for (int col = 0; col < w; col++) {
if (ch == 1) { //灰度图像处理
uchar pv = mat.at<uchar>(row, col);
mat.at<uchar>(row, col) = 255 - pv; //图像颜色取反
}
else if (ch == 3) { //彩色图像处理
Vec3b bgr = mat.at<Vec3b>(row, col); //Vec3b专门保存三个通道的数据类型
mat.at<Vec3b>(row, col)[0] = 255 - bgr[0]; //图像颜色取反
mat.at<Vec3b>(row, col)[1] = 255 - bgr[1]; //图像颜色取反
mat.at<Vec3b>(row, col)[2] = 255 - bgr[2]; //图像颜色取反
}
}
}
#endif
#if 1
//使用指针的方法进行操作,效率更高
for (int row = 0; row < h; row++) {
uchar* current_row = mat.ptr<uchar>(row);
for (int col = 0; col < w; col++) {
if (ch == 1) { //灰度图像处理
*current_row++ = 255 - *current_row; //图像颜色取反
}
else if (ch == 3) { //彩色图像处理
*current_row++ = 255 - *current_row; //图像颜色取反
*current_row++ = 255 - *current_row; //图像颜色取反
*current_row++ = 255 - *current_row; //图像颜色取反
}
}
}
#endif
imshow("test03", mat);
waitKey(0); //有按键事件触发就继续执行
}
/*********************************************************
* Mat的算数操作
**********************************************************/
void my_test03(void) {
Mat src = Mat::zeros(Size(512, 512), CV_8UC3);
src = Scalar(100,150,200);
Mat src2 = Mat::zeros(Size(512, 512), CV_8UC3);
src2 = Scalar(2, 2, 2);
Mat dst;
//dst = src + Scalar(2,2,2); //加运算,add()
//dst = src - Scalar(2, 2, 2); //减运算,subtract()
multiply(src, src2, dst); //乘法运算
//divide(src, src2, dst); //除法运算
//saturate_cast<uchar>(ch1+ch2); //saturate_cast<>()可以保证后面括号内数据运算后的范围还在所定义类型范围之内
imshow("test04", src);
imshow("test05", dst);
waitKey(0); //有按键事件触发就继续执行
}
/*********************************************************
* 滚动条回调函数
**********************************************************/
static void on_track(int b,void *userdata) {
Mat image = *((Mat*)userdata);
Mat m = Mat::zeros(image.size(), image.type());
Mat dst1 = Mat::zeros(image.size(), image.type());
m = Scalar(b, b, b);
subtract(image,m,dst1);
//namedWindow("test_opencv_track2", CV_WINDOW_AUTOSIZE);
imshow("test_opencv_track1", dst1);
}
/*********************************************************
* Mat的GUI编程,方便调试通过滚动条调节亮度
**********************************************************/
void my_test04(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
namedWindow("test_opencv_track1", CV_WINDOW_AUTOSIZE); //生成一个窗口,大小与图片一致
//imshow("test_opencv_track", src); //在指定窗口展示图片
int lightness = 50;
int max_value = 100;
//滚动条创建函数,1.滚动条名称。2.滚动条所在窗口3.传递的一个参数4.滚动条最大值5.回调函数6.第二个传递参数
createTrackbar("Value Bar","test_opencv_track1",&lightness, max_value,on_track,(void*)(&src));
on_track(50,&src); //调用回调函数
waitKey(0); //有按键事件触发就继续执行
}
/*********************************************************
* 按键的使用
**********************************************************/
void my_test05(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
namedWindow("test_opencv_key", CV_WINDOW_AUTOSIZE);
imshow("test_opencv_key", src);
while (true)
{
int c = waitKey(100); //Opencv使用的键值是ASCII码,必须要在Opencv创建的窗口上按才有效果;
//100 是按键等待时间100ms
if (c == 27)
{
break;
}
else if (c == 49)
{
std::cout << "您按下了 # 1"<< std::endl;
}
std::cout << c << std::endl;
}
}
/*********************************************************
* Opencv颜色表的使用
**********************************************************/
void my_test06(void) {
int color_style[] = { //Opencv支持的所有颜色风格
COLORMAP_AUTUMN , //!< ![autumn](pics/colormaps/colorscale_autumn.jpg)
COLORMAP_BONE , //!< ![bone](pics/colormaps/colorscale_bone.jpg)
COLORMAP_JET , //!< ![jet](pics/colormaps/colorscale_jet.jpg)
COLORMAP_WINTER , //!< ![winter](pics/colormaps/colorscale_winter.jpg)
COLORMAP_RAINBOW , //!< ![rainbow](pics/colormaps/colorscale_rainbow.jpg)
COLORMAP_OCEAN , //!< ![ocean](pics/colormaps/colorscale_ocean.jpg)
COLORMAP_SUMMER , //!< ![summer](pics/colormaps/colorscale_summer.jpg)
COLORMAP_SPRING , //!< ![spring](pics/colormaps/colorscale_spring.jpg)
COLORMAP_COOL , //!< ![cool](pics/colormaps/colorscale_cool.jpg)
COLORMAP_HSV , //!< ![HSV](pics/colormaps/colorscale_hsv.jpg)
COLORMAP_PINK , //!< ![pink](pics/colormaps/colorscale_pink.jpg)
COLORMAP_HOT , //!< ![hot](pics/colormaps/colorscale_hot.jpg)
COLORMAP_PARULA //!< ![parula](pics/colormaps/colorscale_parula.jpg)
};
//applyColorMap();
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
namedWindow("test_opencv_key", CV_WINDOW_AUTOSIZE);
imshow("test_opencv_key", src);
Mat dst = Mat::zeros(src.size(), src.type());
while (true)
{
int c = waitKey(100); //Opencv使用的键值是ASCII码,必须要在Opencv创建的窗口上按才有效果;
//100 是按键等待时间100ms
if (c == 27)
{
break;
}
else if (c == 49)
{
applyColorMap(src, dst, COLORMAP_JET);
}
imshow("test_opencv_key", dst);
}
}
/*********************************************************
* Opencv的位操作、与或非
**********************************************************/
void my_test07(void) {
Mat mat1 = Mat::zeros(Size(256, 256), CV_8UC3);
Mat mat2 = Mat::zeros(Size(256, 256), CV_8UC3);
rectangle(mat1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0); //绘制矩形Rect()矩形大小和位置,Scalar()矩形颜色,-1实心填充,大于0的表示边框的宽度
rectangle(mat2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
Mat dst;
//namedWindow("mat1", CV_WINDOW_AUTOSIZE);
//namedWindow("mat2", CV_WINDOW_AUTOSIZE);
imshow("mat1", mat1);
imshow("mat2", mat2);
//bitwise_and(mat1, mat2, dst); //对图像的三个通道取交集;
//bitwise_or(mat1, mat2, dst); //对图像的三个通道取并集;
bitwise_not(mat1, dst); //对图像的三个通道取非;
//bitwise_xor(mat1, mat2, dst); //对图像的三个通道取交集;
imshow("dst", dst);
waitKey(0); //有按键事件触发就继续执行
}
/*********************************************************
* Opencv通道的分离与合并
* 三个通道其实就是三种颜色的灰度图像
**********************************************************/
void my_test08(void) {
//通道分离
std::vector<Mat> mv;
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
split(src, mv); //通道分离API
imshow("原图", src);
imshow("蓝色", mv[0]);
imshow("绿色", mv[1]);
imshow("红色", mv[2]);
Mat dst;
mv[0] = 0;
//mv[1] = 0;
merge(mv, dst); //通道合并API
imshow("红色1", dst);
int from_to[] = {0,2,1,1,2,0}; //用于指明通道混合的方式,那个通道和那个通道交换;
mixChannels(&src, 1,&dst, 1, from_to, 3); //通道调换API
imshow("通道混合", dst);
waitKey(0); //有按键事件触发就继续执行
}
/*********************************************************
* Opencv图像空间转化,人物识别
* HSV色彩空间,色调(H),饱和度(S),明度(V)
**********************************************************/
void my_test09(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Mat hsv;
cvtColor(src, hsv,COLOR_BGR2HSV);
Mat mask;
inRange(hsv,Scalar(20,20,20), Scalar(200,200,150),mask); //色彩二值化操作,1.输入的HSV格式的图片2.HSV颜色的下限3.HSV颜色的上限4.输出的RGB图片
imshow("色彩空间", mask);
Mat dst;
src.copyTo(dst,mask); //把mask中像素值不为一的部分从src中拷贝到dst中,精髓所在
waitKey(0); //有按键事件触发就继续执行
}
/*********************************************************
* Opencv图像像素值统计,均值,方差等
**********************************************************/
void my_test10(void) {
std::vector<Mat> mv;
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
double minv, maxv;
Point minloc, maxloc;
split(src, mv);
for (int i = 0; i < mv.size(); i++)
{
minMaxLoc(mv[i], &minv, &maxv, &minloc, &maxloc);
std::cout <<"通道数:" <<i << " minv: " << minv << " maxv: " << maxv << std::endl;
}
Mat mean, stddev;
meanStdDev(src, mean, stddev);
std::cout << "均值: " << mean <<"\\n" << "方差: " << stddev << std::endl;
std::cout << "均值: " << mean.at<double>(2,0) << std::endl; //单独输出每个通道的值
//mean.at<double>(2,0), 第一个是通道数,第二个是0固定
}
/*********************************************************
* Opencv图像几何形状的绘制
**********************************************************/
void my_test11(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Rect rect;
rect.x = 100;
rect.y = 100;
rect.width = 300;
rect.height = 300;
//rectangle(src, rect, Scalar(0, 0, 255), 3, 8, 0); //绘制矩形
//circle(src, Point(350,400), 15, Scalar(255 ,0 ,0), 3 , 8, 0); //绘制圆形
Mat dst;
Mat bg = Mat::zeros(src.size(), src.type());
line(bg , Point(100, 100), Point(400, 400), Scalar(255, 0, 255), 4, 8, 0);
rectangle(bg, rect, Scalar(0, 255, 0), -1, 8, 0); //绘制实心矩形
addWeighted(src , 0.7, bg, 0.3, 0, dst); //对两张照片进行合并,并设置透明度
imshow("形状绘制", dst);
}
/*********************************************************
* Opencv像素类型转化于归一化
**********************************************************/
void my_test12(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Mat dst;
std::cout << "数据类型1: " << src.type()<< std::endl;
src.convertTo(src,CV_32F); //数据类型转化 CV_32F转化成32位的浮点数据,CV_32S 转化成32位的整型数据
std::cout << "数据类型2: " << src.type() << std::endl;
normalize(src, dst, 1.0,0, NORM_MINMAX); //数据归一化处理,转化成浮点数据后必须进行归一化处理之后才能正常显示
std::cout << "数据类型3: " << dst.type() << std::endl;
imshow("归一化处理", dst);
}
/*********************************************************
* Opencv图像的放缩与插值
**********************************************************/
void my_test13(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Mat zoomin, zoomax;
int h = src.rows;
int w = src.cols;
resize(src, zoomin, Size(w/2,h/2), 0, 0, INTER_LINEAR); //图像的放大 INTER_LINEAR 计算方式,还有很多方式,这是最简单的一种
imshow("图像的缩小:", zoomin);
resize(src, zoomax, Size(w*1.5, h*1.5), 0, 0, INTER_LINEAR);
imshow("图像的放大:", zoomax);
}
/*********************************************************
* Opencv图像的翻转
**********************************************************/
void my_test14(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Mat dst;
flip(src, dst, 0); //上下镜像
//flip(src, dst, 1); //左右镜像
//flip(src, dst, -1); //旋转180°
imshow("图像反转:", dst);
}
/*********************************************************
* Opencv图像的旋转
**********************************************************/
void my_test15(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Mat M, dst;
int h = src.rows;
int w = src.cols;
M = getRotationMatrix2D(Point2f(w/2, h/2), 45,1.0); //先用一个模板旋转45°
//计算旋转后新的宽高
double cos = abs(M.at<double>(0, 0));
double sin = abs(M.at<double>(0, 1));
int nw = cos * w + sin * h;
int nh = sin * w + cos * h;
M.at<double>(0, 2) += (nw / 2 - w / 2);
M.at<double>(1, 2) += (nh / 2 - h / 2);
warpAffine(src, dst, M, Size(nw, nh), INTER_LINEAR, 0, Scalar(255, 200, 100)); //图片旋转API
imshow("旋转演示", dst);
}
/*********************************************************
* Opencv视频的读取
**********************************************************/
void my_test16(void) {
VideoCapture capture(0); //定义一个视频对象从摄像头中读取图像信息
//VideoCapture capture("D:/图片/opencv_prc/马里奥.jpg"); //放入一个视频文件的路径也可以
Mat frame;
while (true)
{
capture.read(frame);
flip(frame, frame, 1);
if (frame.empty())
{
break;
}
imshow("frame",frame);
int c = waitKey(1);
if (c == 27)
{
break;
}
}
capture.release(); //手动释放相机
}
/*********************************************************
* Opencv视频的属性
**********************************************************/
void my_test17(void) {
VideoCapture capture("D:/文件/非标擂台格斗/初赛作品/驭梦队作品视频.mp4"); //定义一个视频对象从摄像头中读取图像信息
int frame_w = capture.get(CAP_PROP_FRAME_WIDTH); //宽度
int frame_h = capture.get(CAP_PROP_FRAME_HEIGHT); //高度
int frame_zhen = capture.get(CAP_PROP_FRAME_COUNT); //总共多少张图片
double fps = capture.get(CAP_PROP_FPS); //帧率,每秒多少张图片
std::cout << " frame_w: " << frame_w << " frame_h: " << frame_h << " frame_zhen: " << frame_zhen << " fps: " << fps << std::endl;
VideoWriter writer("D:/图片/opencv_prc/my_Opencv.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_w, frame_h), true); //保存视频初始化函数,指明路径,要保存的视频,以及大小
Mat frame;
while (true)
{
capture.read(frame);
//flip(frame, frame, 1); //以X轴翻转视频
if (frame.empty())
{
break;
}
writer.write(frame); //一帧一帧的对图片进行保存,就是视频
imshow("frame", frame);
int c = waitKey(1);
if (c == 27)
{
break;
}
}
capture.release(); //手动释放相机
writer.release(); //手动释放保存
}
/*********************************************************
* Opencv图像直方图,每个通道上,每个灰度值有多少个点
* 一个图像平移,旋转,放大缩小,直方图数据都不会变,但是不能唯一表示图片;
**********************************************************/
void my_test18(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
imshow("原图", src);
//通道分离
std::vector<Mat> bgr_plane;
split(src, bgr_plane);
//设置基本参数
const int channels[1] = { 0 };
const int bins[1] = { 256 }; //分成多少份,X轴
float hranges[2] = { 0, 255 }; //第一个通道的取值范围
const float* ranges[1] = { hranges };
//定义存储对象
Mat b_hist;
Mat g_hist;
Mat r_hist;
//统计像素点个数
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges); //倒数第三个数,表示通道数
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
//画布大小定义
int hist_w = 700;
int hist_h = 550;
int bin_W = cvRound((double)hist_w / bins[0]);
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
//图像值归一化处理
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
//绘制直方图
for (int i = 1; i < bins[0]; i++)
{
line(histImage, Point(bin_W * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_W * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_W * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_W * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_W * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_W * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
}
//显示直方图
namedWindow("图像直方图", WINDOW_AUTOSIZE);
imshow("图像直方图", histImage);
}
/*********************************************************
* Opencv二维直方图,HSV色彩空间
**********************************************************/
void my_test19(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Mat hsv, hs_hist;
cvtColor(src, hsv, COLOR_BGR2HSV); //转化色彩空间
int hbins = 30, sbins = 32;
int hist_bins[] = { hbins, sbins };
float h_range[] = { 0, 180 };
float s_range[] = { 0, 256 };
const float* hs_ranges[] = { h_range , s_range };
int hs_channels[] = { 0, 1 };
calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, true); //计算直方图数据
double maxVal = 0;
minMaxLoc(hs_hist, 0, &maxVal, 0, 0); //计算出最大值
int scale = 10;
Mat hist2d_image = Mat::zeros(sbins * scale, hbins * scale, CV_8UC3);
for (int h = 0; h < hbins; h++) //绘制2D直方图
{
for (int s = 0; s < sbins; s++)
{
float binVal = hs_hist.at<float>(h, s);
int intensity = cvRound(binVal * 255 / maxVal);
rectangle(hist2d_image, Point(h * scale, s * scale),
Point((h + 1) * scale - 1, (s + 1) * scale - 1),
Scalar::all(intensity), -1);
}
}
applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET); //把灰度图转化为彩色图
imshow("2D直方图", hist2d_image);
imwrite("D:/图片/opencv_prc/2D直方图.png", hist2d_image); //保存图片
}
/*********************************************************
* Opencv直方图均衡化
**********************************************************/
void my_test20(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
Mat dst;
cvtColor(src, dst, COLOR_BGR2GRAY);
imshow("直方图均衡化之前", dst);
equalizeHist(dst, dst); //均衡化API
imshow("直方图均衡化之后", dst);
}
/*********************************************************
* Opencv图像的线性卷积操作:图像对比度减小,变模糊
**********************************************************/
void my_test21(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
imshow("图像模糊之前", src);
Mat dst;
blur(src, dst, Size(10, 10), Point(-1, -1)); //卷积API
imshow("图像模糊之后", dst);
}
/*********************************************************
* Opencv的高斯模糊,中心卷积
**********************************************************/
void my_test22(void) {
Mat src = imread("D:/图片/opencv_prc/马里奥.jpg");
imshow("图像模糊之前", src);
Mat dst;
GaussianBlur(src, dst, Size(11, 11), 30); //Size()里面的值必须是奇数,最后一个数越大越模糊
imshow("图像模糊之后", dst);
}
以上是关于OpenCV基础应用20例的主要内容,如果未能解决你的问题,请参考以下文章