C++ OpenCV4.5 图像处理(三)
·
系列文章目录
C++ OpenCV4.5环境搭建(一)
C++ OpenCV4.5常用API查询手册(二)
文章目录
前言
该篇主要讲解OpenCV对图像的部分处理
一、加载/修改/保存图片
添加一个新建源文件main.cpp,代码如下(示例):
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(void)
{
// 加载图像文件成为一个Mat对象
Mat img = imread("E:\\1.jpg");
if (img.empty())
{
cout << "can not load image.." << endl;
return -1;
}
// 创建一个OpenCV窗口
namedWindow("测试");
// 根据窗口名称显示图像到指定窗口
imshow("测试", img);
Mat outImg;
// 将一个图像转换成灰度图像
cvtColor(img, outImg,COLOR_BGR2GRAY);
namedWindow("测试输出");
imshow("测试输出", outImg);
// 保存图像文件到指定路径,只有8位和16位的PNG、JPG和Tiff文件格式,并且是单通道或三通道的BGR的图像才可通过改方式保存;保存PNG格式的时候可以保存透明通道图片;可以指定压缩参数
imwrite("D:\\out.jpg",outImg);
// waitKey是给它一个指令才关闭,waitKey(0)等待键盘按下时关闭,任意键
waitKey(0);
return 0;
}
二、掩膜操作
1、掩膜操作原理
矩阵的掩膜操作很简单,就是先读取每个像素点的像素值,根据计算公式来重新计算该像素点的像素值,计算公式如下:
I(i, j) = 5*(i, j) - [I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]
如下图所示,红色是中心像素,中心像素×5,减去上下左右四个点的像素,最终结果复制给中心像素;
从上到下、从左到右,对每个像素做相同处理,重新计算每个像素的像素值,最终结果就是对比度提高后的输出图像Mat对象;
| 0 -1 0 |
| 1 5 -1 |
| 0 -1 0 |
1、读取像素值
读取一个单通道GRAY像素点的像素值(CV_8UC1)
int intensity = img.at<uchar>(x, y);
//或
int intensity = img.at<uchar>(Point(x, y));
读取一个三通道RGB像素点的像素值
// Vec3b对应的三通道顺序是blue、green、read的uchar类型数据
Vec3b intensity = img.at<Vec3b>(x, y);
int blue = intensity.val[0];
int green = intensity.val[1];
int red = intensity.val[2];
2、修改像素值
修改一个单通道GRAY图像的像素值
img.at<uchar>(x, y) = 128;
修改一个三通道RGB图像的像素值
img.at<Vec3b>(x, y)[0] = 128; // blue
img.at<Vec3b>(x, y)[1] = 128; // green
img.at<Vec3b>(x, y)[2] = 128; // red
空白图像赋值
img = Scalar(0);
示例代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(void)
{
Mat srcImg, dstImg;
srcImg = imread("D:\\1.jpg");
if (!srcImg.data)
{
cout << "can not load image.." << endl;
return -1;
}
namedWindow("测试");
imshow("测试", srcImg);
dstImg.create(srcImg.size(), srcImg.type());
int iHeight = srcImg.rows;
int iWidth = srcImg.cols;
int iChannels = srcImg.channels();
for (int row = 0; row < iHeight; ++row)
{
for (int col = 0; col < iWidth; ++col)
{
if (iChannels == 1)
{
int iGray = srcImg.at<uchar>(row, col);
// 翻转图像颜色(源像素 = 255 - 源像素)
dstImg.at<uchar>(row, col) = 255 - iGray;
}
else
{
int iB = srcImg.at<Vec3b>(row, col)[0];
int iG = srcImg.at<Vec3b>(row, col)[1];
int iR = srcImg.at<Vec3b>(row, col)[2];
// 翻转图像颜色(源像素 = 255 - 源像素)
dstImg.at<Vec3b>(row, col)[0] = 255 - iB;
dstImg.at<Vec3b>(row, col)[1] = 255 - iG;
dstImg.at<Vec3b>(row, col)[2] = 255 - iR;
}
}
}
// 翻转图像颜色,效果与(源像素 = 255 - 源像素)一样
//bitwise_not(srcImg, dstImg);
namedWindow("测试输出");
imshow("测试输出", dstImg);
waitKey(0);
return 0;
}
3、掩膜操作实现
代码如下(示例):
#include <opencv2/opencv.hpp>
#include <Windows.h>
using namespace std;
using namespace cv;
int main(void)
{
Mat srcImg, dstImg;
srcImg = imread("D:\\1.png");
if (!srcImg.data)
{
cout << "can not load image.." << endl;
return -1;
}
namedWindow("测试");
imshow("测试", srcImg);
/************************方法一*************************/
// 像素列数,等于图像列数*通道数,因为第一列不计算,所以列数-1
int iCols = (srcImg.cols - 1) * srcImg.channels();
// 像素行数
int iRows = srcImg.rows;
// 像素列数起始偏移长度
int iOffsetY = srcImg.channels();
// 根据源图像的大小和图片类型,创建一个空的Mat对象
dstImg = Mat::zeros(srcImg.size(), srcImg.type());
for (int row = 1; row < iRows - 1; ++row)
{
// Mat.ptr<uchar>(int i):获取像素矩阵的指针,索引i表示第几行,从0开始计数
// 获取源图像前一行的像素矩阵指针
const uchar* pPrevious = srcImg.ptr<uchar>(row - 1);
// 获取源图像当前行的像素矩阵指针
const uchar* pCurrent = srcImg.ptr<uchar>(row);
// 获取源图像下一行的像素矩阵指针
const uchar* pNext = srcImg.ptr<uchar>(row + 1);
// 获取目标图像当前行像素矩阵指针
uchar* pOutput = dstImg.ptr<uchar>(row);
for (int col = iOffsetY; col < iCols; ++col)
{
// 掩膜计算公式:I(i, j) = 5*(i, j) - [I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]
// saturate_cast<uchar>:像素范围处理,确保RGB值的范围在0-255之间,小于0返回0,大于255返回255,其他返回实际的值
pOutput[col] = saturate_cast<uchar>(5 * pCurrent[col] -
(pCurrent[col - iOffsetY] + pCurrent[col + iOffsetY] + pPrevious[col] + pNext[col]));
}
}
/************************方法二*************************/
/*
// 定义一个掩膜
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
// filter2D:图像卷积运算函数
// 参数一:源图像,Mat类型对象
// 参数二:目标图像,Mat类型对象
// 参数三:位图深度,有32、24、8等
// 参数四:掩膜,Mat类型对象
filter2D(srcImg, dstImg, srcImg.depth(), kernel);
*/
namedWindow("测试输出");
imshow("测试输出", dstImg);
waitKey(0);
return 0;
}
三、图像混合
1、理论-线性混合操作
计算公式如下图

