OpenCV基础学习

一:显示图像并保存

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;
int main() 
{

	Mat src = imread("D:/images/011.jpg",IMREAD_GRAYSCALE);//读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。
	if (src.empty()) 
	{
		printf("could not load image");//如果图片不存在 将无法读取,打印到终端。
	}
	//超过屏幕的图像无法显示时候调用此函数。
	namedWindow("输入窗口", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
	imshow("输入窗口", src);//表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat 
	waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位ms
	imwrite("E:\\QTFiles\\zhh1913021023\\example1_zhh\\test1.png",src);//保存图片,第一个参数是保存地址,第二个参数是对象
	destroyAllWindows();//销毁前面创建的显示窗口
	
	return 0;
}

二:色彩转换函数:cvtcolor

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

class QuickDemo //创建一个QuickDemo对象
{
	public:
		void colorSpace_Demo(Mat &imge); //定义一个类,里面包含输入一个图片,对图片操作
};

void QuickDemo::colorSpace_Demo(Mat &image)
{
	Mat gray, hsv;//定义2个矩阵类的图像gray和hsv,
	cvtColor(image,hsv,COLOR_BGR2HSV);//图像转换函数,可以把image转成hsv,第三个参数是转成的类型
	cvtColor(image,gray,COLOR_BGR2GRAY);//图像转换函数,可以把image转成hsv,第三个参数是转成的类型
	imshow("HSV",hsv);
	imshow("灰度",gray);
	imwrite("D:/hsv.jpg",hsv);//保存图片,前面是保存图的地址,后面是保存图的名称
	imwrite("D:/gray.jpg",gray);
}

int main() 
{

	Mat src = imread("D:/images/1.jpg",IMREAD_ANYCOLOR);//B,G,R实际上0-255三色。3通道
	//读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。
	if (src.empty()) 
	{
		printf("could not load image");//如果图片不存在 将无法读取,打印到终端。
		return -1;
	}
	//超过屏幕的图像无法显示时候调用此函数。
	
	namedWindow("输入窗口", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
	imshow("输入窗口", src);//表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat 
//在主函数中调用之前创建的类对象	
	QuickDemo qd;
	qd.colorSpace_Demo(src);

	waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位ms
	destroyAllWindows();//销毁前面创建的显示窗口
	return 0;
}

三:mat对象

通过创建新的Mat对象来创建用户的特定的底色画布,创建图像的基本类型有两种一种是ones一种是zeros,ones()中的第一个参数代表图像的大小,第二个参数代表创建几维的图像,UC代表无符号字符型,数组3代表通道数。克隆和赋值的区别,克隆就是产生一个新的对象,新对象改变属性,旧对象属性不变(各自为政)。赋值是二者同体,当新属性发生改变,旧属性也发生改变(二者同体)。

void QuickDemo::mat_creation_demo(Mat &image) 
{
	Mat m1, m2;
	m1 = image.clone();
	image.copyTo(m2);

	//创建空白图像
	Mat m3 = Mat::ones(Size(400, 400), CV_8UC3);//创建8*8的CV8位的无符号的n通道的unsigned char
	//ones&zeros是初始化的方法
	m3 = Scalar(255, 0, 0);//给三个通道都赋值127  ,单通道赋值方法 m3 = 127;
	//m3初始为蓝色
	//数据的宽度和长度是由通道数决定的。
	//std::cout << "width:"<<m3.cols<<"height"<< m3.rows <<"channels"<<m3.channels()<< std::endl;
	//用来查看宽度,高度与通道数。
	/*std::cout << m3 << std::endl;*/
	Mat m4 = m3.clone();//赋值M4就是M3 M4改变了,M3也改变了,没有产生新的自我(M4与M3同体)
	//M4为M3的克隆,M3还是原来的颜色,不会改变。(M4与M3不同体,各自是各自的颜色)
	//m3.copyTo(m4);//把M3赋值给M4,M4就是蓝色
	m4 = Scalar(0, 255, 255);//改变m4的颜色为黄色 ,m4也改变
	imshow("图像3", m3);//标题和图像名称   显示图像m3 纯蓝色
	imshow("图像4", m4);//标题和图像名称
}

mat对象的7种创建方式,分别创建灰度和彩色图像

         //方法1使用mat的构造函数
        //对于二维通道图像,首先要定义尺寸,即行数和列数。然后,需要指定存储元素的数据类型以及每个矩阵点的通道数。
        Mat image1(10,10,CV_8UC1,Scalar(0,255,255)); //灰度图像
        Mat image1_rgb(10,10,CV_8UC3,Scalar(0,255,255));   //彩色图像
        //方法2  通过构造函数进行初始化
        int sz[3]={10,10,10};
        Mat image2(2,sz,CV_8UC3,Scalar::all(0));     //灰度图像
         Mat image2_rgb(2,sz,CV_8UC1,Scalar::all(0)); //彩色图像

        //方法3为已存在的IplImage指针创建信息头
        IplImage *img = cvLoadImage("d:/image/melina.jpg",CV_8UC1);//灰度图像
        IplImage *img1 = cvLoadImage("d:/image/melina.jpg",CV_8UC3);//彩色图像
           Mat image3=cvarrToMat(img);///转换IplImage*->Mat
           Mat image3_rgb=cvarrToMat(img1);
        //方法4  利用Create()函数
           Mat image4,image4_rgb;
           image4.create(10,10,CV_8UC1);//灰度图像
           image4_rgb.create(10,10,CV_8UC3);//彩色图像
         //方法5 采用Matlab式的初始化方式
            Mat image5 = Mat::eye(10, 10,CV_8UC1);//灰度图像
            Mat image5_rgb=Mat::eye(10, 10,CV_8UC3);//彩色图像
         //方法6 对小矩阵使用逗号分隔式初始化函数
            Mat image6=(Mat_<unsigned char>(3,3)<<1,2,3,4,5,6,7,8,9,CV_8UC1);//灰度图像
            Mat image6_rgb=(Mat_<unsigned char>(3,3)<<1,2,3,4,5,6,7,8,9,CV_8UC3);//彩色图像
         //方法7 为已存在的对象创建新信息头,使用clone函数和copyto
           Mat image1_row=image1.row(1).clone(); //将image1的第一行赋值给image1_row
           Mat image1_row_rgb;
           image1_rgb.copyTo(image1_row_rgb);

四:图像像素读写

数组方式

void QuickDemo::pixel_visit_demo(Mat &image)
{
	int dims = image.channels();
	int h = image.rows;
	int w = image.cols;
	for (int row = 0; row < h; row++) 
	{
		for (int col = 0; col < w; col++) 
		{
			if (dims == 1) //单通道的灰度图像
			{
				int pv = image.at<uchar>(row, col);//得到像素值
				image.at<uchar>(row, col) = 255 - pv;//给像素值重新赋值

			}
			if (dims == 3) //三通道的彩色图像
			{
				Vec3b bgr = image.at<Vec3b>(row, col); //opencv特定的类型,获取三维颜色,3个值
				image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
				image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
				image.at<Vec3b>(row, col)[2] = 255 - bgr[2];//对彩色图像读取它的像素值,并且对像素值进行改写。
			}
		}
	}
	namedWindow("像素读写演示", WINDOW_FREERATIO);
	imshow("像素读写演示", image);
}

指针方式

void QuickDemo::pixel_visit_demo(Mat &image)
{
	int dims = image.channels();
	int h = image.rows;
	int w = image.cols;
	for (int row = 0; row < h; row++)
	{
		uchar *current_row = image.ptr<uchar>(row);

		for (int col = 0; col < w; col++)
		{
			if (dims == 1) //单通道的灰度图像
			{
				int pv = *current_row;//得到像素值
					*current_row++ = 255 - pv;//给像素值重新赋值

			}
			if (dims == 3) //三通道的彩色图像
			{
				*current_row++ = 255 - *current_row; //指针每做一次运算,就向后移动一位
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
			}
		}
	}
	namedWindow("像素读写演示", WINDOW_FREERATIO);
	imshow("像素读写演示", image);
	
}

五:图像像素操作:加减乘除

void QuickDemo::operators_demo(Mat &image)
{
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	dst = image - Scalar(50, 50, 50);
	m = Scalar(50, 50, 50);
	multiply(image,m,dst);//乘法操作 api
	imshow("乘法操作", dst);
	add(image, m, dst);//加法操作 api
	imshow("加法操作", dst);
	subtract(image, m, dst);//减法操作 api
	imshow("减法操作", dst);
	divide(image, m, dst);//除法操作 api
	namedWindow("加法操作", WINDOW_FREERATIO);
	imshow("加法操作", dst);
	//加法操作底层
	int dims = image.channels();
	int h = image.rows;
	int w = image.cols;
	for (int row = 0; row < h; row++)
	{
		for (int col = 0; col < w; col++)
		{
				Vec3b p1 = image.at<Vec3b>(row, col); //opencv特定的类型,获取三维颜色,3个值
				Vec3b p2 = m.at<Vec3b>(row, col);
				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0]	+ p2[0]);//saturate_cast用来防爆,小于0就是0,大于255就是255
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);//对彩色图像读取它的像素值,并且对像素值进行改写。
		}
	}
	imshow("加法操作", dst);
}

