4.1 图像操作
4.1.1 读写图像
Mat cv::imread(const String &filename, int flags = IMREAD_COLOR)
通过imread可以指定加载为灰度或RGB图像。
bool cv::imwrite(const String &filename, InputArray img, const std::vector<int> ¶ms=std::vector<int>())
通过imwrite可以保存为指定类型的图像文件。
4.1.2 读写像素
可以通过动态地址索引去获取像素值
读取单通道灰度图像(如:CV_8UC1)的某个像素点的像素值
Scalar Value=img.at<uchar>(y,x); //at直接获取位置为(行,列)
或
Scalar Value=img.at<uchar>(point(x,y));
读取三通道图像(RGB图像)的某个像素点的像素值
Vec3b Value =Img.at<Vec3b>(y,x);
uchar blue=Value[0];
uchar green=Value[1];
uchar red=Value[2];
4.1.3 像素操作示例
对图像进行像素值取反
int main()
{
Mat srcImg = imread("D:\\testimg\\CSet12\\lena.png");
if (srcImg.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
//显示窗口
namedWindow("srcImg", WINDOW_AUTOSIZE);
imshow("srcImg", srcImg);
//单通道
Mat grayImg;
cvtColor(srcImg,grayImg,COLOR_BGR2GRAY);
int nHeight = grayImg.rows;
int nWidth = grayImg.cols;
//显示窗口
namedWindow("grayImg", WINDOW_AUTOSIZE);
imshow("grayImg", grayImg);
for (int i = 0; i < nHeight; i++)
{
for (int j = 0; j < nWidth; j++)
{
int grayValue = grayImg.at<uchar>(i,j);
grayImg.at<uchar>(i, j) = 255 - grayValue;
}
}
//显示窗口
namedWindow("grayImg invert", WINDOW_AUTOSIZE);
imshow("grayImg invert", grayImg);
//三通道
Mat colorInvert;
colorInvert.create(srcImg.size(),srcImg.type());
int nChannels = srcImg.channels();
if (3 == nChannels)
{
for (int i = 0; i < nHeight; i++)
{
for (int j = 0; j < nWidth; j++)
{
int bValue = srcImg.at<Vec3b>(i, j)[0];
int gValue = srcImg.at<Vec3b>(i, j)[1];
int rValue = srcImg.at<Vec3b>(i, j)[2];
colorInvert.at<Vec3b>(i, j)[0] = 255 - bValue;
colorInvert.at<Vec3b>(i, j)[1] = 255 - gValue;
colorInvert.at<Vec3b>(i, j)[1] = 255 - rValue;
}
}
//显示窗口
namedWindow("srcImg invert", WINDOW_AUTOSIZE);
imshow("srcImg invert", colorInvert);
}
else;
waitKey(0);
return 0;
}
结果图如下所示:
4.2 图像混合
4.2.1 线性混合操作
对于两个图像的线性混合可以用以下公式表征:
其中的取值范围在0~1之间,
、
为两张待混合的图像,g(x)为混合后的图像;
4.2.2 addWeighted函数
该函数的作用就是将两张源图片以一定的权重进行混合;
void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype=-1
参数 | 含义 | |
作用 | 对两个图像进行加权混合,得到新的图像 | |
输入 | src1 | 需要混合的原图1 |
alpha | src1的权重值 | |
src1 | 需要混合的原图2 | |
beta | src2的权重值 | |
gamma | 添加到每一个线性叠加总和的gamma值 | |
dst | 混合后的结果图 | |
dtype | 目标图像深度,当两幅图像深度相同时可以将dtype置为-1,这样目标图像的深度将与输入图像相同 | |
返回值 | void | 无 |
注意事项:
- 需要混合的两个图像,其图像大小和类型必须一致;
- dst = src1*alpha + src2*beta + gamma;
4.2.3 代码示例
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat srcImg1 = imread("D:\\testimg\\CSet12\\lena.png");
Mat srcImg2 = imread("D:\\testimg\\CSet12\\House.png");
if (srcImg1.empty())
{
printf("Could not load the image1...\n");
return -1;
}
else;
if (srcImg2.empty())
{
printf("Could not load the image2...\n");
return -1;
}
else;
//显示窗口
namedWindow("srcImg1", WINDOW_AUTOSIZE);
imshow("srcImg1", srcImg1);
//显示窗口
namedWindow("srcImg2", WINDOW_AUTOSIZE);
imshow("srcImg2", srcImg2);
if (srcImg1.size() == srcImg2.size() && srcImg1.type() == srcImg2.type())
{
Mat dst;
double dAlpha = 0.5;
double dBeta = 0.5;
double dGamma = 0;
addWeighted(srcImg1,dAlpha,srcImg2,dBeta,dGamma,dst);
//add(srcImg1, srcImg2,dst,Mat());//进行两幅图像相加
//multiply(srcImg1, srcImg2, dst, 1.0);//进行两幅图像相乘
//显示窗口
namedWindow("addWeight Img", WINDOW_AUTOSIZE);
imshow("addWeight Img", dst);
}
else
{
printf("Could not blend image,the size or type is not same...\n");
return -1;
}
waitKey(0);
return 0;
}
结果图像(alpha=0.5,beta=0.5,gamma=0):
以下对比直接相加和相乘的差异:
无权重相加的时候,直接相加或相乘,单个像素值的大小容易大于255,及像素点赋值255。
4.3 图像调整(亮度和对比度)
图像变换可以分为两类(像素变换--点操作,领域操作--区域)
- 点运算也称为对比度增强和拉伸、灰度变换。常用于改变图像的灰度范围和分布,如光度学标定、对比度增强、显示增强、轮廓线确定、图像裁剪等。
- 领域操作是指输出图像的像素点取值决定于输入图像的某个像素点及其领域内的像素,通常远小于图像自身尺寸、形状规则的像素块。通常使用于图像卷积、整体特征提取、梯度计算、模式匹配前处理、模糊、角点检测等。
这里介绍的调整图像亮度和对比度属于像素变换-点操作
其中
是增益变量。
4.3.1 代码示例
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
Mat srcImg = imread("D:\\testimg\\CSet12\\lena.png");
if (srcImg.empty())
{
printf("Could not load the image...\n");
return -1;
}
else;
//显示窗口
char input_win[] = "srcImg";
namedWindow(input_win, WINDOW_AUTOSIZE);
imshow(input_win, srcImg);
//对比度和亮度调整
int nHeight = srcImg.rows;
int nWidth = srcImg.cols;
Mat dst = Mat::zeros(srcImg.size(),srcImg.type());
float fAlpha = 1.5;
float fBeta = 10;
for (int i = 0;i < nHeight; i++)
{
for (int j = 0;j < nWidth; j++)
{
if (3 == srcImg.channels())
{
float b = srcImg.at<Vec3b>(i,j)[0];
float g = srcImg.at<Vec3b>(i, j)[1];
float r = srcImg.at<Vec3b>(i, j)[2];
dst.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(fAlpha*b+ fBeta);
dst.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(fAlpha*g + fBeta);
dst.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(fAlpha*r + fBeta);
}
else if (1 == srcImg.channels())
{
float v = srcImg.at<uchar>(i, j);
dst.at<uchar>(i, j) = saturate_cast<uchar>(fAlpha*v + fBeta);
}
}
}
namedWindow("contract and brightness change");
imshow("contract and brightness change", dst);
waitKey(0);
return 0;
}