c++ opencv4.5.5 学习笔记(三) 图像基本操作(读入、保存、遍历像素at()、ROI、通道转换)

图像基本操作

    • 一、输入/输出
      • 1.1、输入
      • 1.2、保存图像
      • 1.3、可视化图像
    • 二、访问像素值
      • 2.1、at()函数
      • 2.2、使用迭代器
      • 2.3、感兴趣区域ROI
    • 三、内存管理和引用计数
    • 四、通道转换
    • 五、缩放
    • 六、旋转
    • 七、对比度与亮度

一、输入/输出

1.1、输入

从文件加载图像:

Mat imread( const String& filename, int flags = IMREAD_COLOR )
filename:文件名
flags:读取图片的颜色类型

支持图片格式:  
  1、windows位图:*.bmp,*.dib 
  2、JPEG文件:*.jpg,*.jpe,*.jpeg
  3、JPEG 2000 文件
  4、PNG 图片:*.png
  5、便携文件格式  
  6、Sun rasters
  7、TIFF文件
flags参数:
  CV_LOAD_IMAGE_ANYDEPTH 返回图像的深度不变
   CV_LOAD_IMAGE_COLOR 总是返回一个彩色图
  CV_LOAD_IMAGE_GRAYSCALE 总是返回一个灰度图
   flag =-1,8位深度,原通道
  flag = 0,8位深度,1通道
  flag = 1, 8位深度,3通道
  flag = 2,原深度 ,1通道
   flag = 3, 原深度 ,3通道
  flag = 4,8位深度,3通道

1.2、保存图像

imwrite(filename,img)

注意:
  文件的格式由其扩展名决定。
  使用imdecode和imencode从/到内存而不是文件读写图像。

1.3、可视化图像

Mat img = imread(“image.jpg”);
namedWindow(“image”,WINDOW_AUTOSIZE);
imshow(“image”,img);

完整代码如下:

#include 
#include 

int readAndWriteDemo()
{
	//读入图片
	std::string imagename = "Standard_image/lena.jpg";
	cv::Mat img = cv::imread(imagename);
	//如果读入图像失败
	if (img.empty())
	{
		std::cout << "miss the image file : " + imagename << std::endl;
		return - 1;
	}
    
    cv::imwrite("savelena.jpg", imagename);
    
	//创建窗口
	cv::namedWindow("image", 1);
	//显示图像
	cv::imshow("image", img);
	//等待按键,按键盘任意键返回
	cv::waitKey(0);

	return 0;
}

二、访问像素值

2.1、at()函数

为了获得像素强度值,您必须知道图像的类型和通道数。以下是单通道灰度图像(类型8UC1)和像素坐标x和y的示例:

Scalar intensity = img.at(y, x);

函数 at()来实现读去矩阵中的某个像素,或者对某个像素进行赋值操作。下面两行代码演示了 at()函数的使用方法。

uchar value = grayim.at(i,j);//读出第 i 行第 j 列像素值
grayim.at(i,j)=128; //将第 i 行第 j 列像素值设置为 128

要对图像进行遍历例程代码

#include 
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

int usingAtDemo(int argc, char* argv[])
{
	Mat grayimg(600, 800, CV_8UC1);   //单通道
 	Mat colorimg(600, 800, CV_8UC3);  //三通道
 	//遍历所有像素,并设置像素值
 	for( int i = 0; i < grayimg.rows; ++i)
 		for( int j = 0; j < grayimg.cols; ++j )
 			grayimg.at<uchar>(i,j) = (i+j)%255;
 	//遍历所有像素,并设置像素值
 	for( int i = 0; i < colorimg.rows; ++i)
 		for( int j = 0; j < colorimg.cols; ++j )
 		{
 			Vec3b px;
 			px[0] = i%255; //Blue
 			px[1] = j%255; //Green
 			px[2] = 0;     //Red
 			colorimg.at<Vec3b>(i,j) = px;
 		}
 	//显示结果
 	imshow("grayimg", grayimg);
 	imshow("colorimg", colorimg);
 	waitKey(0);
 	return 0;
}

2.2、使用迭代器

迭代器可以方便地遍历所有元素。Mat 也增加了迭代器的支持,以便于矩阵元素的遍历。

#include 
#include 

int usingSTLDemo(int argc, char* argv[])
{
	//创建 mat 类
	//CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
	cv::Mat grayimg(600, 800, CV_8UC1, cv::Scalar(0)); //创建行数为 600,列数为 800,通道数为 1 的图像, Scalar并初始化位0
	cv::Mat colorimg(600, 800, CV_8UC3);

	//遍历所有像素,并设置像素值 MatIterator_ 是一个迭代器
	cv::MatIterator_<uchar> grayit, grayend;
	for (grayit = grayimg.begin<uchar>(), grayend = grayimg.end<uchar>(); grayit != grayend; ++grayit)
	{
		*grayit = rand() % 255;
	}

	//遍历所有像素,并设置像素值, MatIterator_ 是一个迭代器
	cv::MatIterator_<cv::Vec3b> colorit, colorend;
	for (colorit = colorimg.begin<cv::Vec3b>(), colorend = colorimg.end<cv::Vec3b>(); colorit != colorend; ++colorit)
	{
		*colorit = (255, 255, 255);
	}
	
	//显示结果
	cv::imshow("grayim", grayimg);
	cv::imshow("colorim", colorimg);
	cv::waitKey(0);

	return 0;
}

2.3、感兴趣区域ROI

  • ROI(region of interest),这个区域是图像分析所关注的重点。我们圈定这个区域,以便进行进一步处理。
  • 优点:使用ROI定想读入的目标,可以减少处理时间,增加精度,给图像处理来带不小的便利。