六:滚动条调节图片亮度

Mat  src, dst, m;
int lightness = 50;//定义初始的亮度为50
static void on_track(int ,void*) 
{
	m = Scalar(lightness,lightness,lightness);//创建调整亮度的数值
	subtract(src, m, dst);//定义亮度变化为减
	imshow("亮度调整", dst);//显示调整亮度之后的图片
}
void QuickDemo::tracking_bar_demo(Mat &image)
{
	namedWindow("亮度调整",WINDOW_AUTOSIZE);
	dst = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像
	m = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像
	src = image;//给src赋值
	int max_value = 100;//定义最大值为100
	createTrackbar("Value Bar:", "亮度调整", &lightness, max_value,on_track);//调用函数实现功能。
	on_track(50, 0);
}

可传参数

static void on_lightness(int b ,void* userdata) 
{
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(b,b,b);
	addWeighted(image,1.0,m,0,b,dst);//融合两张图
	imshow("亮度&对比度调整", dst);
}
static void on_contrast(int b, void* userdata)
{
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	double contrast = b / 100.0;
	addWeighted(image, contrast, m, 0.0, 0, dst);//融合两张图
	imshow("亮度&对比度调整", dst);
}
void QuickDemo::tracking_bar_demo(Mat &image)
{
	namedWindow("亮度&对比度调整",WINDOW_AUTOSIZE);
	int lightness = 50;
	int max_value = 100;
	int contrast_value = 100;
	createTrackbar("Value Bar:", "亮度&对比度调整", &lightness, max_value, on_lightness,(void*)(&image));
	createTrackbar("Contrast Bar:", "亮度&对比度调整", &contrast_value, 200, on_contrast, (void*)(&image));
	on_lightness(50, &image);
}

