opencv入门基础(c++)【一】

opencv入门基础(c++)

  • 一、加载、修改、保存图像
    • 1.1加载图像(用cv::imread
      • 1.1.1加载图像(用cv::imread
      • 1.1.2显示图像 (cv::namedWindos 与cv::imshow)
    • 1.2修改图像 (cv::cvtColor)
    • 1.3保存图像(cv::imwrite)
  • 二、矩阵的掩膜操作
    • 2.1获取图像像素指针
    • 2.2掩膜操作解释
  • 三、Mat对象
    • 3.1Mat对象与IplImage对象
    • 3.2Mat对象使用
      • 3.2.1Mat对象构造函数与常用方法
      • 创建空白图片如何赋值
      • 完全克隆Mat dst=src.clone();
      • 完全克隆src.copyTo(dst);
      • 找通道数 src.channels()
      • 像素行列 dst.cols dst.rows
      • 3.2.2Mat对象使用
      • 3.2.3Mat对象创建
      • 3.2.4定义小数组
  • 四、图像操作
    • 4.1读写图像
    • 4.2读写像素
      • ↓单通道图片像素反差操作
      • ↓多通道图片像素反差操作
    • 4.2修改像素值
      • Vec3b与Vec3F
  • 五、图像混合
    • 5.1理论-线性混合操作
    • 5.2相关API (addWeighted)
  • 六、调整图像亮度与对比度
    • 6.1理论
    • 6.2重要的API

一、加载、修改、保存图像

1.1加载图像(用cv::imread

1.1.1加载图像(用cv::imread

imread功能是加载图像文件成为一个Mat对象,其中第一个参数表示图像文件名称
第二个参数,表示加载的图像是什么类型,支持常见的三个参数值
IMREAD_UNCHANGED (<0) 表示加载原图,不做任何改变
IMREAD_GRAYSCALE ( 0)表示把原图作为灰度图像加载进来
IMREAD_COLOR (>0) 表示把原图作为RGB图像加载进来
注意:OpenCV支持JPG、PNG、TIF等常见格式图像文件加载

#include 
#include

using namespace std;
using namespace cv;

int main()
{
	//读取图片(使用图片的绝对路径)
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg",IMREAD_GRAYSCALE);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}

	imshow("ImputImage", src);
	//不加此语句图片会一闪而过
	waitKey(0);
	system("path");
	getchar();
	return 0;
}

1.1.2显示图像 (cv::namedWindos 与cv::imshow)

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

常见用法namedWindow(“Window Title”, WINDOW_AUTOSIZE)

WINDOW_AUTOSIZE会自动根据图像大小,显示窗口大小,不能人为改变窗口大小

WINDOW_NORMAL,跟QT集成的时候会使用,允许修改窗口大小。(一般不用)

imshow根据窗口名称显示图像到指定的窗口上去,第一个参数是窗口名称,第二参数是Mat对象

1.2修改图像 (cv::cvtColor)

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

#include 
#include

using namespace std;
using namespace cv;

int main()
{

	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}

	imshow("ImputImage", src);//显示默认窗口
	
	namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	Mat output_image;
	cvtColor(src, output_image, COLOR_BGR2GRAY);
	imshow("output windows", output_image);//显示创建的窗口
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

1.3保存图像(cv::imwrite)

保存图像文件到指定目录路径
只有8位、16位的PNG、JPG、Tiff文件格式而且是单通道或者三通道的BGR的图像才可以通过这种方式保存
保存PNG格式的时候可以保存透明通道的图片
可以指定压缩参数

#include 
#include

using namespace std;
using namespace cv;

int main()
{

	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}

	imshow("ImputImage", src);//显示默认窗口
	
	namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	Mat output_image;//创建图像对象
	cvtColor(src, output_image, COLOR_BGR2HLS);//图像转变
	imshow("output windows", output_image);//显示创建的窗口
	imwrite("C:/Users/Admin/Desktop/3.png", output_image);//保存图像,支持PNG、JPG、Tiff文件格式
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

二、矩阵的掩膜操作

这一节还是看别人的博客更好https://blog.csdn.net/wangyuankl123/article/details/104726702

2.1获取图像像素指针

CV_Assert(myImage.depth() == CV_8U);
Mat.ptr(int i=0) 获取像素矩阵的指针,索引i表示第几行,从0开始计行数。
获得当前行指针const uchar* current= myImage.ptr(row );
获取当前像素点P(row, col)的像素值 p(row, col) =current[col]

像素范围处理saturate_cast
saturate_cast(-100),返回 0。
saturate_cast(288),返回255
saturate_cast(100),返回100
这个函数的功能是确保RGB值得范围在0~255之间

2.2掩膜操作解释

掩膜操作提供提高图像对比度在这里插入图片描述opencv入门基础(c++)【一】_第1张图片
以下代码有指针错误,具体代码需要看别人的博客,但是除去指针问题,语法是没有问题的

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	imshow("ImputImage", src);//显示默认窗口
	Mat  resultImage;
	int nchannels = src.channels();//获取通道数
	int height = src.rows;
	int cols = src.cols;
	int width = cols * nchannels;
	for (int row = 1; row < height - 1; row++) {
		const uchar* previous = src.ptr<uchar>(row - 1);
		const uchar* current = src.ptr<uchar>(row);
		const uchar* next = src.ptr<uchar>(row + 1);
		uchar* output = resultImage.ptr<uchar>(row);
		for (int col = nchannels; col < nchannels * (cols - 1); col++) {
			*output = saturate_cast<uchar>(5 * current[col] - previous[col] - next[col] - current[col - nchannels] - current[col + nchannels]);
			output++;
		}
	}
	namedWindow("mask_result", WINDOW_AUTOSIZE);
	imshow("mask_result", resultImage);

	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

opencv入门基础(c++)【一】_第2张图片

三、Mat对象

Mat对象与IplImage对象
Mat对象使用
Mat定义数组

3.1Mat对象与IplImage对象

Mat对象OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构。分了两个部分,头部与数据部分

IplImage是从2001年OpenCV发布之后就一直存在,是C语言风格的数据结构,需要开发者自己分配与管理内存,对大的程序使用它容易导致内存泄漏问题(现在一般不用)

3.2Mat对象使用

3.2.1Mat对象构造函数与常用方法

他人博客可供参考
https://blog.csdn.net/danwuxie/article/details/81395650
https://blog.csdn.net/wangyuankl123/article/details/104732460
opencv入门基础(c++)【一】_第3张图片
常用方法:

void copyTo(Mat mat)
void convertTo(Mat dst, int type)
Mat clone()
int channels()
int depth()
bool empty();
uchar* ptr(i=0)

创建空白图片如何赋值

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	imshow("ImputImage", src);//显示默认窗口
	
	Mat dst;
	dst = Mat(src.size(), src.type());
	dst = Scalar(127, 0, 255);
	namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	imshow("output windows", dst);//显示创建的窗口
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

完全克隆Mat dst=src.clone();

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	imshow("ImputImage", src);//显示默认窗口
	
	Mat dst=src.clone();//克隆
	
	namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	imshow("output windows", dst);//显示创建的窗口
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

完全克隆src.copyTo(dst);

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	imshow("ImputImage", src);//显示默认窗口
	
	Mat dst;
	src.copyTo(dst);
	
	namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	imshow("output windows", dst);//显示创建的窗口
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

找通道数 src.channels()

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	imshow("ImputImage", src);//显示默认窗口
	
	Mat dst;
	//src.copyTo(dst);
	cvtColor(src,dst, COLOR_BGR2GRAY);
	printf("the src's channels is! : %d", src.channels());
	printf("the dst's channels is! : %d",dst.channels());
	namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	imshow("output windows", dst);//显示创建的窗口
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

像素行列 dst.cols dst.rows

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	imshow("ImputImage", src);//显示默认窗口
	
	Mat dst;
	//src.copyTo(dst);
	cvtColor(src,dst, COLOR_BGR2GRAY);
	printf("the src's channels is! : %d", src.channels());
	printf("the dst's channels is! : %d",dst.channels());
	const uchar* firstRow= src.ptr<uchar>(0);

	int cols = dst.cols;
	int rows = dst.rows;
	printf("the src's cols is : %d", cols);
	printf("the dst's rows is : %d", rows);
		
	printf("the firstRow value is! : %d", *firstRow);
	/*namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	imshow("output windows", dst);//显示创建的窗口*/
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

3.2.2Mat对象使用

部分复制:一般情况下只会复制Mat对象的头和指针部分,不会复制数据部分
Mat A= imread(imgFilePath);
Mat B(A) // 只复制
完全复制:如果想把Mat对象的头部和数据部分一起复制,可以通过如下两个API实现
Mat F = A.clone(); 或 Mat G; A.copyTo(G);

四个要点
输出图像的内存是自动分配的
使用OpenCV的C++接口,不需要考虑内存分配问题
赋值操作和拷贝构造函数只会复制头部分
使用clone与copyTo两个函数实现数据完全复制

3.2.3Mat对象创建

cv::Mat::Mat构造函数
Mat M(2,2,CV_8UC3, Scalar(0,0,255))
其中前两个参数分别表示行(row)跟列(column)、第三个CV_8UC3中的8表示每个通道占8位、U表示无符号、C表示Char类型、3表示通道数目是3,第四个参数是向量表示初始化每个像素值是多少,向量长度对应通道数目一致

创建多维数组cv::Mat::create
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC1, Scalar::all(0));

#include  
#include  
#include 
#include 

using namespace cv;
using namespace std;
int main(int argc, char** args) {
Mat image = imread("D:/test.jpg", IMREAD_GRAYSCALE);
if (image.empty()) {
cout << "could not find the image resource..." << std::endl;
return -1;
}
namedWindow("My Image", CV_WINDOW_AUTOSIZE);
imshow("My Image", image);

Mat M;
M.create(4, 3, CV_8UC2);
M = Scalar(127,127);
cout << "M = " << endl << " " << M << endl << endl;
uchar* firstRow = M.ptr<uchar>(0);
printf("%d\n", *firstRow);

Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "C = " << endl << " " << C << endl << endl;

waitKey(0);
return 0;
}

3.2.4定义小数组

Mat C = (Mat_(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "C = " << endl << " " << C << endl << endl;
opencv入门基础(c++)【一】_第4张图片

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/2.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
//	imshow("ImputImage", src);//显示默认窗口
	
	Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	cout << "C = " << endl << " " << C << endl << endl;


//	imshow("ImputImage", M);
	/*namedWindow("output windows", WINDOW_AUTOSIZE);//创建窗口
	imshow("output windows", dst);//显示创建的窗口*/
	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

四、图像操作

读写图像
读写像素
修改像素值

4.1读写图像

imread 可以指定加载为灰度或者RGB图像
Imwrite 保存图像文件,类型由扩展名决定

4.2读写像素

读一个GRAY像素点的像素值(CV_8UC1)
Scalar intensity = img.at(y, x);
或者 Scalar intensity = img.at(Point(x, y));

读一个RGB像素点的像素值
Vec3f intensity = img.at(y, x);
float blue = intensity.val[0];
float green = intensity.val[1];
float red = intensity.val[2];

↓单通道图片像素反差操作

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{
	
	Mat src = imread("C:/Users/Admin/Desktop/3.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
   imshow("ImputImage", src);//显示默认窗口

   //单通道图像操作
   Mat grayImg;
   Mat gray2;

   cvtColor(src, grayImg, COLOR_BGR2GRAY);
   gray2 = Mat(grayImg.size(), grayImg.type());
   int height = grayImg.rows;
   int width = grayImg.cols;
  for (int row = 0; row < height; row++) {
	   for (int col = 0; col < width; col++) {
		  int gray = grayImg.at<uchar>(row, col);

		   gray2.at<uchar>(row, col) = 255 - gray;
		  // printf("%d",gray);
	   }
   }
   namedWindow("grayImgm", WINDOW_AUTOSIZE);
   imshow("grayImgm", grayImg);

   namedWindow("gray2m", WINDOW_AUTOSIZE);
   imshow("gray2m", gray2);

	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

↓多通道图片像素反差操作

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{

	Mat src = imread("C:/Users/Admin/Desktop/3.jpg");	//读取图片(使用图片的绝对路径)
	CV_Assert(src.depth() == CV_8U);
	if (src.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	imshow("ImputImage", src);//显示默认窗口

	Mat dst;
	dst.create(src.size(), src.type());

   int height = src.rows;
   int width = src.cols;
   int nc = src.channels();
   for (int row = 0; row < height; row++) {
	   for (int col = 0; col < width; col++) {
		   if (nc = 1) {
			   int gray = src.at<uchar>(row, col);
			   dst.at<uchar>(row, col) = 255 - gray;
		   }
		   else{
			   int b = src.at<Vec3f>(row, col)[0];
			   int g = src.at<Vec3f>(row, col)[1];
			   int r = src.at<Vec3f>(row, col)[2];
			   dst.at<Vec3f>(row, col)[0] = 255 - b;
			   dst.at<Vec3f>(row, col)[1] = 255 - g;
			   dst.at<Vec3f>(row, col)[2] = 255 - r;
		   }
	   }
   }

   namedWindow("gray2m", WINDOW_AUTOSIZE);
   imshow("gray2m", dst);

	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

4.2修改像素值

灰度图像
img.at(y, x) = 128;

RGB三通道图像
img.at(y,x)[0]=128; // blue
img.at(y,x)[1]=128; // green
img.at(y,x)[2]=128; // red

空白图像赋值
img = Scalar(0);

ROI选择
Rect r(10, 10, 100, 100);
Mat smallImg = img®;

Vec3b与Vec3F

Vec3b对应三通道的顺序是blue、green、red的uchar类型数据。
Vec3f对应三通道的float类型数据
把CV_8UC1转换到CV32F1实现如下:
src.convertTo(dst, CV_32F);

五、图像混合

理论-线性混合操作
相关API (addWeighted)

5.1理论-线性混合操作

g(x)=(1-α)f0(x)+αf1(x)
其中α的取值范围为0~1之间

5.2相关API (addWeighted)

opencv入门基础(c++)【一】_第5张图片
在这里插入图片描述
参数1:输入图像Mat – src1
参数2:输入图像src1的alpha值
参数3:输入图像Mat – src2
参数4:输入图像src2的alpha值
参数5:gamma值//校验值,防止图片太暗
参数6:输出混合图像
saturate:用来确认取值合法
注意点:两张图像的大小和类型必须一致才可以

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{

	Mat src1 = imread("C:/Users/Admin/Desktop/1.jpg");	//读取图片(使用图片的绝对路径)
	Mat src2 = imread("C:/Users/Admin/Desktop/2.jpg");
	Mat dst;
	dst.create(src1.size(), src1.type());
	//CV_Assert(src.depth() == CV_8U);
	if (src1.empty()|| src2.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	double alpha = 0.5;
	if (src1.rows == src2.rows&&src1.cols == src1.cols&&src1.type() == src2.type()) {
		addWeighted(src1, alpha,src2,(1.0-alpha),0.0,dst);
			//add(src1, src2, dst, Mat());
			//multiply(src1, src2, dst, 1.0);
		imshow("ImputImage", src1);//显示默认窗口
		namedWindow("gray2", WINDOW_AUTOSIZE);
		imshow("gray2", src2);
		namedWindow("gray2m", WINDOW_AUTOSIZE);
		imshow("gray2m", dst);
	}
	else {
		printf("could not do it!\n");
		return -1;
	}


	


 

	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

六、调整图像亮度与对比度

6.1理论

图像变换可以看作如下:

  • 像素变换 – 点操作
  • 邻域操作 – 区域
    调整图像亮度和对比度属于像素变换-点操作
    ;

6.2重要的API

Mat new_image = Mat::zeros( image.size(), image.type() ); 创建一张跟原图像大小和类型一致的空白图像、像素值初始化为0

saturate_cast(value)确保值大小范围为0~255之间

Mat.at(y,x)[index]=value 给每个像素点每个通道赋值

#include 
#include
#include
using namespace std;
using namespace cv;

int main()
{

	Mat src1 = imread("C:/Users/Admin/Desktop/1.jpg");	//读取图片(使用图片的绝对路径)
	Mat src2 = imread("C:/Users/Admin/Desktop/2.jpg");
	Mat dst;
	if (src1.empty() || src2.empty()) {
		printf("could not find the image!\n");
		return -1;
	}
	char input_win[] = "input image";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src2);

	int height = src2.rows;
	int width = src2.cols;
	int nc = src2.channels();
	dst= Mat::zeros(src2.size(), src2.type());
	float alpha = 1.2;
	float beta = 30;
	for (int row = 0; row < height; row++) {
		for (int col = 0; col < width; col++) {
			 if (nc = 1) {
				 float t = src2.at<uchar>(row, col);
				 dst.at<uchar>(row, col) = saturate_cast<uchar>(t*alpha + beta);
		   }
		   else{
				float b = src2.at<Vec3f>(row, col)[0];
				float g = src2.at<Vec3f>(row, col)[1];
				float r = src2.at<Vec3f>(row, col)[2];
				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha+beta);
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g*alpha + beta);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r*alpha + beta);

		   }
		}
	}
	namedWindow("output", WINDOW_AUTOSIZE);
	imshow("output", dst);

 

	waitKey(0);//不加此语句图片会一闪而过
	system("path");
	getchar();
	return 0;
}

你可能感兴趣的:(opencv)