图片可以进行组合计算,因为图片可以被看作是矩阵;矩阵可以进行加减乘除的四则运算。
1.加法计算,以叠加两张图片为例
在向图片添加一些效果,或者叠加一些信息时,可以将两张图片叠加。
可以调用 cv::add 或者 cv::addWeighted 方法将两张图片叠加,后者拥有权重参数,来决定两张图片叠加时,各自的权重
cv::add(image1, image2, result);
cv::addWeighted(image1, 0.5, image2, 0.5, 0. , result);
这些算数计算方法,默认内部都使用了 cv::saturate_cast 方法来确保计算结果的像素值,处于合法值域范围内。
可以将输入的图片之一,作为结果参数。可以避免 result 做一次内存分配。
示例代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <chrono>
int main(int argc, char *argv[])
{
// 检查命令行参数
if (argc != 4)
{
std::cerr << "Usage: " << argv[0] << " <input_image1> <input_image2> <output_image>" << std::endl;
return -1;
}
// 读取输入图像和logo图像
cv::Mat input_image1 = cv::imread(argv[1]);
// 检查输入图像和logo图像是否成功读取
if (input_image1.empty())
{
std::cerr << "Error: Could not open or find input image" << std::endl;
}
// 读取输入图像和logo图像
cv::Mat input_image2 = cv::imread(argv[2]);
// 检查输入图像和logo图像是否成功读取
if (input_image2.empty())
{
std::cerr << "Error: Could not open or find input image" << std::endl;
}
cv::namedWindow("input_image1", cv::WINDOW_NORMAL);
cv::imshow("input_image1", input_image1);
cv::namedWindow("input_image2", cv::WINDOW_NORMAL);
cv::imshow("input_image2", input_image2);
cv::waitKey(0);
cv::Mat result;
const int64 start = cv::getTickCount();
//注意,需要图片尺寸格式一只,也就是行列数,通道数一致。
#if 0 //[1]
//result[i] = input_image1[i] + input_image2[i]
//cv::add(input_image1, input_image2, result);
#endif
#if 0 //[2]
//result[i] = input_image1[i] * 0.5 + input_image2[i] * 0.5 + 0
cv::addWeighted(input_image1, 0.5, input_image2, 0.5, 0, result);
#endif
#if 0 //[3]
//result[i] = input_image1[i] + 50
cv::add(input_image1, cv::Scalar(50), result);
#endif
#if 0 //[4]
//result[i] = input_image1[i] * 0.5 + input_image2[i]
cv::scaleAdd(input_image1, 0.5, input_image2, result);
#endif
#if 0 //[5.1]
//mask-8位单通道数组,指定要更改的输出数组的元素
cv::Mat mask = cv::Mat::zeros(input_image1.size(), CV_8UC1);
//上半截参与计算
mask(cv::Rect(0, 0, mask.cols, mask.rows / 2)).setTo(cv::Scalar(255));
//if(mask[i] != 0) result[i] = input_image1[i] + input_image2[i]
cv::add(input_image1, input_image2, result, mask);
#endif
#if 1 //[5.2]
//mask-8位单通道数组,指定要更改的输出数组的元素
cv::Mat mask = cv::Mat::zeros(input_image1.size(), CV_8UC1);
//中部1/3参与计算
mask(cv::Rect(0, mask.rows / 3, mask.cols, mask.rows / 3)).setTo(cv::Scalar(255));
//使用图片二作为背景 ,这里 result是引用的input_image2
result = input_image2;
//if(mask[i] != 0) result[i] = input_image1[i] + input_image2[i]
cv::add(input_image1, input_image2, result, mask);
#endif
const int64 end = cv::getTickCount();
std::cout << "sharpen used time: " << (end - start) / cv::getTickFrequency() << "s" << std::endl;
cv::imwrite(argv[3], result);
cv::namedWindow("result", cv::WINDOW_NORMAL);
cv::imshow("result", result);
cv::waitKey(0);
return 0;
}
准备两张图片,进行叠加结果如下:
[2] addWeighted

注意,需要图片尺寸格式一只,也就是行列数,通道数一致。
否则,会报异常:
terminate called after throwing an instance of ‘cv::Exception’
what(): OpenCV(4.12.0) /mnt/c/mine/largescalecppv1/image_processing/opencv-4.12.0/modules/core/src/arithm.cpp:662: error: (-209:Sizes of input arguments do not match) The operation is neither ‘array op array’ (where arrays have the same size and the same number of channels), nor ‘array op scalar’, nor ‘scalar op array’ in function ‘arithm_op’Aborted (core dumped)
[5.1] add 使用mask, 只计算上半截