七:键盘响应

void QuickDemo::key_demo(Mat &image) 
{
	Mat dst= Mat::zeros(image.size(), image.type());
	while (true) 
	{
		char c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
		if (c == 49)//key#1
		{
			std::cout <<"you enter key #1" << std::endl;
			cvtColor(image, dst, COLOR_BGR2GRAY);
		}
		if (c == 50)//key#1
		{
			std::cout << "you enter key #2"  << std::endl;
			cvtColor(image, dst, COLOR_BGR2HSV);
		}
		if (c == 51)//key#1
		{
			std::cout << "you enter key #3" << std::endl;
			dst = Scalar(50, 50, 50);
			add(image,dst,dst);
		}
		imshow("键盘响应",dst);
		std::cout << c << std::endl;
	}
}

八:调用OpenCV自带颜色

void QuickDemo::color_style_demo(Mat &image) 
{
	int colormap[] = {
		COLORMAP_AUTUMN ,
		COLORMAP_BONE,
		COLORMAP_CIVIDIS,
		COLORMAP_DEEPGREEN,
		COLORMAP_HOT,
		COLORMAP_HSV,
		COLORMAP_INFERNO,
		COLORMAP_JET,
		COLORMAP_MAGMA,
		COLORMAP_OCEAN,
		COLORMAP_PINK,
		COLORMAP_PARULA,
		COLORMAP_RAINBOW,
		COLORMAP_SPRING,
		COLORMAP_TWILIGHT,
		COLORMAP_TURBO,
		COLORMAP_TWILIGHT,
		COLORMAP_VIRIDIS,
		COLORMAP_TWILIGHT_SHIFTED,
		COLORMAP_WINTER
	};
	
	Mat dst;
	int index = 0;
	while (true) 
	{
		char c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
		if (c == 49)//key#1 按下按键1时,保存图片到指定位置
		{
			std::cout << "you enter key #1" << std::endl;
			imwrite("D:/gray.jpg", dst);
		}
		applyColorMap(image, dst, colormap[index%19]);//循环展示19种图片
		index++;
		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是图片名称,参数2是矩形的起始&末尾位置,参数3 Scalar表示将要绘制图像的颜色,参数4表示小于0表示填充,大于0表示绘制,参数5表示四邻域或者八邻域的绘制,参数6表示中心坐标或者半径坐标的小数位数。
	rectangle(m2,Rect(150,150,80,80), Scalar(0,255,255), -1, LINE_8, 0);
	imshow("m1", m1);
	imshow("m2", m2);
	Mat dst;
	bitwise_and(m1, m2, dst);//位操作与
	bitwise_or(m1, m2, dst);//位操作或
	bitwise_not(image, dst);//取反操作
	bitwise_xor(m1, m2, dst);//异或操作
	imshow("像素位操作", dst);
}

十:通道的分离和合并

void QuickDemo::channels_demo(Mat &image)
{	
	std::vector<Mat>mv;
	split(image, mv);
	//imshow("蓝色", mv[0]);
	//0,1,2三个通道分别代表BGR。
	//关闭2个通道意味着开启一个通道。
	//imshow("绿色", mv[1]);
	//imshow("红色", mv[2]);
	Mat dst;
	mv[0] = 0;
	mv[2] = 0;
	merge(mv, dst);
	imshow("蓝色", dst);
	int from_to[] = { 0,2,1,1,2,0 };
	//把通道相互交换,第0->第2,第一->第一,第二->第0
	mixChannels(&image,1,&dst,1,from_to,3);//3表示3个通道
	//参数1指针引用图像->参数2引用到dst
	imshow("通道混合", dst);
}

十一:图像色彩空间转换

HSV色彩空间的颜色

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);
	//35,43,46根据图片中绿色最低来确定最小值。
	//77,255,255 提取
	//参数1低范围,参数2高范围
	//将hsv中的由低到高的像素点提取出来并且存储到mask当中。
	imshow("mask",hsv);
	Mat redback = Mat::zeros(image.size(), image.type());
	redback = Scalar(40, 40, 200);
	bitwise_not(mask, mask);
	imshow("mask", mask);
	image.copyTo(redback, mask);//把redback复制到mask,mask通过inRange得到。
	imshow("roi区域提取", redback);
}

