OpenCV - C++实战(04) — 简单的图像运算

目录

第4章  像素的访问与扫描 

4.1 图像相加

(1)合并两张图像

(2)创建滑动条设置合并参数

4.2 其他的运算操作

4.3 分割图像通道

4.4 图像的重映射 

4.5 完整代码

(1)代码1

(2)代码2

(3)代码3


Github代码地址:GitHub - Qinong/OpenCV

第4章  像素的访问与扫描 

        图像就是普通的矩阵,可以进行加、减、乘、除运算,因此可以用多种方式组合图像。OpenCV提供了很多图像算法运算符。 

4.1 图像相加

        两幅图像相加可以用于创建特效因或覆盖图像中的信息。可以使用cv::add函数实现相加功能,但因要考虑图像的加权和,因此使用更精确的 cv::addweighted函数。

void cv::add(InputArray src1,
             InputArray src2,
             OutputArray dst,
             InputArray mask = noArray(),
             int dtype = -1)	
  • src1:输入的第一个图像。
  • src2:输入的第二个图像。
  • dst:输出的数组。
  • mask:掩码
  • dtype:输出阵列的可选深度,默认值-1。
void cv::addWeighted(InputArray src1, 
                     double alpha, 
                     InputArray src2,
                     double beta, 
                     double gamma, 
                     OutputArray dst, 
                     int dtype = -1);
  • src1:输入的第一个需要加权的图像。
  • alpha:第一个数组的权重。
  • src2:输入的第二个需要加权的图像。
  • beta:第二个数组的权重。
  • gamma:加到权重总和上的标量值。
  • dst:输出的数组。
  • dtype:输出阵列的可选深度,默认值-1。

(1)合并两张图像

// 合并图像
cv::Mat image3;
cv::addWeighted(image1,0.7,image2,0.9,0.,image3 );
cv::namedWindow("Image3",0);
cv::imshow("Image3",image3);
    
// 使用运算符重载
image3= 0.7*image1+0.9*image2;
cv::namedWindow("Image4",0);
cv::imshow("Image4",image3);

(2)创建滑动条设置合并参数

cv::namedWindow("test",0);
    int alpha = 0;
    int beta = 0;
    int gamma = 0;
    cv::createTrackbar("alpha","test",&alpha,100);
    cv::createTrackbar("beta","test",&beta,100);
    cv::createTrackbar("gamma","test",&gamma,255);
    for(;;)
    {
        cv::Mat image3;
        cv::addWeighted(image1, alpha/100.0f, image2, beta/100.0f, gamma, image3);
        cv::namedWindow("test",0);
        cv::imshow("test",image3);
        if(cv::waitKey(10)==0)
            break;
    }

 

 

4.2 其他的运算操作

        OpenCV还提供了丰富的矩阵操作的函数。

        算术运算:cv::add,cv::addWeighted, cv::scaleAdd,cv::subtract, cv::absdiff, cv::multiply,cv::divide

        位运算:cv::bitwise_and, cv::bitwise_or,cv::bitwise_xor,cv::bitwise_not,cv::max,cv::min

        其他运算:cv::sqrt,cv::pow,cv::abs,cv::cuberoot,cv::exp,cv::log

        矩阵操作函数的详细解析可参考文章:https://blog.csdn.net/godadream/article/details/81742505

4.3 分割图像通道

        我们有时需要分别处理图像中的不同通道,例如只对图像中的一个通道执行某个操作。可以使用cv::split函数。

        假设我们要把一张雨景因只加到蓝色通道中,可以这样实现:

// 分割图像通道
image2= cv::imread("huang.jpg",0);
// 创建三幅图像的向量
std::vector<cv::Mat> planes;
cv::split(image1,planes);
// 加到蓝色通道上
planes[0]+= image2;
// 将三个单通道图像合并为一个三通道图像
cv::merge(planes,image3);
cv::namedWindow("Image5",0);
cv::imshow("Image5",image3);
cv::waitKey();

 

 

