一、概述
1.1 图像代数运算
图像代数运算是指两幅图像对应像素的加、减、乘、除运算,有其组合的运算成为复合代数运算。
1.2 功能
图像代数运算可以抑制噪声或消除噪声,也可以利用叠加运算合成新的图像。
1.3 基本运算形式
式中, 、分别为两幅输入图像在处的灰度值或彩色值。代数运算中,操作的是像素的灰度值或(彩色分量),像素的位置不变。
1.4 代数运算主程序
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
// 函数声明
void ImgAdd(Mat& inputImage_1, Mat& inputImage_2, Mat& outputImage);
int main()
{
// 载入图像并显示
Mat originImage_boy = imread("baby.png", 1);
Mat originImage_bf = imread("butterfly.png", 1);
imshow("original_boy", originImage_boy);
imshow("original_bf", originImage_bf);
// 创建效果图
Mat resultImage;
resultImage.create(originImage_boy.rows, originImage_boy.cols, originImage_boy.type());
// 记录时间
double timeClock = static_cast<double>(getTickCount());
// 两幅图像的加运算
ImgAdd(originImage_boy, originImage_bf, resultImage);
// 输出时间
timeClock = ((double)getTickCount() - timeClock) / getTickCount();
cout << "run time:" << timeClock << "seconds" << endl;
Mat resultImage_add = resultImage.clone();
addWeighted(originImage_boy, 0.5, originImage_bf, 0.5, 0, resultImage_add);
imshow("resultImage_add", resultImage_add);
imshow("result_add",resultImage);
waitKey(0);
return 0;
}
二、图像加运算
2.1 加运算基础理论:
加运算即将两幅图像对应像素的灰度值或彩色分量进行相加
2.2 功能
2.2.1 将同一场景的图像相加后再取平均,消除图像的随机噪声。
2.2.1 把多幅图像叠加在一起再进一步处理,做特效。
2.3 具体操作理论
对于灰度图像,相加的结果为对应像素的灰度值相加;对于彩色图像,对应的颜色的分量相加,若结果大于255,则置为255.
2.4 编程实例
通常,相加的两幅图像大小和尺寸应该相同。
方法一、使用迭代器对图像的像素进行操作:
void ImgAdd(Mat& inputImage_1, Mat& inputImage_2, Mat& outputImage)
{
outputImage = inputImage_1.clone();
Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>(); // outputImage的初始位置
Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>(); // outputImage的终止位置
Mat_<Vec3b>::iterator it_1 = inputImage_1.begin<Vec3b>(); // inputImage_1初始迭代器
Mat_<Vec3b>::iterator it_2 = inputImage_2.begin<Vec3b>(); // inputImage_2的初始迭代器
for(; it != itend; it++) // 遍历并相加求平均
{
(*it)[0] = ((*it_1)[0] + (*it_2)[0]) / 2;
(*it)[1] = ((*it_1)[1] + (*it_2)[1]) / 2;
(*it)[2] = ((*it_1)[2] + (*it_2)[2]) / 2;
it_1++;
it_2++;
}
}
方法一结果:
方法二、OpenCV中的addWeighted函数进行线性相加
Mat resultImage_add = resultImage.clone();
addWeighted(originImage_boy, 0.5, originImage_bf, 0.5, 0, resultImage_add);
imshow("resultImage_add", resultImage_add);
三、图像减运算
3.1 图像减运算基础理论
图像减运算就是将两幅图像对应像素的灰度值或彩色分量进行相减,若结果小于0,则为0。
3.2 功能
可以用于运动目标检测。
3.3 编程实例
法一、使用动态地址遍历计算
// 使用动态地址计算图像的减运算
void ImgSubt(Mat& inputImage_1, Mat& inputImage_2, Mat& outputImage)
{
outputImage = inputImage_1.clone();
int rowsNum = outputImage.rows;
int colsNum = outputImage.cols;
for (int i = 0; i < rowsNum; i++)
{
for (int j = 0; j < colsNum; j++)
{
outputImage.at<Vec3b>(i,j)[0] = tozero(inputImage_1.at<Vec3b>(i,j)[0] - inputImage_2.at<Vec3b>(i,j)[0]);
outputImage.at<Vec3b>(i,j)[1] = tozero(inputImage_1.at<Vec3b>(i,j)[1] - inputImage_2.at<Vec3b>(i,j)[1]);
outputImage.at<Vec3b>(i,j)[2] = tozero(inputImage_1.at<Vec3b>(i,j)[2] - inputImage_2.at<Vec3b>(i,j)[2]);
}
}
}
uchar tozero(uchar a)
{
if (a < 0)
return 0;
else
return a;
}
法一结果图:
法二、OpenCV中的addWeighted函数进行线性相加
Mat resultImage_subt = resultImage.clone();
addWeighted(originImage_boy, 1, originImage_bf, -1, 0, resultImage_subt);
imshow("resultImage_subt", resultImage_subt);
法二、结果
四、图像乘运算
4.1 图像的乘运算
将两幅图像对应的灰度值或彩色分量进行相乘。若相乘的结果大于255,则为255.
4.2 功能
主要作用是抑制图像的某些区域,对于需要保留下来的像素,与之相乘的膜为1,否则为0.(乘运算具有掩膜功能)
4.2 编程实例
使用动态地址遍历计算
// 使用动态地址计算图像的乘运算
void ImgMultiply(Mat& inputImage_1, Mat& inputImage_2, Mat& outputImage)
{
outputImage = inputImage_1.clone();
int rowsNum = outputImage.rows;
int colsNum = outputImage.cols;
for (int i = 0; i < rowsNum; i++)
{
for (int j = 0; j < colsNum; j++)
{
outputImage.at<Vec3b>(i,j)[0] = (inputImage_1.at<Vec3b>(i,j)[0] * inputImage_2.at<Vec3b>(i,j)[0]) % 256;
outputImage.at<Vec3b>(i,j)[1] = (inputImage_1.at<Vec3b>(i,j)[1] * inputImage_2.at<Vec3b>(i,j)[1]) % 256;
outputImage.at<Vec3b>(i,j)[2] = (inputImage_1.at<Vec3b>(i,j)[2] * inputImage_2.at<Vec3b>(i,j)[2]) % 256;
}
}
}
4.3 实验结果
五、图像除运算
5.1 图像除运算基本原理
图像除运算是将两幅图像对应的元素的灰度值或彩色分量进行相除。若作除数的灰度值为0,则用1代替
5.2 功能
可以改变图像的灰度级,可以用于校正非线性畸变的成像设备
5.3 编程实例
// 使用动态地址计算图像的除运算
void ImgDivide(Mat& inputImage_1, Mat& inputImage_2, Mat& outputImage)
{
outputImage = inputImage_1.clone();
int rowsNum = outputImage.rows;
int colsNum = outputImage.cols;
for (int i = 0; i < rowsNum; i++)
{
for (int j = 0; j < colsNum; j++)
{
outputImage.at<Vec3b>(i,j)[0] = (inputImage_1.at<Vec3b>(i,j)[0] * 1.0) / inputImage_2.at<Vec3b>(i,j)[0];
outputImage.at<Vec3b>(i,j)[1] = (inputImage_1.at<Vec3b>(i,j)[1] * 1.0) / inputImage_2.at<Vec3b>(i,j)[1];
outputImage.at<Vec3b>(i,j)[2] = (inputImage_1.at<Vec3b>(i,j)[2] * 1.0) / inputImage_2.at<Vec3b>(i,j)[2];
}
}
}
5.4 实验结果