十二:图像像素值统计

void QuickDemo::pixel_statistic_demo(Mat &image)
{
	double minv, maxv;//定义最值
	Point minLoc, maxLoc;//定义最值地址
	std::vector<Mat>mv;//mv是一个Mat类型的容器 装在这个容器内
	split(image, mv);
	for (int i = 0; i < mv.size(); i++) 
	{
		//分别打印各个通道的数值
		minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());//求出图像的最大值和最小值。
		std::cout <<"No.channels:"<<i<<"minvalue:" << minv << "maxvalue:" << maxv << std::endl;
	}
	Mat mean, stddev;
	meanStdDev(image, mean, stddev);//求出图像的均值和方差
	std::cout << "mean:" << mean << std::endl;
	std::cout << "stddev:" << stddev << std::endl;
}

十三:图像几何形状的绘制及文字的写入

void drawing_demo(Mat &image)
{
    Rect rect;
    rect.x = 400;
    rect.y = 200;
    rect.width = 100;
    rect.height = 100;
    Mat bg = Mat::zeros(image.size(),image.type());
    rectangle(bg, rect, Scalar(255, 0, 255), -1, 8, 0);
    //参数1为绘图的底图或者画布名称,参数2位图片的起始,宽度,高度
    //参数3代表填充颜色。参数4大于0是线小于0是填充
    //参数5表示邻域填充,参数6默认值为0
    circle(bg, Point(350, 400), 15, Scalar(0, 0, 255), 2, LINE_AA, 0);
    //参数2位图片中心位置,参数3为半径为15的圆
    Mat dst;
    //addWeighted(image, 0.7, bg, 0.3, 0, dst);
    RotatedRect rtt;
    rtt.center = Point(200, 200);
    rtt.size = Size(100, 200);
    rtt.angle = 0.0;
    line(bg,Point(100,100),Point(350,400), Scalar(0, 0, 255), 8, LINE_AA, 0);//line_AA表示去掉锯齿
    ellipse(bg,rtt, Scalar(0, 0, 255), 2, 8);

    putText(bg, "hello everyone", Point(bg.cols/2-200, bg.rows/2), CV_FONT_HERSHEY_COMPLEX, 1.0, Scalar(0, 255, 0), 8, LINE_8);

    imshow("drawing",bg);
}


#include <QCoreApplication>
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

Mat src_bgImg;
const char *draw_window = "show windows";
void DrawLine();//画线
void DrawRectangle();//画矩形
void DrawEllipse();//绘制椭圆
void DrawCircle();//  圆形
void DrawPolygon();//多边形
void DrawRandomLine();//画随机线


