一、实现简单的图像运算
【事前准备】准备两张大小一样的图片
【实现】
cv::Mat image1;
image1 = cv::imread("1.jpg");
cv::Mat image2 = cv::imread("1.1.jpg");
cv::Mat result;
cv::addWeighted(image1, 0.7, image2, 0.9, 0., result);//加运算
cv::namedWindow("AddImage");
cv::imshow("AddImage", result);
cv::waitKey(0);
【实现原理】二进制运算函数:提供两个输入参数,指定一个输出参数,有时需要指定加权系数(可以把其中的一个输入图像用作输出图像)。cv::add就是典型的有多种格式的函数。
// c[i]= a[i]+b[i];
cv::add(imageA,imageB,resultC);
// c[i]= a[i]+k;
cv::add(imageA,cv::Scalar(k),resultC);
// c[i]= k1*a[i]+k2*b[i]+k3;
cv::addWeighted(imageA,k1,imageB,k2,k3,resultC);
// c[i]= k*a[i]+b[i];
cv::scaleAdd(imageA,k,imageB,resultC);
// 如果(mask[i]) c[i]= a[i]+b[i];
cv::add(imageA,imageB,resultC,mask);
注:(1)使用掩码后,操作只在掩码值非空的像素上执行(掩码必须是单通道的)。
(2)在所有场合都要使用 cv::saturate_cast 函数,以确保结果在预定 的像素值范围之内
【扩展阅读】cv::Mat也可以用普通的C++运算符
1. 重载图像运算符
cv::addWeighted也可以写成
result = 0.7 * image1 + 0.9 * image2;
这两种方 法都会调用 cv::saturate_cast 函数
大部分 C++运算符都已被重载,其中包括位运算符&、 |、 ^、~和函数 min、max、abs。比较运算符和>=也已被重载,它们返回一个 8 位的二值图像。此外还有矩 阵乘法 m1*m2(其中 m1 和 m2 都是 cv::Mat 实例)、矩阵求逆 m1.inv()、变位 m1.t()、行列 式 m1.determinant()、求范数 v1.norm()、叉乘 v1.cross(v2)、点乘 v1.dot(v2),等等。
//减色函数可以用以下代码简单地进行重写
image=(image&cv::Scalar(mask,mask,mask))
+cv::Scalar(div/2,div/2,div/2);
2.分割图像通道:我们有时需要分别处理图像中的不同通道,例如只对图像中的一个通道执行某个操作。这当 然可以通过图像扫描循环实现,但也可以使用 cv::split 函数,将图像的三个通道分别复制到 三个 cv::Mat 实例中。假设我们要把一张雨景图只加到蓝色通道中,可以这样实现:
// 创建三幅图像的向量
std::vector<cv::Mat> planes;
// 将一个三通道图像分割为三个单通道图像
cv::split(image1,planes);
// 加到蓝色通道上
planes[0]+= image2;
// 将三个单通道图像合并为一个三通道图像
cv::merge(planes,result);
//这里的 cv::merge 函数执行反向操作,即用三个单通道图像创建一个彩色图像。
二、图像重映射
【实现】
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>
#include<random>
using namespace std;
using namespace cv;
//重映射图像,创建波浪形效果
void wave(const cv::Mat& image, cv::Mat& result) {
//映射参数
cv::Mat srcX(image.rows, image.cols, CV_32F);
cv::Mat srcY(image.rows, image.cols, CV_32F);
//创建映射参数
for (int i = 0; i < image.rows; i++) {
for (int j = 0; j < image.cols; j++) {
//(i,j)像素的新位置
srcX.at<float>(i, j) = j;//保持在同一列
//原来在第i行的像素,现在根据一个正弦曲线移动
srcY.at<float>(i, j) = i + 5 * sin(j / 10.0);
}
}
//应用映射参数
cv::remap(image, //源图像
result, //目标图像
srcX, //x映射
srcY, //y映射
cv::INTER_LINEAR);//填补方法
}
int main()
{
cv::Mat image;
image = cv::imread("1.jpg");
cv::Mat result;
wave(image, result);
cv::namedWindow("WaveImage");
cv::imshow("WaveImage", result);
cv::waitKey(0);
}
【实现原理】
先创建映射参数,x方向和y方向,通过对x和y坐标的操作,可以形成波浪大小。
调用remap函数,即可生成结果图像。