目录
第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
矩阵操作函数的详细解析可参考文章:
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;
}