int main()
{
            src_bgImg = Mat::ones(500,500,CV_8UC3);

            DrawLine();
            DrawRectangle();
            DrawEllipse();
            DrawCircle();
            DrawPolygon();

            putText(src_bgImg,"zhenghonghui",Point(200,200),CV_FONT_HERSHEY_COMPLEX,1.0,Scalar(255,255,0),1,8);//绘制添加文字
            namedWindow(draw_window,CV_WINDOW_AUTOSIZE);
            imshow(draw_window,src_bgImg);
            DrawRandomLine();

            waitKey(0);
            return 0;
}

void DrawLine()// 线
{
    Point p1 = Point(100, 50);

    Point p2 = Point(300,300);
    Scalar color = Scalar(0,255,255);
    line(src_bgImg,p1,p2,color,3,LINE_8);//3表示线的粗细

}
//画矩形
void DrawRectangle()
{
    Rect rect = Rect(150,20,100,100);
    Scalar color = Scalar(255, 0, 255);
    rectangle(src_bgImg,rect,color,3,LINE_8);
}
void DrawEllipse()
{
    //(背景图像,椭圆的中心,椭圆的半径,角度,0,360,颜色,粗细,line的类型)
    //0:开始度数,360:结束的度数,也可以0-180,画成弧形,0-100度位置。等等
    Scalar color = Scalar(255, 0, 0);
    ellipse(src_bgImg,Point(src_bgImg.cols/2,src_bgImg.rows/2),Size(src_bgImg.cols/4,src_bgImg.rows/8),90,0,360,color,2,LINE_8);
}
void DrawCircle()
{
    Scalar color = Scalar(0, 255, 0);
    //定义圆形坐标
    Point center = Point(src_bgImg.cols/2,src_bgImg.rows/2);
    circle(src_bgImg,center,80,color,2,LINE_8);

}
void DrawPolygon()//多边形
{
    Scalar color = Scalar(255, 255, 0);
    Point pts[1][5];
    pts[0][0] = Point(100,100);
    pts[0][1] = Point(100, 200);
    pts[0][2] = Point(200, 200);
    pts[0][3] = Point(200, 100);
    pts[0][4] = Point(100, 100);
    const Point *ppts[] = {pts[0]};
    int npt[] = {5};
    fillPoly(src_bgImg,ppts,npt,1,color,8);//line_8也可以直接写成8
}
void DrawRandomLine()//画随机线
{
    RNG rng(12345);
    Point pt1;
    Point pt2;
    Mat bg_imgs = Mat::zeros(src_bgImg.size(),src_bgImg.type());
    namedWindow("randow_window",CV_WINDOW_AUTOSIZE);
    for (int i = 0; i < 20000; i++)
    {
        pt1.x = rng.uniform(0, src_bgImg.cols);
        pt2.x = rng.uniform(0, src_bgImg.cols);
        pt1.y = rng.uniform(0, src_bgImg.cols);
        pt2.y = rng.uniform(0, src_bgImg.cols);
        Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        if (waitKey(100)==27)//键盘 按 esc退出
        {
            break;
        }
        line(bg_imgs, pt1, pt2, color, 1, 8);
        imshow("randow_window", bg_imgs);
    }
}

十四:随机数和随机颜色

void QuickDemo::random_drawing()
{
	Mat canvas = Mat::zeros(Size(512,512), CV_8UC3);
	int w = canvas.cols;
	int h = canvas.rows;
	RNG rng(12345);
	while (true) 
	{
		int c = waitKey(10);
		if (c == 27) 
		{
			break;
		}
		int x1 = rng.uniform(0,canvas.cols);
		int y1 = rng.uniform(0, h);
		int x2 = rng.uniform(0, canvas.cols);
		int y2 = rng.uniform(0, h);
		int b  = rng.uniform(0, 255);
		int g  = rng.uniform(0, 255);
		int r  = rng.uniform(0, 255);
		canvas = Scalar(0,0,0);
		line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b,g,r), 8, LINE_AA,0);//line_AA表示去掉锯齿	
		imshow("随机绘制演示", canvas);
	}
}

十五:多边形填充和绘制

第一种方式,通过标记各个点,然后存储到容器中,之后对容器中的点进行操作。填充多边形调用fillPoly,绘制多边形调用polylines。第二种方式,使用一个API接口绘制。通过一个容器中的存储的点组成的另一个容器。

