1、加载图片
//__________加载图片______________ // 注意imread的第二个参数intflag默认是1,即原色彩,但是他可以指定多种色彩,比如0即灰色,一个彩色的图载入进去就会变成灰色 // CV_LOAD_IMAGE_UNCHANGED = -1,// 此值已被废弃 // CV_LOAD_IMAGE_GRAYSCALE = 0,// 灰度(灰色、黑白) // CV_LOAD_IMAGE_COLOR = 1,// 彩色 // CV_LOAD_IMAGE_ANYDEPTH,// 深度返回? // 一个彩色可以变成灰色,一个灰色却不能变为彩色 Mat srcImage = imread("1_5_12.jpg",0);// 图片文件放在debug/release文件夹同级 namedWindow("【原始图】"); imshow("【原始图】",srcImage); waitKey(0);
2、图像腐蚀
//_________图像腐蚀_______________ Mat srcImage = imread("1_5_2.jpg");// 加载图片 namedWindow("【原图】腐蚀操作");// 窗口 imshow("【原图】腐蚀操作",srcImage);// 显示原图 Mat element = getStructuringElement(MORPH_RECT,Size(15,15));// 进行腐蚀操作 Mat dstImage; erode(srcImage,dstImage,element); namedWindow("【效果图】腐蚀操作"); imshow("【效果图】腐蚀操作",dstImage);// 显示效果图 waitKey(0);
3、图像模糊
//______________图像模糊____________ Mat srcImage = imread("1_5_3.jpg"); namedWindow("均值滤波【原图】"); imshow("均值滤波【原图】",srcImage); Mat dstImage; blur(srcImage,dstImage,Size(7,7)); namedWindow("均值滤波【效果图】"); imshow("均值滤波【效果图】",dstImage); waitKey(0);
4、边缘检测
//_____________边缘检测____________ Mat srcImage = imread("1_5_4.jpg"); namedWindow("【原始图】Canny边缘检测"); imshow("【原始图】Canny边缘检测",srcImage); Mat dstImage,edge,grayImage; dstImage.create(srcImage.size(),srcImage.type());// 创建和src同样类型和大小的矩阵 cvtColor(srcImage,grayImage,CV_BGR2GRAY);// opencv3:COLOR_BGR2GRAY;opencv2:CV_BGR2GRAY blur(grayImage,edge,Size(3,3));// 先使用3*3内核来降噪 Canny(edge,edge,3,9,3);// 运行Canny算子 namedWindow("【效果图】Canny边缘检测"); imshow("【效果图】Canny边缘检测",edge); waitKey(0);
5、读取视频
//_____________读取视频___________________ VideoCapture capture("1_6_1.avi");// 读取视频 namedWindow("读取视频"); while(1) { Mat frame; capture>>frame;// 读取当前帧 imshow("读取视频",frame);// 显示当前帧 waitKey(30); }
6、调用摄像头
//______________调用摄像头_____________ VideoCapture capture(0); namedWindow("读取视频"); while(1) { Mat frame; capture>>frame; imshow("读取视频",frame); waitKey(30); }
7、摄像头边缘检测
//______________摄像头边缘检测_____________ VideoCapture capture(0); Mat edges; namedWindow("被canny后的视频"); while(1) { Mat frame; capture>>frame; cvtColor(frame,edges,COLOR_BGR2GRAY); blur(edges,edges,Size(7,7)); Canny(edges,edges,0,30,3); imshow("被canny后的视频",edges); waitKey(30); }
8、用imwrite输出png
//_____________用imwrite输出png___________________ Mat mat(480,640,CV_8UC4);// 创建带alpha通道的Mat createAlphaMat(mat); vector<int> compression_params; compression_params.push_back(IMWRITE_PNG_COMPRESSION); compression_params.push_back(9); try { namedWindow("透明Alpha值图"); imwrite("透明Alpha值图",mat,compression_params);// imwrite测试失败,不知原因 namedWindow("生成的PNG图"); imshow("生成的PNG图",mat); fprintf(stdout,"PNG图片文件的alpha数据保存完毕~\n可以在工程目录下查看由imwrite函数生成的图片\n"); waitKey(0); } catch(runtime_error & ex) { fprintf(stderr,"图像转换成PNG格式发生错误:%s\n",ex.what()); return 1; }
void createAlphaMat(Mat & mat) { for(int i = 0;i<mat.rows;++i) { for(int j = 0;j<mat.cols;++j) { Vec4b & rgba = mat.at<Vec4b>(i,j); rgba[0] = UCHAR_MAX; rgba[1] = saturate_cast<uchar>((float(mat.cols-j))/((float)mat.rows)*UCHAR_MAX); rgba[2] = saturate_cast<uchar>((float(mat.rows-i))/((float)mat.rows)*UCHAR_MAX); rgba[3] = saturate_cast<uchar>(0.5*(rgba[1]+rgba[2])); } } }
9、综合示例:图像载入、显示和混合
#include "study3_1_9.h" #include <QDebug> #include <opencv2/opencv.hpp> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <fstream> #include <iostream> #include <string> #include <stdlib.h> #include <stdio.h> #include <iomanip> #include <stdio.h> using namespace cv; using namespace std; Study3_1_9::Study3_1_9() { //___________载入和显示____________ Mat girl = imread("girl.jpg"); namedWindow("【1】动漫图"); imshow("【1】动漫图",girl); //___________初级图像混合__________ Mat image = imread("dota.jpg"); Mat logo = imread("dota_logo.jpg"); qDebug()<<"image-cols:"<<image.cols;//列,纵向:494 qDebug()<<"image-rows:"<<image.rows;//行,横向:700 qDebug()<<"logo-cols:"<<logo.cols; qDebug()<<"logo-rows:"<<logo.rows; namedWindow("【2】原画图"); imshow("【2】原画图",image); namedWindow("【3】logo图"); imshow("【3】logo图",logo); // ROI感兴趣区域 Mat imageROI; imageROI = image(Rect(800,350,logo.cols,logo.rows));// 这是切割出来的区域 // 资源1,alpha,资源2,alpha,偏差,输出 addWeighted(imageROI,0.1,logo,0.1,0,imageROI);// 图片融合,就是刚才切出来的图和要贴上去的图做一个融合 // 注意修改了imageROI其实也修改了image namedWindow("【4】原画+logo图"); imshow("【4】原画+logo图",image); imwrite("由imwrite生成的图片.jpg",image); waitKey(0); }
<1>指定ROI(感兴趣区域)
Mat image("xxx.jpg"); Mat imageROI = image(Rect(x,y,width,height));//在image内指定一个矩形,指定矩形的起点以及宽和高 Mat imageROI = image(Range(x1,xn),Range(y1,yn));// 或者指定一个x坐标的起止点(序列),指定一个y坐标的起止点(序列) // 需要注意的是,不管是哪种方法,范围内所有点必须在image范围之内
<2>图片融合
// 资源1,alpha,资源2,alpha,偏差,输出 addWeighted(imageROI,0.1,logo,0.1,0,imageROI);// 图片融合,就是刚才切出来的图和要贴上去的图做一个融合 // 注意修改了imageROI其实也修改了image
10、用createTrackbar创建滑动条
注意:载入的两个图片必须一样大小。
下面的示例来自于:http://monkeycoding.com/?p=652,感谢!
#include <cstdio> #include <opencv2/opencv.hpp> using namespace cv; int sliderValue; Mat src1, src2; void on_trackbar(int, void*){ double alpha = (double) sliderValue/100.0 ; double beta = ( 1.0 - alpha ); Mat dst; addWeighted( src1, alpha, src2, beta, 0.0, dst); imshow("trackbar demo", dst); } int main(){ src1 = imread("beach.jpg",CV_LOAD_IMAGE_UNCHANGED); src2 = imread("cat.jpg",CV_LOAD_IMAGE_UNCHANGED); sliderValue = 0; int sliderMaxValue = 100; namedWindow("trackbar demo", 0); createTrackbar("Ratio", "trackbar demo", &sliderValue, sliderMaxValue, on_trackbar); on_trackbar(sliderValue, 0 ); waitKey(0); return 0; }
11、鼠标交互setMouseCallback
注意:窗口不要用宏定义+中文,不知道为什么就是出问题,改了就好了
#include <QDebug> #include <opencv2/opencv.hpp> using namespace cv; // 全局函数声明 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(123456); int main(int argc,char ** argv) { // 鼠标交互setMouseCallback // 准备参数 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("testw"); setMouseCallback("testw",on_MouseHandle,(void*)&srcImage); // 程序主循环,当进行绘制的标识符为真时,进行绘制 while(1) { srcImage.copyTo(tempImage);// 复制源图到临时变量 if(g_bDrawingBox) DrawRectangle(tempImage,g_rectangle);// 当进行绘制的标识符为真时,则进行绘制 imshow("testw",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;// 一个Mat类型的指针执行指针标识,就变成引用 switch(event) { case EVENT_MOUSEMOVE: { if(g_bDrawingBox) { 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; if(g_rectangle.width<0) { g_rectangle.x+=g_rectangle.width; g_rectangle.width *= -1;//乘以-1 } if(g_rectangle.height<0) { g_rectangle.y+=g_rectangle.height; g_rectangle.height *= -1; } DrawRectangle(image,g_rectangle); } break; } } void DrawRectangle(cv::Mat &img, Rect box) { rectangle(img,box.tl(),box.br(),Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255)));// 随机颜色 }
12、Mat的深复制和浅复制
Mat A,C;// 仅创建信息头部分 A = imread("1.jpg",CV_LOAD_IMAAGE_COLOR);// 这里为矩阵开辟内存 Mat B(A);// 使用拷贝构造函数(指针指向同一个矩阵) C = A;// 这里ABC都是指向同一个内存 // 以下两个方法都是共享矩阵(内存),而且指定了范围 Mat D(A,Rect(10,10,100,100));// 使用矩形界定 Mat E = A(Range:all(),Range(1,3));// 使用行列界定 // 使用clone和copyTo则完全复制,指向不同的内存 Mat F = A.clone(); Mat G; A.copyTo(G);
13、显式创建Mat的方法
(1)使用Mat()构造函数
Mat M(2,2,CV_8UC3,Scalar(0,0,255)); // 2,2即2行2列 // CV_8UC3公式:CV_[位数][带符号否][类型前缀][通道数] // 8UC3即:使用8位的unsigned char型,每个像素由3个元素组成3通道 // Scalar是个short型的向量,可以用他表示一个颜色(即3通道) // 输出: cout<<"M="<<endl<<" "<<M<<endl<<endl;
输出:
M= [ 0, 0, 255, 0, 0, 255; 0, 0, 255, 0, 0, 255]
由此可见,Mat的矩阵就是:
[x,y,z,x,y,z,x,y,z; x,y,z,x,y,z,x,y,z]
这样连起来,换行用分号。
(2)用create创建
Mat M; M.create(4,4,CV_8UC2); cout<<"M="<<endl<<" "<<M<<endl<<endl;
[ 64, 210, 119, 98, 80, 210, 119, 98; 96, 210, 119, 98, 224, 207, 119, 98; 240, 207, 119, 98, 0, 208, 119, 98; 16, 208, 119, 98, 32, 208, 119, 98]
14、python风格的输出(每个像素会有中括号)
Mat r = Mat(10,3,CV_8UC3); randu(r,Scalar::all(0),Scalar::all(255)); cout<<"r(PythonStyle)="<<format(r,Formatter::FMT_PYTHON)<<endl<<endl;
r(PythonStyle)=[[[ 91, 2, 79], [179, 52, 205], [236, 8, 181]], [[239, 26, 248], [207, 218, 45], [183, 158, 101]], [[102, 18, 118], [ 68, 210, 139], [198, 207, 211]], [[181, 162, 197], [191, 196, 40], [ 7, 243, 230]], [[ 45, 6, 48], [173, 242, 125], [175, 90, 63]], [[ 90, 22, 112], [221, 167, 224], [113, 208, 123]], [[214, 35, 229], [ 6, 143, 138], [ 98, 81, 118]], [[187, 167, 140], [218, 178, 23], [ 43, 133, 154]], [[150, 76, 101], [ 8, 38, 238], [ 84, 47, 7]], [[117, 246, 163], [237, 69, 129], [ 60, 101, 41]]]
15、颜色的直观感受
颜色与RGB数值,数值越小,颜色越深;数值越大颜色越浅。
三个数值线性变化则颜色会呈明暗变化,但是色相基本不变。
16、颜色空间缩减
// ______________颜色空间缩减原理________________ // 注意:此处颜色空间缩减,并非能减少图片在内存中占用空间的意思。 // 此处的意思是,如果我们需要把图片的所有点的数据取出来进行操作处理,如果我们用此缩减的方法,那么存放这些用来处理的数据可以更精简 // 此处非图片压缩之意,而是缩减我们的处理数据 // 颜色每个通道有0~255共256个数,由于数值相近则颜色非常相近,我们用近似取法,即: // 0~9的数取0 // 10~19的数取10 // ... // 这样做其实这个颜色偏差不大,但是数据量就少了很多 // 可以这样理解:颜色有256种,256种之间区别很精细。我们缩减到26种,就是颜色没有分的那么精细了,但是在某些情况下还是可用。 // 只要这样:颜色数值/10*10,就可以了比如136,136/10即13,余数6自动被丢弃,再乘以10,则变成130. // 即我们只需要:0,10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200,210,220,230,240,250. // 我们可以做一个这样的对应表:256个颜色给他分别对应到26个颜色里面,这样就不需要再计算了。 int divideWith = 10; uchar table[256]; for(int i = 0;i<256;i++) table[i] = divideWith*(i/divideWith); // 注意这个table: // table[0] = 0; // table[1] = 0; // table[2] = 0; // table[3] = 0; // ... // table[10] = 10; // table[11] = 10; // table[12] = 10; // ... // table[20] = 20; // table[21] = 20; // ... // ... // table[250] = 250; // table[251] = 250; // table[252] = 250; // ... // 可见这个talbe已经天然的完成了一个映射关系,他的下标跟值的映射 // p[j] = table[p[j]];// 颜色值变成table的下标,取对应下标的值 // 用LUT函数 Mat lookUpTable(1,256,CV_8U); uchar * p = lookUpTable.data; for(int i = 0;i<256;i++) p[i] = table[i];// 把数据装到p,改变了p其实也改变了lookUpTable // 然后就可以用LUT函数了, LUT(I输入图片Mat,lookUpTable,J输出图片Mat);// 直接全图全转了
17、操作图片像素的三种方法示例
#include <QDebug> #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #pragma execution_character_set("utf-8") using namespace cv; using namespace std; void colorReduceByPointer(Mat & inputImage,Mat & outputImage,int div); void colorReduceByIterator(Mat & inputImage,Mat & outputImage,int div); void colorReduceByAddr(Mat & inputImage,Mat & outputImage,int div); int main(int argc,char ** argv) { Mat srcImage = imread("dota.jpg"); namedWindow("原始图像"); imshow("原始图像",srcImage); Mat dstImage; dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());// 大小类型要相同 double time0 = static_cast<double>(getTickCount()); // colorReduce(srcImage,dstImage,32); // colorReduceByIterator(srcImage,dstImage,32); colorReduceByAddr(srcImage,dstImage,32); time0 = ((double)getTickCount()-time0)/getTickFrequency(); cout<<"this method run time is:"<<time0<<"s"<<endl;//输出运行时间 namedWindow("效果图"); imshow("效果图",dstImage); waitKey(0); return 0; } // ___________________用指针操作像素_______________________ void colorReduceByPointer(Mat &inputImage, Mat &outputImage, int div) { outputImage = inputImage.clone(); int rowNumber = outputImage.rows; int colNumber = outputImage.cols*outputImage.channels(); for(int i = 0;i<rowNumber;i++) { // 指针+下标可以取值 uchar * data = outputImage.ptr<uchar>(i);//获取第i行首地址 if(i == 1) { cout<<"data[1]="<<int(data)<<"[16]"<<hex<<int(data)<<"[val]="<<int(data[0])<<endl;// data[1]=116131067[16]6ec04fb 这应该是一个内存地址,[val]=56 } for(int j = 0;j<colNumber;j++) { if(i==1&&j==0) { cout<<"data[1][1]="<<dec<<int(data[j])<<endl;// 10进制就变成86,10进制86对应16进制56 } // 开始处理每个像素除以32再乘以32再加16 data[j] = data[j]/div*div+div/2; } } } //____________________迭代器___________________ void colorReduceByIterator(Mat &inputImage, Mat &outputImage, int div) { outputImage = inputImage.clone(); Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>(); Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>(); for(;it!=itend;++it) { (*it)[0] = (*it)[0]/div*div+div/2; (*it)[1] = (*it)[1]/div*div+div/2; (*it)[2] = (*it)[2]/div*div+div/2; } } //____________________动态地址计算_____________________ void colorReduceByAddr(Mat &inputImage, Mat &outputImage, int div) { outputImage = inputImage.clone(); int rowNumber = outputImage.rows; int colNumber = outputImage.cols; for(int i = 0;i<rowNumber;i++) { for(int j = 0;j<colNumber;j++) { outputImage.at<Vec3b>(i,j)[0] = outputImage.at<Vec3b>(i,j)[0]/div*div+div/2; outputImage.at<Vec3b>(i,j)[1] = outputImage.at<Vec3b>(i,j)[1]/div*div+div/2; outputImage.at<Vec3b>(i,j)[2] = outputImage.at<Vec3b>(i,j)[2]/div*div+div/2; } } }
18、利用感兴趣区域ROI实现图像叠加
Mat srcImage1 = imread("dota_pa.jpg"); Mat logoImage = imread("dota_logo.jpg"); if(!srcImage1.data) { printf("read image1 error!"); return 0; } if(!logoImage.data) { printf("read image2 error!"); return 0; } Mat imageROI = srcImage1(Rect(200,50,logoImage.cols,logoImage.rows)); Mat mask = imread("dota_logo.jpg",1);// 加载掩膜,书上说必须是灰度图,经测试此参数任意值都是可以的,缺省也可以 logoImage.copyTo(imageROI);// 书上写:logoImage.copyTo(imageROI,mask);经测试可以不要mask namedWindow("window1"); imshow("window1",srcImage1);
19、线性叠加:addWeight
double alphaValue = 0.2; double betaValue; Mat srcImage2,srcImage3,dstImage; srcImage2 = imread("mogu.jpg"); srcImage3 = imread("rain.jpg"); if(!srcImage2.data) { printf("load image2 error!"); return 0; } if(!srcImage3.data) { printf("load image3 error!"); return 0; } betaValue = (1.0 - alphaValue); addWeighted(srcImage2,alphaValue,srcImage3,betaValue,0.0,dstImage);// 两个图片叠加并配置透明比重 namedWindow("原图",1); imshow("原图",srcImage2); namedWindow("效果图",1); imshow("效果图",dstImage);
20、线性混合综合示例:
#include <QDebug> #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #pragma execution_character_set("utf-8") using namespace cv; using namespace std; bool ROI_AddImage(); bool LinearBlending(); bool ROI_LinearBlending(); int main(int argc,char ** argv) { system("color 5E"); if(ROI_AddImage()&&LinearBlending()&&ROI_LinearBlending()) { cout<<endl<<"ok!"; } waitKey(0); return 0; } bool ROI_AddImage() { Mat srcImage1 = imread("dota_pa.jpg"); Mat logoImage = imread("dota_logo.jpg"); if(!srcImage1.data) { printf("read error!"); return false; } if(!logoImage.data) { printf("read error!"); return false; } Mat imageROI = srcImage1(Rect(200,250,logoImage.cols,logoImage.rows)); Mat mask = imread("dota_logo.jpg",0); logoImage.copyTo(imageROI,mask); namedWindow("ROI叠加"); imshow("ROI叠加",srcImage1); return true; } bool LinearBlending() { double alphaValue = 0.5; double betaValue; Mat srcImage2,srcImage3,dstImage; srcImage2 = imread("mogu.jpg"); srcImage3 = imread("rain.jpg"); if(!srcImage2.data) { printf("read error!"); return false; } if(!srcImage3.data) { printf("read error!"); return false; } betaValue = (1.0-alphaValue); addWeighted(srcImage2,alphaValue,srcImage3,betaValue,0.0,dstImage); namedWindow("线性混合原图",1); imshow("线性混合原图",srcImage2); namedWindow("线性混合效果图"); imshow("线性混合效果图",dstImage); return true; } bool ROI_LinearBlending() { Mat srcImage4 = imread("dota_pa.jpg"); Mat logoImage = imread("dota_logo.jpg"); if(!srcImage4.data) { printf("read error"); return false; } if(!logoImage.data) { printf("read error"); return false; } Mat imageROI; imageROI = srcImage4(Rect(200,250,logoImage.cols,logoImage.rows)); imageROI = srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols)); addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI); namedWindow("区域线性混合"); imshow("区域线性混合",srcImage4); return true; }
21、通道分离、合并
//--------------------------------------【程序说明】------------------------------------------- // 程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序26 // 程序描述:分离颜色通道&多通道图像混合 // 开发测试所用IDE版本:Visual Studio 2010 // 开发测试所用OpenCV版本: 3.0 beta // 2014年11月 Created by @浅墨_毛星云 // 2014年12月 Revised by @浅墨_毛星云 //------------------------------------------------------------------------------------------------ //-----------------------------------【头文件包含部分】--------------------------------------- // 描述:包含程序所依赖的头文件 //------------------------------------------------------------------------------------------------ #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> //-----------------------------------【命名空间声明部分】--------------------------------------- // 描述:包含程序所使用的命名空间 //------------------------------------------------------------------------------------------------- using namespace cv; using namespace std; //-----------------------------------【全局函数声明部分】-------------------------------------- // 描述:全局函数声明 //----------------------------------------------------------------------------------------------- bool MultiChannelBlending(); void ShowHelpText(); //-----------------------------------【main( )函数】------------------------------------------ // 描述:控制台应用程序的入口函数,我们的程序从这里开始 //----------------------------------------------------------------------------------------------- int main( ) { system("color 9F"); ShowHelpText( ); if(MultiChannelBlending( )) { cout<<endl<<"\n运行成功,得出了需要的图像~! "; } waitKey(0); return 0; } //-----------------------------------【ShowHelpText( )函数】---------------------------------- // 描述:输出一些帮助信息 //---------------------------------------------------------------------------------------------- void ShowHelpText() { //输出欢迎信息和OpenCV版本 printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n"); printf("\n\n\t\t\t此为本书OpenCV3版的第26个配套示例程序\n"); printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION ); printf("\n\n ----------------------------------------------------------------------------\n"); } //-----------------------------【MultiChannelBlending( )函数】-------------------------------- // 描述:多通道混合的实现函数 //----------------------------------------------------------------------------------------------- bool MultiChannelBlending() { //【0】定义相关变量 Mat srcImage; Mat logoImage; vector<Mat> channels; Mat imageBlueChannel; //=================【蓝色通道部分】================= // 描述:多通道混合-蓝色分量部分 //============================================ // 【1】读入图片 logoImage= imread("dota_logo.jpg",0); srcImage= imread("dota_jugg.jpg"); if( !logoImage.data ) { printf("Oh,no,读取logoImage错误~! \n"); return false; } if( !srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; } //【2】把一个3通道图像转换成3个单通道图像 split(srcImage,channels);//分离色彩通道 //【3】将原图的蓝色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变 imageBlueChannel= channels.at(0); //【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中 addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0, logoImage,0.5,0,imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows))); //【5】将三个单通道重新合并成一个三通道 merge(channels,srcImage); //【6】显示效果图 namedWindow(" <1>游戏原画+logo蓝色通道"); imshow(" <1>游戏原画+logo蓝色通道",srcImage); //=================【绿色通道部分】================= // 描述:多通道混合-绿色分量部分 //============================================ //【0】定义相关变量 Mat imageGreenChannel; //【1】重新读入图片 logoImage= imread("dota_logo.jpg",0); srcImage= imread("dota_jugg.jpg"); if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; } if( !srcImage.data ) { printf("读取srcImage错误~! \n"); return false; } //【2】将一个三通道图像转换成三个单通道图像 split(srcImage,channels);//分离色彩通道 //【3】将原图的绿色通道的引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变 imageGreenChannel= channels.at(1); //【4】将原图的绿色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageGreenChannel中 addWeighted(imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0, logoImage,0.5,0.,imageGreenChannel(Rect(500,250,logoImage.cols,logoImage.rows))); //【5】将三个独立的单通道重新合并成一个三通道 merge(channels,srcImage); //【6】显示效果图 namedWindow("<2>游戏原画+logo绿色通道"); imshow("<2>游戏原画+logo绿色通道",srcImage); //=================【红色通道部分】================= // 描述:多通道混合-红色分量部分 //============================================ //【0】定义相关变量 Mat imageRedChannel; //【1】重新读入图片 logoImage= imread("dota_logo.jpg",0); srcImage= imread("dota_jugg.jpg"); if( !logoImage.data ) { printf("Oh,no,读取logoImage错误~! \n"); return false; } if( !srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; } //【2】将一个三通道图像转换成三个单通道图像 split(srcImage,channels);//分离色彩通道 //【3】将原图的红色通道引用返回给imageBlueChannel,注意是引用,相当于两者等价,修改其中一个另一个跟着变 imageRedChannel= channels.at(2); //【4】将原图的红色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageRedChannel中 addWeighted(imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0, logoImage,0.5,0.,imageRedChannel(Rect(500,250,logoImage.cols,logoImage.rows))); //【5】将三个独立的单通道重新合并成一个三通道 merge(channels,srcImage); //【6】显示效果图 namedWindow("<3>游戏原画+logo红色通道 "); imshow("<3>游戏原画+logo红色通道 ",srcImage); return true; }