[5.2] add 使用mask, 只计算中间2/3截,并且将 image2作为结果图片。

2.其它计算方法
OpenCV提供大量的计算方法。
cv::subtract
cv::absdiff
cv::multiply
cv::divide
Bitwise operators
cv::bitwise_and
cv::bitwise_or
cv::bitwise_xor
cv::bitwise_not
cv::min
cv::max
cv::sqrt
cv::pow
cv::abs
cv::exp
cv::log
示例代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <chrono>
//图片相减,特别示例mask用法
void subtract_demo(const cv::Mat &input_image1, const cv::Mat &input_image2, cv::Mat &result)
{
//mask-8位单通道数组,指定要更改的输出数组的元素
cv::Mat mask = cv::Mat::zeros(input_image1.size(), CV_8UC1);
//中部1/3参与计算
mask(cv::Rect(0, mask.rows / 3, mask.cols, mask.rows / 3)).setTo(cv::Scalar(255));
//使用图片二作为背景
result = input_image2;
//if(mask[i] != 0) result[i] = input_image1[i] + input_image2[i]
cv::subtract(input_image1, input_image2, result, mask);
}
//计算两个图片之间各个像素的绝对差值
//实质是,计算两个数组之间或数组与标量之间的每个元素的绝对差。
void absdiff_demo(const cv::Mat &input_image1, const cv::Mat &input_image2, cv::Mat &result)
{
cv::absdiff(input_image1, input_image2, result);
}
//计算两个数组的按元素缩放的乘积。
void multiply_demo(const cv::Mat &input_image1, const cv::Mat &input_image2, cv::Mat &result)
{
//缩放因子 0.01 不然会溢出,全 255, 全白了
cv::multiply(input_image1, input_image2, result);
cv::multiply(input_image1, input_image2, result, 0.01);
}
/*
cv::divide
//Bitwise operators
cv::bitwise_and
cv::bitwise_or
cv::bitwise_xor
cv::bitwise_not
cv::min
cv::max
cv::sqrt
cv::pow
cv::abs
cv::exp
cv::log
*/
int main(int argc, char *argv[])
{
// 检查命令行参数
if (argc != 4)
{
std::cerr << "Usage: " << argv[0] << " <input_image1> <input_image2> <output_image>" << std::endl;
return -1;
}
// 读取输入图像和logo图像
cv::Mat input_image1 = cv::imread(argv[1]);
// 检查输入图像和logo图像是否成功读取
if (input_image1.empty())
{
std::cerr << "Error: Could not open or find input image" << std::endl;
}
// 读取输入图像和logo图像
cv::Mat input_image2 = cv::imread(argv[2]);
// 检查输入图像和logo图像是否成功读取
if (input_image2.empty())
{
std::cerr << "Error: Could not open or find input image" << std::endl;
}
cv::namedWindow("input_image1", cv::WINDOW_NORMAL);
cv::imshow("input_image1", input_image1);
cv::namedWindow("input_image2", cv::WINDOW_NORMAL);
cv::imshow("input_image2", input_image2);
cv::waitKey(0);
cv::Mat result;
const int64 start = cv::getTickCount();
//注意,需要图片尺寸格式一只,也就是行列数,通道数一致。
//subtract_demo(input_image1,input_image2,result);
//absdiff_demo(input_image1,input_image2,result);
multiply_demo(input_image1,input_image2,result);
const int64 end = cv::getTickCount();
std::cout << "sharpen used time: " << (end - start) / cv::getTickFrequency() << "s" << std::endl;
cv::imwrite(argv[3], result);
cv::namedWindow("result", cv::WINDOW_NORMAL);
cv::imshow("result", result);
cv::waitKey(0);
return 0;
}
subtract_demo 结果:
高亮像素值减暗像素值,会更多的保留原始颜色。
暗像素值减比它更亮的值,会变成负数,然后被归为 0 ,也就是还是暗的。
颜色像素值接近,减完会变成暗色。

absdiff_demo 结果:
计算每个像素间的绝对差值。
也就是两个图片像素的颜色值越相近,结果就越暗。
越亮,或者最终结果保留了亮部的结果的,就是这个像素值位置,是一明一暗的状态,最终计算绝对差值,更接近亮值,所以亮值的信息存留了下来。
中部的天空。最右侧的绿色骆驼。
中部的天空和太阳都处于两张图片的亮部,颜色亮度上差值较小,所以最终看起来更黑。

multiply_demo 结果
每个像素相乘,亮的更亮,暗的,特别是黑色的部分就是黑洞,乘完还是零,所以保留了黑色。
最后的结果还挺好玩的。

815

被折叠的 条评论
为什么被折叠?