void QuickDemo::polyline_drawing_demo(Mat &image)
{
	Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
	Point p1(100, 100);
	Point p2(350, 100);
	Point p3(450, 280);
	Point p4(320, 450);
	Point p5(80, 400);
	std::vector<Point>pts;//将5个点装入一个容器内。
	pts.push_back(p1);//未初始化数组容量,只能用pushback操作
					  //如果初始化,可以用数组下标操作。
	pts.push_back(p2);
	pts.push_back(p3);
	pts.push_back(p4);
	pts.push_back(p5);
	//fillPoly(canvas, pts, Scalar(122, 155, 255), 8, 0);//填充多边形
	//polylines(canvas, pts, true, Scalar(0, 0, 255), 2, 8, 0);//绘制多边形
	/*
	参数1表示画布,参数2表示点集,参数3表示true,参数4颜色
	参数5表示线宽,参数6表示渲染方式,参数7表示相对左上角(0,0)的位置
	*/
	//单个API搞定图片的绘制填充
	std::vector<std::vector<Point>>contours;
	contours.push_back(pts);
	drawContours(canvas,contours,-1, Scalar(0, 0, 255),-1);
	//参数2表示容器名称,参数3为正表示多边形的绘制,为负表示多边形的填充
	imshow("多边形绘制", canvas);
}

十六:鼠标操作和响应

//参数1表示鼠标事件。
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 image = *((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;
		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);
			imshow("ROI区域", image(box));
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
			imshow("鼠标绘制", image);
			sp.x = -1;
			sp.y = -1;//复位,为下一次做准备
		}
	}
	else if (event == EVENT_MOUSEMOVE) 
	{
		if (sp.x > 0 && sp.y > 0)
		{
			ep.x = x;
			ep.y = y;
			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(image);
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);
			}
		}
	}
}
void QuickDemo::mouse_drawing_demo(Mat &image)
{
	namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
	setMouseCallback("鼠标绘制", on_draw,(void*)(&image));
	//设置窗口的回调函数。参数1表示名称,参数2表示调用on_draw
	imshow("鼠标绘制", image);
	temp = image.clone();
}

十七:图像像素类型的转换和归一化

void QuickDemo::norm_demo(Mat &image)
{
	Mat dst;//定义一个名为dst的二值化类型的数据
	std::cout << image.type() << std::endl;//打印出来图片的类型
	image.convertTo(image,CV_32F);//将dst数据转换成浮点型float32位数据。
	std::cout << image.type() << std::endl;//再次打印转换后的数据类型
	normalize(image, dst, 1.0, 0, NORM_MINMAX);//进行归一化操作
	std::cout << dst.type() << std::endl;//打印归一化操作之后的数据
	imshow("图像的归一化", dst);//显示归一化的图像
	//CV_8UC3 ,CV_32FC3  //3通道每个通道8位的UC类型
	//转换后 3通道 每个通道32位的浮点数
}

十八:图像的放缩和差值

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.5, h*1.5), 0, 0, INTER_LINEAR);
	imshow("zoomin", zoomout);//
}

十九:图像的旋转

void QuickDemo::flip_demo(Mat &image)
{
	Mat dst;
	flip(image, dst, 0);//上下翻转 x对称
	flip(image, dst, 1);//左右翻转 y对称
	flip(image, dst, -1);//旋转180°
	imshow("图像翻转",dst);
}

二十:图像的翻转

void QuickDemo::rotate_demo(Mat &image)
{
	Mat dst, M;
	int h = image.rows;//定义图片的高度
	int w = image.cols;//定义图片的宽度
	M = getRotationMatrix2D(Point(w / 2, h / 2),45,1.0);
	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);
	//参数1原来图像的中心位置。参数2角度是多少。参数3是图像本身大小的放大缩小
	warpAffine(image, dst, M,Size(nw,nh),INTER_LINEAR,0, Scalar(0, 0, 255));
	imshow("旋转演示", dst);
}

二十一:读取视频文件

void QuickDemo::video_demo(Mat &image) 
{
	VideoCapture capture("D:/images/123.mp4");  //读取视频的地址
	Mat frame;//定义一个二值化的 frame
	
	while (true)
	{
		capture.read(frame); //读取视频
		//flip(frame, frame, 1);//图像镜像操作
		if(frame.empty())//如果视频为空的话 跳出操作
		{
			break;
		}
		imshow("frame", frame);//显示视频
		colorSpace_Demo(frame);//对视频调用之前的demo
		int c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
	}
	capture.release();//释放相机的资源
}


二十二:视频处理和保存