4.4 图像的重映射 

        接下来我们看看如何通过移动像素修改图像的外观。这个过程不会修改像素值,而是把每个像素的位置重新映射到新的位置。这可用来创建图像特效,或者修正因镜片等原因导致的图像扭曲。
        要使用 OpenCV 的remap函数,首先需要定义在重映射处理中使用的映射参数,然后把映射参效应用到输人图像。很明显,定义映射参数的方式将决定产生的效果。这里定义一个装换函数,在图像上创建波浪形效果:

// 重映射图像,创建波浪效果
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++) {
			srcX.at<float>(i,j)= j;
			srcY.at<float>(i,j)= i+8*sin(j/6.0);
			// horizontal flipping
			// srcX.at<float>(i,j)= image.cols-j-1;
			// srcY.at<float>(i,j)= i;
		}
	}

	cv::remap(image,  
		      result, 
			  srcX,   
			  srcY,   
			  cv::INTER_LINEAR);
}

4.5 完整代码

(1)代码1

#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

int main()
{
	cv::Mat image1;
	cv::Mat image2;
	image1= cv::imread("AUdi_A8.jpg");
	image2= cv::imread("huang.jpg");
	if (!image1.data)
		return 0; 
	if (!image2.data)
		return 0; 
	cv::namedWindow("Image1",0);
	cv::imshow("Image1",image1);
	cv::namedWindow("Image2",0);
	cv::imshow("Image2",image2);
    
    // 合并图像
	cv::Mat image3;
	cv::addWeighted(image1,0.7,image2,0.9,0.,image3 );
	cv::namedWindow("Image3",0);
	cv::imshow("Image3",image3);
    
	// 使用运算符重载
	image3= 0.7*image1+0.9*image2;
	cv::namedWindow("Image4",0);
	cv::imshow("Image4",image3);

    // 分割图像通道
	image2= cv::imread("huang.jpg",0);
	std::vector<cv::Mat> planes;
	cv::split(image1,planes);
	planes[0]+= image2;
	cv::merge(planes,image3);
	cv::namedWindow("Image5",0);
	cv::imshow("Image5",image3);
	cv::waitKey();
    
	return 0;
}

(2)代码2

#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

int main()
{
	cv::Mat image1;
	cv::Mat image2;
	image1= cv::imread("AUdi_A8.jpg");
	image2= cv::imread("huang.jpg");
	if (!image1.data)
		return 0; 
	if (!image2.data)
		return 0; 
	
    cv::namedWindow("test",0);
    int alpha = 0;
    int beta = 0;
    int gamma = 0;
    cv::createTrackbar("alpha","test",&alpha,100);
    cv::createTrackbar("beta","test",&beta,100);
    cv::createTrackbar("gamma","test",&gamma,255);
    for(;;)
    {
        cv::Mat image3;
        cv::addWeighted(image1, alpha/100.0f, image2, beta/100.0f, gamma, image3);
        cv::namedWindow("test",0);
        cv::imshow("test",image3);
        if(cv::waitKey(10)==0)
            break;
    }

	return 0;
}

(3)代码3


#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <math.h>

// 重映射图像,创建波浪效果
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++) {
			srcX.at<float>(i,j)= j;
			srcY.at<float>(i,j)= i+8*sin(j/6.0);
			// horizontal flipping
			// srcX.at<float>(i,j)= image.cols-j-1;
			// srcY.at<float>(i,j)= i;
		}
	}

	cv::remap(image,  
		      result, 
			  srcX,   
			  srcY,   
			  cv::INTER_LINEAR);
}

int main()
{
	cv::Mat image= cv::imread("AUdi_A8.jpg");
	cv::namedWindow("Image",0);
	cv::imshow("Image",image);

	cv::Mat result;
	wave(image,result);
	cv::namedWindow("Image1",0);
	cv::imshow("Image1",result);
	cv::waitKey();
	return 0;
}

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

几度春风里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值