opencv入门

窗口显示

cv::imshow

void cv::imshow ( const String & winname,InputArray mat);
  • imshow根据窗口名称显示图像到指定的窗口上去,第一个参数是窗口名称第二参数是Mat对象
#include <opencv2/opencv.hpp>
#include <iostream>
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;
}

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

注意:

  • imread可以加载灰度图像

cv::imread

imread(const string& filename, int flags=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);

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

cv::namedWindow

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

//常见用法
namedWindow("Window Title", WINDOW_ AUTOSIZE)
  • WINDOW_ AUTOSIZE会自动根据图像大小,显示窗门大小,不能认为改变窗口大小。
  • WINDOW_ NORMAL,跟QT集成的时候会使用,允许修改窗口大小。
  • WINDOW_FREERATIO, 可以调整图片的自由比率。
#include <opencv2/opencv.hpp>
#include <iostream>
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;
}

cv::cvtColor

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

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

COLOR_BGR2GRAY = 6彩色到灰度
COLOR_GRAY2BGR= 8灰度到彩色
COLOR_BGR2HSV = 40 BGR到HSV
COLOR_HSV2BGR = 54 HSV到BGR

cv::imwrite

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

  • 只有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);
}

main.cpp

#include <opencv2/opencv.hpp>
#include <iostream>
#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;

}

在这里插入图片描述

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);
}

创建 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;

在这里插入图片描述

使用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;

在这里插入图片描述

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

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

在这里插入图片描述

改变空白对象的色彩

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

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);
}

如果只是单纯的进行浅拷贝的话,那么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);
}

效果:

在这里插入图片描述

opencv图像像素点读写操作

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

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

读一个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];

数组遍历

  • 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);
}

修改前 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);
}

像素范围处理saturate_cast < uchar >

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

图像掩膜操作

红色是中心像素,从上到下,
从左到右对每个像素做同样
的处理操作。得到最终结果
就是对比度提高之后的输出
图像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)]
//			  当前点       上          下           左            右

掩膜操作代码

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);
}

掩膜操作前后对比

在这里插入图片描述

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

定义掩膜:

Mat kernel= (Mat_ <char>(3,3)<<0, -1,0, -1,5,-1,0,-1, 0);
filter2D( src, dst, src.depth(), kernel);
  • 其中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);	
}

在这里插入图片描述

图像像素的算术操作

除法操作两种方式

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);
}

乘法操作

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);
}

像素点相加

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);
	
}

算术运算常用的四个接口

//加法
void add(src, m, dst);
//减法
void subtract(src, m, dst);
//乘法
void multiply(src, m, dst);
//除法
void divide(src, m, dst);

在这里插入图片描述

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱生活,爱代码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值