视频的属性,SD(标清),HD(高清),UHD(超清),蓝光。如何读取视频文件,以及读取视频文件的属性,衡量视频处理指标:FPS。保存视频时的编码格式。保存视频的实际size和create的size大小保持一致。

void QuickDemo::video_demo(Mat &image) 
{
	VideoCapture capture("D:/images/123.mp4");
	int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);//获取视频的宽度
	int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT);//获取视频的高度
	int count = capture.get(CAP_PROP_FRAME_COUNT);//视频总的帧数
	//fps是衡量处理视频的能力
	double fps = capture.get(CAP_PROP_FPS);
	std::cout << "frame width" << frame_width << std::endl;
	std::cout << "frame height" << frame_height << std::endl;
	std::cout << "frame FPS" << fps << std::endl;
	std::cout << "frame count" << count << std::endl;
	VideoWriter writer("D:/test.mp4",capture.get(CAP_PROP_FOURCC),fps,Size(frame_width, frame_height),true);
	//参数1 保存地址。参数2 获取图片的格式 参数3 图片的帧数 参数4 视频宽高 参数5 真
	Mat frame;
	while (true)
	{
		capture.read(frame);
		//flip(frame, frame, 1);//图像镜像操作
		if(frame.empty())
		{
			break;
		}
		imshow("frame", frame);
		colorSpace_Demo(frame);
		writer.write(frame);

		int c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
	}
	capture.release();//释放相机的资源
	writer.release();//释放存放的资源
}

二十三:直方图

#include <QCoreApplication>
#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;
Mat src, hsv_src;
Mat hue;

int bins = 12;
void Hist_And_Backprojection(int, void*);
int main()
{
   src = imread("E:/QTFiles/firsttext/fish.jpg");
   if (!src.data)
   {
       cout << "could not load image...\n";
       return -1;
   }
   namedWindow("input", CV_WINDOW_AUTOSIZE);

   //将图像从RGB色彩空间转换到HSV色彩空间
   cvtColor(src, hsv_src, CV_BGR2HSV);

   hue.create(hsv_src.size(), hsv_src.depth());
   int nchannels[] = { 0,0 };

   //mixChannels主要就是把输入的矩阵(或矩阵数组)的某些通道拆分复制给对应的输出矩阵(或矩阵数组)
   //的某些通道中,其中的对应关系就由fromTo参数制定.
   mixChannels(&hsv_src, 1, &hue, 1, nchannels, 1);

   createTrackbar("Histogram Bins:", "input", &bins, 180, Hist_And_Backprojection);
   Hist_And_Backprojection(0, 0);

   imshow("input", src);
   return 0;
}

void Hist_And_Backprojection(int, void*)
{
   //计算直方图
   float range[] = { 0,180 };
   const float *histRanges = { range };
   Mat h_hist;
   calcHist(&hue, 1, 0, Mat(), h_hist, 1, &bins, &histRanges, true, false);
   //归一化
   normalize(h_hist, h_hist, 0, 255, NORM_MINMAX, -1, Mat());

   //计算反向投影图像 - calcBackProject
   Mat backProjectIamge;
   calcBackProject(&hue, 1, 0, h_hist, backProjectIamge, &histRanges, 1, true);

   namedWindow("BackProjectIamge", CV_WINDOW_AUTOSIZE);
   imshow("BackProjectIamge", backProjectIamge);

   //画直方图
   int hist_h = 400;
   int hist_w = 400;
   int bin_w = (hist_w / bins);
   Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
   for (size_t i = 1; i < static_cast<size_t>(bins); i++)
   {
       rectangle(histImage,
          Point((i - 1)*bin_w, (hist_h - cvRound(h_hist.at<float>(i - 1)*(400 / 255)))),
          Point(i*bin_w, (hist_h - cvRound(h_hist.at<float>(i)*(400 / 255)))),
          Scalar(0, 0, 255), 2, LINE_AA);
   }
   imshow("Histogram", histImage);
   waitKey(0);

}

#include <QCoreApplication>
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;

const char*output = "histogram iamge";

