• opencv入门


    窗口显示

    cv::imshow

    void cv::imshow ( const String & winname,InputArray mat);
    
    • 1
    • imshow根据窗口名称显示图像到指定的窗口上去,第一个参数是窗口名称第二参数是Mat对象
    #include 
    #include 
    using namespace cv;
    using namespace std;
    
    int main() 
    {
    	cv::Mat src = imread("C:/Users/26961/Desktop/dog.jpg");
    	if (src.empty()) {
    		cout << "图图片未加载" << endl;
    		return -1;
    	}
    	imshow("输入窗口", src);
    	waitKey(0); //阻塞式等待
    	destroyAllWindows(); //销毁所有的窗口对象
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    并不能进行窗口的缩放,只是图片固定在创建的窗口上会固定尺寸

    注意:

    • imread可以加载灰度图像

    cv::imread

    imread(const string& filename, int flags=1);
    
    • 1
    • imread功能是加载图像文件成为一个Mat对象,其中第一个参数表示图像文件名称。
    • 第二个参数,表示加载的图像是什么类型,支持常见的三个参数值
      IMREAD_ UNCHANGED (<0)表示加载原图,不做任何改变
      IMREAD_GRAYSCALE ( 0)表示把原图作为灰度图像加载进来
      IMREAD_ COLOR (>0)表示把原图作为RGB图像加载进来

    注意: OpenCV支持JPG、PNG、 TIFF等常 见格式图像文件加载

    cv::Mat src = imread("C:/Users/26961/Desktop/dog.jpg", 
    									IMREAD_GRAYSCALE);
    
    • 1
    • 2

    显示效果:
    在这里插入图片描述

    cv::namedWindow

    namedWindos功能是创建一个OpenCV窗口 ,它是由OpenCV自动创建与释放,你无需取销毁它。

    //常见用法
    namedWindow("Window Title", WINDOW_ AUTOSIZE)
    
    • 1
    • 2
    • WINDOW_ AUTOSIZE会自动根据图像大小,显示窗门大小,不能认为改变窗口大小。
    • WINDOW_ NORMAL,跟QT集成的时候会使用,允许修改窗口大小。
    • WINDOW_FREERATIO, 可以调整图片的自由比率。
    #include 
    #include 
    using namespace cv;
    using namespace std;
    
    int main() 
    {
    	cv::Mat src = imread("C:/Users/26961/Desktop/dog.jpg");
    	if (src.empty()) {
    		cout << "图片未加载" << endl;
    		return -1;
    	}
    	
    	//可以进行窗口的缩放
    	namedWindow("输入窗口", WINDOW_FREERATIO);  //WINDOW_FREERATIO -可以调整图片的自由比率
    	imshow("输入窗口", src);
    	waitKey(0);//阻塞式等待
    	destroyAllWindows();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    cv::cvtColor

    void cv::cvtColor(InputArray 	src,	//输入图像
                      OutputArray 	dst,	//输出图像
                      int 	code,			//目标色彩空间, 如COLOR_BGR2GRAY 等
                      int 	dstCn = 0 
                      )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    cvtColor的功能是把图像从一-个彩色空间转换到另外一个色彩空间,有三个参数,第一个参数表示源图像、第二参数表示色彩空间转换之后的图像、第三个参数表示源和目标色彩空间如:

    COLOR_BGR2GRAY = 6彩色到灰度
    COLOR_GRAY2BGR= 8灰度到彩色
    COLOR_BGR2HSV = 40 BGR到HSV
    COLOR_HSV2BGR = 54 HSV到BGR
    
    • 1
    • 2
    • 3
    • 4

    cv::imwrite

    CV_EXPORTS_W bool imwrite( const String& filename, InputArray img,
                  const std::vector<int>& params = std::vector<int>());
    
    • 1
    • 2
    • 保存图像文件到指定目录路径

    • 只有8位、16位的PNG、 JPG、 Tiff文件格式而 且是单通道或者三通道的BGR的图像才可以通过这种方式保存。

    • 保存PNG格式的时候可以保存透明通道的图片可以指定压缩参数

    void QuickDemo::quick_space_demo(Mat& src)
    {
    	Mat gray, hsv;  //用于存储灰色和彩色的Mat对象
    
    	
    	cvtColor(src, hsv, COLOR_BGR2HSV);	//设置灰色
    	cvtColor(src, gray, COLOR_BGR2GRAY); //设置彩色
    	
    	//调整图片的自由比率
    	namedWindow("灰色", WINDOW_FREERATIO);
    	namedWindow("hsv", WINDOW_FREERATIO);
    
    	imshow("hsv", hsv);				//显示转换后的图片
    	imshow("灰色", gray);			//显示转换后的图片
    
    	//保存转换颜色后的图片
    	imwrite("C:/Users/26961/Desktop/images/hsv.jpg", hsv);
    	imwrite("C:/Users/26961/Desktop/images/gray.jpg", gray);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    main.cpp

    #include 
    #include 
    #include "quick_demo.h"
    
    
    using namespace cv;
    using namespace std;
    
    int main()		
    {
    	cv::Mat src = imread("C:\\Users\\26961\\Desktop\\images\\dog.jpg");
    	if (src.empty()) {
    		cout << "图片未打开" << endl;
    		return -1;
    	}
    
    	//可以进行窗口的缩放,图片与窗口大小匹配
    	namedWindow("输入窗口", WINDOW_FREERATIO);
    	imshow("输入窗口", src);
    
    	//彩色转换
    	QuickDemo obj;
    	obj.quick_space_demo(src);  
    	//将Mat 对象传递给quick_space_demo函数,将转换的图片保存到
    	// C:/Users/26961/Desktop/images/路径中
    
    	//阻塞等待
    	waitKey(0);
    
    	//销毁窗口对象
    	destroyAllWindows();
    	return 0;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    openCV图像对象创建与赋值

    图像对象的创建和赋值

    void QuickDemo::mat_creater_demo(Mat& src) 
    {
    	Mat m1, m2;
    	m1 = src.clone(); //赋值方式一
    	src.copyTo(m2);   //赋值方式二
    	cvtColor(src, m1, COLOR_BGR2HSV); //为了区别,将m1对象色彩设置为彩色
    
    	imshow("m1对象", m1);
    	imshow("m2对象", m2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    创建 8 * 8 的空白对象

    //设置8 * 8的空白图像,指定一个通道。
    Mat m3 = Mat::zeros(Size(8, 8), CV_8UC1);
    
    /*
    	显示宽度、高度、通道。
    */
    std::cout << "width: " << m3.cols << " height: " << m3.rows  
     << " channels: " << m3.channels() << std::endl;
    
    //打印空白图像
    std::cout << m3 << std::endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    使用ones和zeros的区别
    如果在创建空白Mat对象时,如果指定要创建3个通道的时候,但是此时是使用Mat::ones该方法进行创建的话都出现1和0交替的现象,并且1总是出现在1通道

    Mat m3 = Mat::ones(Size(8, 8), CV_8UC3);
    std::cout << "width: " << m3.cols << " height: " << m3.rows  
     << " channels: " << m3.channels() << std::endl;
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    而如果是使用Mat::zeros方法时,并不会发送该情况,而是全部会初始化为0。

    Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);
    
    • 1

    在这里插入图片描述

    改变空白对象的色彩

    Mat m3 = Mat::zeros(Size(500, 500), CV_8UC3);
    m3 = Scalar(255,0,0); //设置m3对象的色彩,这里会被设置为纯蓝色
    imshow("图像", m3);	  //显示m3对象			
    
    • 1
    • 2
    • 3

    Mat对象之间的深浅拷贝问题

    void QuickDemo::mat_creater_demo(Mat& src) 
    {
    	Mat m1, m2;
    	m1 = src.clone(); //赋值方式一
    	src.copyTo(m2);   //赋值方式二
    	cvtColor(src, m1, COLOR_BGR2HSV); //为了区别,将m1对象色彩设置为彩色
    
    	/*imshow("m1对象", m1);
    	imshow("m2对象", m2);*/
    
    	Mat m3 = Mat::zeros(Size(500, 500), CV_8UC3);
    	m3 = Scalar(255,0,0); //设置m3对象的色彩
    	imshow("图像3", m3);
    	std::cout << "width: " << m3.cols << " height: " << m3.rows  
    	 << " channels: " << m3.channels() << std::endl;
    		
    
    	//浅拷贝
    	Mat m4 = m3;
    	m4 = Scalar(0, 0 ,0); //修改了m3
    	imshow("图像4", m4);
    	
    	//深拷贝
    	Mat m5 = m3.clone(); //深拷贝已经修改了的m3
    	imshow("图像5", m5);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    如果只是单纯的进行浅拷贝的话,那么m4对象的改变会影响到m3对象, 直到m4被修改了后m3也会收到影响。

    在这里插入图片描述

    解决的方案就是让m4深拷贝m3,那么就不会导致m3发生改变

    void QuickDemo::mat_creater_demo(Mat& src) 
    {
    	Mat m3 = Mat::zeros(Size(500, 500), CV_8UC3);
    	m3 = Scalar(255,0,0); //设置m3对象的色彩
    	imshow("图像3", m3);
    	std::cout << "width: " << m3.cols << " height: " << m3.rows  
    	 << " channels: " << m3.channels() << std::endl;
    		
    	//浅拷贝
    	Mat m4 = m3.clone();
    	m4 = Scalar(0, 0 ,0);
    	imshow("图像4", m4);
    	
    	//深拷贝
    	Mat m5 = m3.clone();
    	m5 = Scalar(160,20,20);
    	imshow("图像5", m5);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    效果:

    在这里插入图片描述

    opencv图像像素点读写操作

    读一个GRAY像素点的值(CV_8UC1)

    • 注:单通道
    Scalar intensity = img.at<uchar> (x, y);  //第一种
    Scalar intensity = img.at<uchar> (Point(x, y)); //第二种
    
    • 1
    • 2

    读一个RGB像素点的像素值, B、G、R读取顺序

    • 注:三通道
    Vec3f intensity = img.at<Vec3f>(x,y);
    double blue = intensity.val[0];
    double green = intensity.val[1];
    double red = intensity.val[2];
    
    • 1
    • 2
    • 3
    • 4

    数组遍历

    • CV Assert(mylmage.depth()==CV 8U);
    void changeimg(Mat &src) {
    
    	int w = src.cols;   //列
    	int h = src.rows;	//行
    	int dims = src.channels();  //通道
    
    	for (int i = 0; i < h; i++) {
    		for (int j = 0; j < w; j++) {
    			if (dims == 1) { //单通道的灰度图像
    
    				//获取[i, j]位置的像素值
    				int pv = src.at<uchar>(i, j);
    				//修改[i, j]位置的像素值
    				src.at<uchar>(i, j) = 255 - pv;
    			}
    
    			//三个通道的像素点需要修改三次,因为三个通道的彩色图像每一个像素点可以存储3个值
    			if (dims == 3) { //3通道的彩色图像
    			
    				//Vec3b 是一个三通道的像素点,所以Vec3b对象包含三个值 
    				Vec3b bgr = src.at<Vec3b>(i, j);
    				src.at<Vec3b>(i, j)[0] = 255 - bgr[0];
    				src.at<Vec3b>(i, j)[1] = 255 - bgr[1];
    				src.at<Vec3b>(i, j)[2] = 255 - bgr[2];
    			}
    		}
    	}
    	
    }
    
    void QuickDemo::pixel_vlist_demo(Mat& src) {
    	Mat m1 = src.clone();
    	changeimg(m1);
    	imshow("src图像", src);
    
    
    	Mat m2 = src.clone();
    	changeimg(m2);
    	imshow("m2图像", m2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    修改前 vs 修改后

    在这里插入图片描述

    指针方式遍历

    • Mat.ptr< uchar >(int i=0) 获取像素矩阵的指针,索弓li表示第几行,从开始计行数。
    • 获得当前行指针 const uchar* current=mylmage.ptr(row );
    • 获取当前像素点 P(row, col)的像素值p(row, col) =current[col]
    void changeimg2(Mat& src) {
    
    	int w = src.cols;   //列
    	int h = src.rows;	//行
    	int dims = src.channels();  //通道
    
    	for (int i = 0; i < h; i++) {
    		// 获取行指针
    		uchar* curr_row = src.ptr<uchar>(i);
    		for (int j = 0; j < w; j++) {
    
    			//获取列指针
    			if (dims == 1) {
    				int pv = *curr_row;
    				*curr_row++ = 255 - pv;
    			}
    			if (dims == 3) {
    				//遍历一个像素点拥有三个值的图像
    				*curr_row++ = 255 - *curr_row;
    				*curr_row++ = 255 - *curr_row;
    				*curr_row++ = 255 - *curr_row;
    			}
    		}
    	}
    
    }
    
    void QuickDemo::pixel_vlist_demo(Mat& src) {
    	Mat m1 = src.clone();
    	changeimg1(m1);
    	imshow("src图像", m1);
    
    
    	Mat m2 = src.clone();
    	changeimg2(m2);
    	imshow("m2图像", m2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    像素范围处理saturate_cast < uchar >

    • 这个函数的功能是确保RGB值得范围在0~255之间
    saturate_cast < uchar >  ( -100 ),返回0saturate_cast < uchar >  ( 288 ),返回255
    saturate_cast < uchar > ( 100 ) , 返回100
    
    • 1
    • 2
    • 3

    图像掩膜操作

    红色是中心像素,从上到下,
    从左到右对每个像素做同样
    的处理操作。得到最终结果
    就是对比度提高之后的输出
    图像Mat对象。

    在这里插入图片描述

    • 矩阵的掩膜操作十分简单,根据掩膜来重新计算每个像素的像素值,掩膜(mask 也被称为Kernel)
    • 通过掩膜操作实现图像对比度提高。
    //x: 通道数
    I(i, j) = 5 * I(i, j) - [I(i -x,j) + I(i + x,j) + I(i, j - x) + I(i, j + x)]
    //			  当前点       上          下           左            右
    
    • 1
    • 2
    • 3

    掩膜操作代码

    void Test_Demo::maskopt(cv::Mat &src, cv::Mat *outsrc)
    {
    	//存放目标答案
    	cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
    
    	//获取宽高
    	int row = src.rows;  //行
    	int col = (src.cols - 1) * src.channels(); //列
    	
    	//获取偏移量
    	int offset = src.channels();
    	for (int i = 1; i < row - 1; i++) {
    		const uchar* prevptr = src.ptr<uchar>(i - 1);
    		const uchar* currptr = src.ptr<uchar>(i);
    		const uchar* nextptr = src.ptr<uchar>(i + 1);
    
    		uchar* dst_ptr = dst.ptr<uchar>(i);
    		for (int j = offset; j < col; j++) {
    			//[I(i - 1, j) + I(i + 1, j) + I(i, j - 1) + I(i, j + 1)]
    			dst_ptr[j] = saturate_cast<uchar> ((5 * currptr[j]) - (currptr[j - offset]
    							+ currptr[j + offset] + prevptr[j] + nextptr[j]));
    		}
    	}
    
    	*outsrc = dst.clone();
    }
    
    
    void test_demo_func() 
    {
    	
    	cv::String filename = "C:/Users/26961/Desktop/images/jay.jpg";
    	Test_Demo obj;
    	cv::Mat src = cv::imread(filename);
    	cv::Mat dst;
    
    	obj.maskopt(src, &dst);
    	
    	cv::namedWindow("掩膜前");
    	imshow("掩膜前", src);
    
    	cv::namedWindow("掩膜后");
    	imshow("掩膜后", dst);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    掩膜操作前后对比

    在这里插入图片描述

    使用cv::filter2D 对图像进行掩膜处理

    定义掩膜:

    Mat kernel= (Mat_ <char>(3,3)<<0, -1,0, -1,5,-1,0,-1, 0);
    
    • 1
    filter2D( src, dst, src.depth(), kernel);
    
    • 1
    • 其中src与dst是Mat类型变量、
    • src.depth表示位图深度 ,有32、24、8等。
    • kernel需要人为的去定义一个掩膜

    使用filter2D的效果

    void test_demo_func() 
    {
    	cv::String filename = "C:/Users/26961/Desktop/images/jay.jpg";
    	Test_Demo obj;
    	cv::Mat src = cv::imread(filename);
    	cv::Mat dst;
    
    	//obj.maskopt(src, &dst);
    	Mat kernel = (Mat_ <char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    	filter2D(src, dst, src.depth(), kernel);
    
    	cv::namedWindow("掩膜前");
    	imshow("掩膜前", src);
    
    	cv::namedWindow("掩膜后");
    	imshow("掩膜后", dst);	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    图像像素的算术操作

    除法操作两种方式

    void QuickDemo::operator_demo(Mat& src)
    {
    	Mat dst;
    	dst = src / Scalar(2, 2, 2);
    
    	imshow("算术操作", dst);
    }
    
    void QuickDemo::operator_demo(Mat& src)
    {
    	Mat dst;
    	Mat m = Mat::zeros(src.size(), src.type());
    	m = Scalar(2, 2, 2);
    
    	divide(src, m, dst);
    	imshow("除法操作", dst);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    乘法操作

    void QuickDemo::operator_demo(Mat& src)
    {
    	Mat dst;
    	Mat m = Mat::zeros(src.size(), src.type());
    	m = Scalar(2, 2, 2);
    
    	multiply(src, m, dst); //src 与 m相乘的结果放入dst中
    	imshow("算术操作", dst);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    像素点相加

    void QuickDemo::operator_demo(Mat& src)
    {
    	//初始化dst, 用于存储m和src 运算后的结果值 
    	Mat dst = Mat::zeros(src.size(), src.type());
    	//初始化m对象
    	Mat m = Mat::zeros(src.size(), src.type());
    	m = Scalar(2, 2, 2);
    
    	
    
    	int h = src.rows; //获取行
    	int w = src.cols; //获取列
    	
    	//计算 m对象和src的和值
    	for (int i = 0; i < h; i++) {
    		for (int j = 0; j < w; j++) {
    			Vec3b p1 = src.at<Vec3b>(i, j);
    			Vec3b p2 = m.at<Vec3b>(i, j);
    			dst.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
    			dst.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
    			dst.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
    		}
    	}
    
    	imshow("算术操作", dst);
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    算术运算常用的四个接口

    //加法
    void add(src, m, dst);
    //减法
    void subtract(src, m, dst);
    //乘法
    void multiply(src, m, dst);
    //除法
    void divide(src, m, dst);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

  • 相关阅读:
    【精选】网络安全大厂面试题 2.0
    Mybatis入门相关API
    深入理解Netty底层基础、中断、NIO、epoll~~~~
    java计算机毕业设计电子配件公司仓库管理系统源码+mysql数据库+系统+lw文档+部署
    Postman笔记
    数商云:订单积压达 930 亿欧元,西门子如何通过供应链数字化转型缩短交货期
    Unity类银河恶魔城学习记录7-8 P74 Pierce sword源代码
    记一次 Redisson 线上问题 → ERR unknown command 'WAIT' 的排查与分析
    (2022杭电多校四)1001-Link with Bracket Sequence II(区间动态规划)
    anaconda使用系列教程--5)安装anaconda环境到指定位置
  • 原文地址:https://blog.csdn.net/m0_53421868/article/details/126638163