2、相关API(addWeighted)
// 功能:图像混合,两张图像的大小和类型必须一致
// 参数:src1 输入图像1,Mat对象类型
// alpha 输入图像1的混合权重
// src2 输入图像2,Mat对象类型
// beta 输入图像2的混合权重
// gamma 图像1与图像2的像素值、通过上面的公式相加后,会加上该数值
// dst 输出混合图像,Mat对象类型
// dtype ...默认-1
// 返回:无
void addWeighted(InputArray src1, double alpha, InputArray src2,
double beta, double gamma, OutputArray dst, int dtype = -1);
代码如下(示例):
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(void)
{
Mat srcImg, srcImg2, dstImg;
srcImg = imread("D:\\1.jpg");
if (!srcImg.data)
{
cout << "can not load image1.." << endl;
return -1;
}
srcImg2 = imread("D:\\2.jpg");
if (!srcImg2.data)
{
cout << "can not load image2.." << endl;
return -1;
}
double dAlpha = 0.5;
if (srcImg.rows == srcImg2.rows && srcImg.cols == srcImg2.cols && srcImg.type() == srcImg2.type())
{
addWeighted(srcImg, dAlpha, srcImg2, 1 - dAlpha, 0, dstImg);
imshow("测试", srcImg);
imshow("测试2", srcImg2);
imshow("测试输出", dstImg);
}
waitKey(0);
return 0;
}
四、调整图像亮度与对比度
调整图像亮度和对比度属于像素变换-点操作,公式如下
g(i, j) = αƒ(i, j) + β,其中α > 0,β是增益变量
示例代码如下:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat srcImg, dstImg;
srcImg = imread("/home/lzy/1.jpeg");
if(!srcImg.data)
{
cout << "load image failed.." << endl;
return -1;
}
Mat srcImgGray;
cvtColor(srcImg, srcImgGray, COLOR_BGR2GRAY);
imshow("测试", srcImgGray);
int iRows = srcImg.rows;
int iCols = srcImg.cols;
dstImg = Mat::zeros(srcImgGray.size(), srcImgGray.type());
float fAlpha = 1.8;
float fBeta = 30;
for(int i=0; i<iRows; i++)
{
for(int j=0; j<iCols; j++)
{
if(srcImgGray.channels() == 1)
{
float f = srcImgGray.at<uchar>(i, j);
dstImg.at<uchar>(i, j) = saturate_cast<uchar>(f * fAlpha + fBeta);
}
else if(srcImg.channels() == 3)
{
float fGreen = srcImg.at<Vec3b>(i, j)[0];
float fBlue = srcImg.at<Vec3b>(i, j)[1];
float fRed = srcImg.at<Vec3b>(i, j)[2];
dstImg.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(fGreen * fAlpha + fBeta);
dstImg.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(fBlue * fAlpha + fBeta);
dstImg.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(fRed * fAlpha + fBeta);
}
}
}
imshow("测试输出", dstImg);
waitKey(0);
return 0;
}
更多推荐
所有评论(0)