int main()
{

    Mat src, dst, dst1;
    src=imread("E:\\QTFiles\\zhhpicture\\zhh.jpg");
    if(src.empty())
    {
        cout<<"imread wrong!"<<endl;
    }

       char input[] = "input image";
       namedWindow(input, CV_WINDOW_AUTOSIZE);
       namedWindow(output, CV_WINDOW_AUTOSIZE);
       imshow(input, src);

       //步骤一:分通道显示
       vector<Mat>bgr_planes;
       split(src, bgr_planes);
       //split(// 把多通道图像分为多个单通道图像 const Mat &src, //输入图像 Mat* mvbegin)// 输出的通道图像数组

       //步骤二:计算直方图
       int histsize = 256;
       float range[] = { 0,256 };
       const float*histRanges = { range };
       Mat b_hist, g_hist, r_hist;
       calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histsize, &histRanges, true, false);
       calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histsize, &histRanges, true, false);
       calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histsize, &histRanges, true, false);


       //归一化
       int hist_h = 400;//直方图的图像的高
       int hist_w = 512;//直方图的图像的宽
       int bin_w = hist_w / histsize;//直方图的等级
       Mat histImage(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));//绘制直方图显示的图像
       normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());//归一化
       normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
       normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());

       //步骤三:绘制直方图(render histogram chart)
       for (int i = 1; i < histsize; i++)
       {
           //绘制蓝色分量直方图
           line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))),
              Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, CV_AA);
           //绘制绿色分量直方图
           line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))),
              Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, CV_AA);
           //绘制红色分量直方图
           line(histImage, Point((i - 1)*bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))),
              Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, CV_AA);
       }
       imshow(output, histImage);
       waitKey(0);

       return 0;
}

二十四:直方图的均衡化

均衡化的图像只支持单通道。

void QuickDemo::histogram_eq_demo(Mat &image)
{
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	//直方图均衡化只支持灰度图像,不支持彩色图像。
	imshow("灰度图像", gray);
	Mat dst;
	equalizeHist(gray, dst);
	imshow("直方图均衡化", dst);
}

二十五:图像的卷积操作

卷积的作用,高的往下降,低的往上升。但是会造成信息丢失。产生模糊效果。是一种线性操作,点乘,之后相加。

void QuickDemo::blur_demo(Mat &image)
{
	Mat dst;
	blur(image, dst, Size(15, 15), Point(-1, -1));
	//参数1原始图像,参数2卷积之后的图像,参数3卷积的矩阵大小,支持单行或者单列的卷积操作,参数4卷积的起始点。
	imshow("图像卷积操作", dst);
}

二十六:模糊处理

高斯模糊
中心的数值最大,离中心距离越远,数值越小。
高斯卷积数学表达式说明:
在这里插入图片描述
在这里插入图片描述

void QuickDemo::gaussian_blur_demo(Mat &image)
{
	Mat dst;
	GaussianBlur(image, dst, Size(5, 5), 15);
	imshow("高斯模糊", dst);
	//参数1表示初始图像,参数2表示处理后的图像,参数3表示高斯矩阵大小 正数而且是奇数,
	//参数4表示西格玛x为15 西格玛y为15 
}


高斯双边模糊

void QuickDemo::bifilter_demo(Mat &image)
{
	Mat dst;
	bilateralFilter(image,dst,0,100,0);
	//参数1代表原图,参数2代表处理之后的图像,参数3色彩空间。参数4表示坐标空间,双边是指 色彩空间和坐标空间。
	namedWindow("双边模糊", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
	imshow("双边模糊", dst);//表示显示在新创建的
}

二十七:在一幅图片上加logo

1、在左上角加

#include <QCoreApplication>
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;


int main()
{
    Mat image1=imread("E:\\QTFiles\\zhhpicture\\zhh.jpg");
    Mat image2=imread("E:\\QTFiles\\zhhpicture\\name.png");
    imshow("initial image",image1);

    Mat roi =image1(Rect(0,0,image2.cols,image2.rows));

    Mat mask(image2);
    image2.copyTo(roi,mask);
    imshow("image2",image2);
    imshow("mask img1",image1);
    waitKey(0);

    return 0;
}

2、在中间加

int x, y;
	x = image1.cols / 2 - image2.cols / 2;
	y = image1.rows / 2 - image2.rows / 2;
	Mat roi = image1(Rect(x, y, image2.cols, image2.rows));

二十八:Mat类型和QImage类型之间的转换

Mat->QImage

QImage cvMat2QImage(const cv::Mat&amp; mat)
{
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        qDebug() << "CV_8UC4";
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}
cv::Mat QImage2cvMat(QImage image)
{
    cv::Mat mat;
    qDebug() << image.format();
    switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    }
    return mat;
}

QImage->Mat

  image2=image2.convertToFormat(QImage::Format_RGB888);
  Mat image1=Mat(image2.height(),image2.width(),CV_8UC(3),image2.bits(),image2.bytesPerLine());

未完待续

遇到更多我会继续添加

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

&*Savior

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值