定义ROI区域

  • 注意:图像坐标是先说列(长),再说行(宽),原点在窗口左上角

方法一:使用构造函数

 //创建宽度为 320,高度为 240 的 3 通道图像
Mat img(Size(320,240),CV_8UC3);
//roi 是表示 img 中 Rect(10,10,100,100)区域的对象
//Rect四个形参分别是:x坐标,y坐标,长,高;注(x,y)指矩形的左上角点;
Mat roi(img, Rect(10,10,100,100));

方法二:括号运算符

Mat roi = img(Rect(10,10,100,100));

方法三: Range 对象来定义感兴趣区域

//指定感兴趣行或列的范围(Range),Range是指从起始索引到终止索引的一段联系序列
Mat roi = img(Range(250, 250 +xleng), Range(200, 200 + yleng));
//Range两个形参分别是:起始行或列,起始行或列+偏移量

三、内存管理和引用计数

Mat是一种保持矩阵/图像特征(行和列数,数据类型等)和指向数据的指针的结构。所以没有什么可以阻止我们有几个Mat对应于相同数据的实例。当Mat的特定实例被破坏时,Mat保留一个引用计数,指示数据是否必须被释放。以下是创建两个矩阵而不复制数据的示例:

std::vector<Point3f> points;
// .. fill the array
Mat pointsMat = Mat(points).reshape(1);

因此,我们得到一个32FC1矩阵与3列而不是32FC3矩阵与1列。pointsMat使用点数据,销毁时不会释放内存。然而,在这种特殊情况下,开发人员必须确保点的生命周期比pointMat长。如果我们需要复制数据,可以使用例如cv :: Mat :: copyTo或cv :: Mat :: clone:

Mat img = imread(“image.jpg”);
Mat img1 = img.clone();

四、通道转换

从颜色到灰度的转换:

Mat img = imread("image.jpg"); // loading a 8UC3 image
Mat grey;
cvtColor(img, grey, COLOR_BGR2GRAY);

将图像类型从8UC1更改为32FC1:

src.convertTo(dst,CV_32F);

五、缩放

#include 
#include 

int main()
{
	//读入图片
	std::string imagename = "Standard_image/lena.jpg";
	cv::Mat img = cv::imread(imagename), resizeimg, resizeimg2;
	//如果读入图像失败
	if (img.empty())
	{
		std::cout << "miss the image file : " + imagename << std::endl;
		return -1;
	}

	cv::resize(img, resizeimg, cv::Size(img.cols / 2.0, img.rows / 2.0));
	cv::resize(img, resizeimg2, cv::Size(img.cols * 1.2, img.rows * 1.2));

	//显示图像
	cv::imshow("原图", img);
	cv::imshow("缩小", resizeimg);
	cv::imshow("放大", resizeimg2);
	//等待按键,按键盘任意键返回
	cv::waitKey();

	return 0;
}

六、旋转

#include 
#include 

int rotateDemo()
{
	cv::Mat src, dst;
	float angle = - 90.0;
	
	src = cv::imread("Standard_image/lena.jpg", cv::IMREAD_COLOR);
	//从文件读入图片
	cv::Point2f center = cv::Point2f(static_cast<float>(src.cols / 2), static_cast<float>(src.rows / 2)); 
	//定义中心点的坐标,2f的意思为float型,中心点极为X,Y即宽度与高度的二分之一
	cv::Mat affineTrans = cv::getRotationMatrix2D(center, angle, 1.0);
	//getRotationMatrix2D为图像旋转的函数
	//第一个参数center是旋转中心点
	//第二个参数angle为旋转角度
	//第三个1.0的参数为double scale:图像缩放因子


	cv::warpAffine(src, dst, affineTrans, src.size());
	//cv::warpAffine(src, dst, affineTrans, src.size(), cv::INTER_CUBIC, cv::BORDER_REPLICATE);
	//仿射变换函数warpAffine
	//第一个参数src为输入原图像
	//第二个参数dst为输出图像
	//第三个参数为affineTrans转换矩阵
	//第四个参数为输出图像的size大小
	//第五个参数为立方差值法
	//第六个参数为边界用上下行或者左右列来复制填充

	cv::imshow("src", src);
	cv::imshow("dst", dst);
	//显示图片

	cv::waitKey(0);
	//等待按键下

	return 0;

}

七、对比度与亮度

#include 
#include 

#define NAME "name"

//g(x) = alpha*f(x) + beta
int alpha = 100;  //对比度
int beta = 0;     //亮度
cv::Mat img;

void ProcessOpt()
{
	//创建初始化为0的图片矩阵
	cv::Mat new_img = cv::Mat::zeros(img.size(), img.type());
	//
	img.convertTo(new_img, -1, alpha*0.01, beta);

	cv::imshow(NAME, new_img);
	
}

void onAlphaChange(int, void*)
{
	ProcessOpt();
}

void onBetaChange(int, void*)
{
	ProcessOpt();
}

int demo()
{

	img = cv::imread("Standard_image/lena.jpg", cv::IMREAD_COLOR);
	//定义窗口名字
	cv::namedWindow(NAME);
	//创建滑块
	cv::createTrackbar("alpha", NAME, &alpha, 100, onAlphaChange);
	cv::createTrackbar("beta", NAME, &beta, 100, onBetaChange);

	cv::waitKey(0);
	return 0;

}

你可能感兴趣的:(opencv,学习笔记,opencv,计算机视觉,图像处理)