#include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp>
using namespace cv; int main() { Mat Valley = imread("/home/ttwang/Valley.jpg"); Mat ValleyLogo = imread("/home/ttwang/ValleyLogo.jpg"); namedWindow("[1] ValleyPic"); imshow("[1] ValleyPic",Valley); namedWindow("[2] ValleyLogo"); imshow("[2] ValleyLogo",ValleyLogo); Mat valleyROI;
/******************实现两个图像混合****************************/
valleyROI = Valley(Rect(800,350,ValleyLogo.cols,ValleyLogo.rows)); addWeighted(valleyROI,0.5,ValleyLogo,0.3,0.,valleyROI); namedWindow("valley+logo"); imshow("valley+logo",Valley); // imwrite("",Valley);
waitKey(0); return 0; }
二、创建滑动条:createTrackbar()函数 (利用滑动条实现两幅图的Alpha混合)
1 #include <QCoreApplication> //本人所用的IDE是QT,,终端编译时不需要该声明
2 #include <opencv2/core/core.hpp>
3 #include <opencv2/highgui/highgui.hpp>
4 #include <opencv2/imgproc/imgproc.hpp>
5 using namespace cv; 6
7 #define WINDOW_NAME "[Alpha]" //窗口名的宏定义
8
9 const int g_nMaxAlphaValue = 100; 10 int g_nAlphaValueSlider; 11 double g_dAlphaValue; 12 double g_dBetaValue; 13
14 Mat g_srcImage1; 15 Mat g_srcImage2; 16 Mat g_dstImage; 17 /**********响应滑动条的回调函数*************/
18 void on_Trackbar( int ,void*) 19 { 20 g_dAlphaValue = (double) g_nAlphaValueSlider/g_nMaxAlphaValue; 21 g_dBetaValue = (1.0 - g_dAlphaValue); 22 //根据Alpha beta的值进行线性混合
addWeighted(g_srcImage1,g_dAlphaValue,g_srcImage2,g_dBetaValue,0.0,g_dstImage); 23 imshow(WINDOW_NAME,g_dstImage); 24 } 25
26 int main() 27 { 28 g_srcImage1 = imread("/home/ttwang/11.jpg"); //两幅图的尺寸要相同,否则出现如下图错误 29 g_srcImage2 = imread("/home/ttwang/12.jpg"); 30
31 g_nAlphaValueSlider = 70; 32 namedWindow(WINDOW_NAME,1); 33
34 char TrackbarName[50]; 35 sprintf(TrackbarName,"透明值 %d", g_nMaxAlphaValue); 36 createTrackbar(TrackbarName,WINDOW_NAME, &g_nAlphaValueSlider, g_nMaxAlphaValue,on_Trackbar); 37 on_Trackbar(g_nAlphaValueSlider,0); 38
39 waitKey(0); 40 return 0; 41
42 }
由于程序不是直接粘贴过来的,按该程序进行编译时候,总出现错误,可以参考下面的链接 感谢分享
三、鼠标操作:SetMouseCallback()函数
#include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv; #define WINDOW_NAME "[Program window]" //为窗口标题定义的宏 /******************全局函数的声明********************/ void on_MouseHandle(int event,int x, int y, int flags, void* param); void DrawRectangle(cv::Mat& img, cv::Rect box); void ShowHelpText(); /******************全局变量声明*********************/ Rect g_rectangle; bool g_bDrawingBox = false;//是否绘制 RNG g_rng(12345); int main() { g_rectangle = Rect(-1,-1,0,0); Mat srcImage(600,800,CV_8UC3),tempImage; srcImage.copyTo(tempImage); g_rectangle = Rect(-1,-1,0,0); srcImage = Scalar::all(0); //设置鼠标操作回调函数 namedWindow(WINDOW_NAME); setMouseCallback(WINDOW_NAME,on_MouseHandle,(void*)&srcImage); while(1) { srcImage.copyTo(tempImage); //复制源图到临时变量 if(g_bDrawingBox) DrawRectangle(tempImage,g_rectangle);//当绘制标识符为真,进行绘制 imshow(WINDOW_NAME,tempImage); if(waitKey(10) == 27) break; //按下Esc,程序退出 } return 0; } /*********鼠标回调函数,根据不同的鼠标事件进行不同的操作*******************/ void on_MouseHandle(int event, int x, int y, int flags, void *param) { Mat& image = *(cv::Mat*) param; switch (event) { //鼠标移动消息 case EVENT_MOUSEMOVE: { if(g_bDrawingBox)//如果是否进行绘制额标识符为真,则记录下长和宽到RECT型变量中 { g_rectangle.width = x - g_rectangle.x; g_rectangle.height = y- g_rectangle.y; } } break; //左键按下消息 case EVENT_LBUTTONDOWN: { g_bDrawingBox = true; g_rectangle = Rect(x,y,0,0);//记录起始点 } break; //左键抬起消息 case EVENT_LBUTTONUP: { g_bDrawingBox = false; //置标识符为false //对宽和高小于0的进行处理 if(g_rectangle.width < 0) { g_rectangle.x += g_rectangle.width; g_rectangle.width *= -1; } if(g_rectangle.height < 0) { g_rectangle.y += g_rectangle.height; g_rectangle.height *= -1; } //调用回调函数进行绘制 DrawRectangle( image, g_rectangle); } break; } } /********************自定义的矩形绘制函数DrawRectangle() ********************/ void DrawRectangle(cv::Mat& img, cv::Rect box) { rectangle(img,box.tl(),box.br(),Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255))); }
四章、OpenCV数据结构与基本绘图
1. Mat M(2,2,CV_8UC3,Scalar(0,0,255)); //使用Mat()构造函数创建Mat对象
两行两列、CV_8UC3: CV_[位数][带符号与否]C[通道数] Scalar是个short类型的向量,可以使用指定的值来初始化矩阵
2.Mat M; M.create(4,4,CV_8UC3); //使用create()函数创建Mat对象,,此方法不能为矩阵设初值
3.颜色的表示类:Scalar()是具有四个元素的数组,,第四个用不到,则不写 格式如下:
Scalar(a, b, c)定义的RGB颜色值:红色分量c 绿色分量b 蓝色分量 a
4.尺寸的表示类: Size() 常用格式: Size(5,5)表示构造出的Size高度和宽度都为5
5.矩形的表示类: Rect类的成员有x,y,width,height,分别为左上角的坐标和矩形的宽、高
格式: Rect rect(0,0,200,400)
6.颜色空间转换:cvtColor()函数 格式:cvtColor(InputArraysrc, OutputArray dst, int code, int dstCn=0)
第一个参数:输入图像;
第二个参数:输出图像;
第三个参数:颜色空间转换的标识符; (详见:P98)
第四个参数:目标图像的通道数,若为0,则表示其取源图像的通道数。
7.基本图型的绘制涉及的函数: (通过例程学习 P100)
绘制直线的line函数
绘制椭圆的ellipse函数
绘制矩形的rectangle函数
绘制圆的circle函数
绘制填充的多边形的fillPloy函数
第五章 core组件进阶
1.计时函数: getTickCount()和getTickFrequency()
getTickCount()函数返回CPU自某个事件以来走过的时钟周期数
getTickFrequency()函数返回CPU一秒钟走过的周期数
显然: 二者结合可以实现对某种图像处理方法的计时
double time0 = static_cast<double>(getTickCount()); //记录起始时间
time0= ((double)getTickCount() - time0)/getTickFrequency();////计算运行时间并输出
cout<<"\t此方法运行时间为:"<<time0<<"秒"<<endl; //输出运行时间
2.访问图像中像素的几种方法 (简单介绍,具体P110)
需要先明白以下知识:
(1) Mat类的公有成员变量cols和rows给出了图像的宽和高
image.cols image.rows
(2) Mat类的成员函数channels()用于返回图像的通道数;
灰度图像通道数1,彩色图像通道数为3 image.channels()
(4) 每一行的像素个数= image.cols*image.channels()
a.直接遍历,使用Mat里的成员函数data
/*********只用于访问连续空间********/ Mat mat (3000,4000,CV_8UC3) int es = mat.eleSize(); //定义步长,因为定义为3通道的,实质该值为3 int size = mat.rows*mat.cols*es; for(int i = 0; i < size; i += es) { mat.data[i] = 255; // B通道 mat.data[i+1] = 0; // G通道 mat.data[i+2] = 0; // R通道 }
b.直接访问不连续空间
for (int row = 0; row < mat.rows; row++) { for (int col = 0; col < mat.cols; col++) { (&mat.data[row*mat.step])[col*es] = 0; (&mat.data[row*mat.step])[col*es + 1] = 0; (&mat.data[row*mat.step])[col*es + 2] = 255; } }
c.通过opencv ptr模板函数遍历
1 for (int row = 0; row < mat.rows; row++) 2 { 3 for (int col = 0; col < mat.cols; col++) 4 { 5 Vec3b *c = mat.ptr<Vec3b>(row,col); 6 c->val[0] = 0;
8 c->val[1] = 255;
10 c->val[2] = 0; } 13 }
c.通过at遍历
1 for (int row = 0; row < mat.rows; row++) 2 { 3 for (int col = 0; col < mat.cols; col++) 4 { 5 Vec3b &m = mat.at<Vec3b>(row, col); 6 m[0] = 0; 7 m[1] = 0; 8 m[2] = 255; 9 } 10 }
d.通过迭代器遍历
1 auto it = mat.begin<Vec3b>(); //自动类型匹配auto
2 auto it_end = mat.end<Vec3b>(); 3 for (; it != it_end; it++) 4 { 5 (*it).val[0] = 0; 6 (*it).val[1] = 0; 7 (*it).val[2] = 255; 8 }
3.感兴趣区域ROI /******表示方法一 Rect矩形区域*******/ Mat imageROI imageROI = image(Rect(500,250,logo.cols,logo.rows)); //image为已经载入好的图片
/******表示方法二 Range指定感兴趣的行和列********/
imageROI = image(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols)); //image为已经载入好的图片
4.利用addWeighted可实现图像线性混合 数学公式: dst = src1[I] * alpha + src2[I]*beta + gamma (P117)
5.分离颜色通道、多通道图像混合 通道分离:split()函数,将一个3通道图像转换成3个单通道 通道合并:merge()函数 ###例程:(课本P127,以多通道混合-蓝色分量部分为例) ###平台:QT5.7.1+OpenCV3.2.0 ###时间:2017年12月11日 /********建立QT控制台程序*********/ #include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream>
using namespace std; using namespace cv; //全局函数声明
bool MultiChannelBlending(); int main() { if(MultiChannelBlending()) { cout << endl << "\n运行成功,得到目标图像" << endl; } waitKey(0); return 0; } /*********多通道混合的实现函数*********/
bool MultiChannelBlending() { Mat srcImage; Mat logoImage; vector<Mat> channels; /********** 蓝色分量 *************/ Mat imageBlueChannel; logoImage = imread("/home/ttwang/Valley_logo.jpg",0);//一定要读入会灰度图像,不然addWeighted()会因为类型不匹配而报错
srcImage = imread("/home/ttwang/Valley.jpg"); split(srcImage,channels); //将一个3通道图像转换成3个单通道
imageBlueChannel = channels.at(0); //将原图的蓝色通道引用返回给imageBlueChannel
addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,logoImage,0.5,0.,imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows))); merge(channels,srcImage);//将三个单通道重新合并成一个三通道
namedWindow("src+LogoBlue"); imshow("src+LogoBlue",srcImage); /*******绿色分量 ******/ Mat imageGreenChannel; logoImage = imread("/home/ttwang/Valley_logo.jpg",0); srcImage = imread("/home/ttwang/Valley.jpg"); split(srcImage,channels); //将一个3通道图像转换成3个单通道
imageGreenChannel = channels.at(1); addWeighted(imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,logoImage,0.5,0.0,imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows))); merge(channels,srcImage);//将三个单通道重新合并成一个三通道
namedWindow("src+LogoGreen"); imshow("src+LogoGreen",srcImage); /*******红色分量 ******/ Mat imageRedChannel; logoImage = imread("/home/ttwang/Valley_logo.jpg",0); srcImage = imread("/home/ttwang/Valley.jpg"); split(srcImage,channels); //将一个3通道图像转换成3个单通道
imageRedChannel = channels.at(2); addWeighted(imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,logoImage,0.5,0.0,imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows))); merge(channels,srcImage);//将三个单通道重新合并成一个三通道
namedWindow("src+LogoRed"); imshow("src+LogoRed",srcImage); return true; }
6.图像对比度、亮度调整 公式: g(i,j)=a*f(i,j)+b; (opencv控制图像对比度和亮度的理论公式) 参数a(a>0)通常被成为增益,控制图像的对比度 参数b称为偏置,控制图像的亮度 访问图片中的像素:(使用三个for循环,语法:image.at<Vec3b>(y,x)[c]) 其中,y是像素所在的行,x是像素所在的列,c是B、G、 R(对应0、1、2)
7.离散傅里叶变换(详细参照课本P135) 参考资料及函数说明,参照下面的链接: opencv2教程之离散型傅里叶变换