第三章 学习OpenCV——初探OpenCV
来源:互联网 发布:北京邮电大学软件学院 编辑:程序博客网 时间:2024/05/16 05:27
第三章 学习OpenCV——初探OpenCV
例3-1 使用cvSetImageROI来增加某范围的像素
调用cvSetImageROI()函数来构造RIO,实现对图像指定范围的蓝色通道增加150级操作。笔者将其写成了通过cmd调用和直接调用的两个版本,具体代码如下:
#include <cv.h>#include <highgui.h>using namespace std;int main(int argc, char* argv[]){ IplImage* src; /*******************************cmd*********************************/ //if (argc == 7 && ((src = cvLoadImage(argv[1], 1)) != 0)) //判断传递给主函数的参数个数,加载图像至内存 //{ // int x = atoi(argv[2]); //字符串类型转化为整型 char2int // int y = atoi(argv[3]); // int width = atoi(argv[4]); // int height = atoi(argv[5]); // int add = atoi(argv[6]); /*******************************Address*********************************/ if (src = cvLoadImage("D:\\Template\\OpenCV\\Template12_SetROI\\Debug\\3.jpg")) //加载图像至内存,返回指向的指针 { int x = 100; int y = 100; int width = 100; int height = 100; int add = 150; cvSetImageROI(src, cvRect(x, y, width, height)); //设置ROI cvAddS(src, cvScalar(add), src); //数组与标量的元素级相加 cvResetImageROI(src); //释放ROI cvNamedWindow("Roi_Add", CV_WINDOW_AUTOSIZE); //创建窗口 cvShowImage("Roi_Add", src); //显示图片 cvWaitKey(0); cvReleaseImage(&src); //释放图像内存 cvDestroyWindow("Roi_Add"); //释放窗口 } return 0;}
运行结果如下图:
例3-2 利用widthStep方法把interest_img的所有像素增加1
利用widthStep方法RIO所有像素值增加1,实现cvSetImageROI()函数相同的功能,代码如下:
#include <cv.h>#include <highgui.h>using namespace std;int main(int argc, char* argv[]){ IplImage* interest_img = cvLoadImage("D:\\Template\\OpenCV\\Template12_SetROI\\Debug\\3.jpg"); CvRect interest_rect = cvRect(100,100,100,100); IplImage* sub_img = cvCreateImageHeader( //创建一个图像头 cvSize(interest_rect.width, interest_rect.height), //设置图像头的宽度、高度(与ROI相同) interest_img->depth, //设置图像头的深度(与ROI相同) interest_img->nChannels); //设置图像头的通道数(与ROI相同) sub_img->origin = interest_img->origin; //设置图像头原点(与ROI相同) sub_img->widthStep = interest_img->widthStep; //设置行数据长度(可逐行步进到下一行开头) sub_img->imageData = interest_img->imageData+ //指向第一行数据的指针+ interest_rect.y*interest_img->widthStep + //行数*行数据长度+ interest_rect.x*interest_img->nChannels; //列数*通道数 cvAddS(sub_img, cvScalar(150), sub_img); //数组与标量的元素级相加 cvNamedWindow("Rio_Add", CV_WINDOW_AUTOSIZE); //创建窗口 cvShowImage("Rio_Add", interest_img); //显示图片 cvWaitKey(0); cvReleaseImage(&interest_img); //释放图像内存 cvReleaseImage(&sub_img); //释放图像内存 cvDestroyWindow("Rio_Add"); //释放窗口 return 0;}
运行结果如下图:
widthStep操作可以保持一幅图像的多个子区域处于活动状态,而不必像cvSetImageROI()函数一样反复的设置、重置区域。
例3-3 Alpha(RGBA中的透明度通道)融合
调用cvAddWeighted()函数来实现Alpha融合,实现对两张图像的融合。笔者将其写成了通过cmd调用和直接调用的两个版本,具体代码如下:
#include <cv.h>#include <highgui.h>using namespace std;int main(int argc, char* argv[]){ IplImage* src1,*src2; /*******************************cmd*********************************/ //if (argc == 9 && ((src1 = cvLoadImage(argv[1], 1)) != 0) && ((src2 = cvLoadImage(argv[2], 1)) != 0)) //判断传递给主函数的参数个数,加载图像至内存 //{ // int x = atoi(argv[3]); //字符串类型转化为整型 char2int // int y = atoi(argv[4]); // int width = atoi(argv[5]); // int height = atoi(argv[6]); // double alpha = (double)atof(argv[7]); // double beta = (double)atof(argv[8]); /*******************************Address*********************************/ src1 = cvLoadImage("D:\\Template\\OpenCV\\Template13_AlphaBlend\\Debug\\2.jpg"); src2 = cvLoadImage("D:\\Template\\OpenCV\\Template13_AlphaBlend\\Debug\\3.jpg"); //加载图像至内存,返回指向的指针 int x = 50; int y = 0; int width = 320; int height = 320; double alpha = 0.8; double beta = 0.2; cvSetImageROI(src1, cvRect(x, y, width, height)); //设置ROI cvSetImageROI(src2, cvRect(150, 70, width, height)); //设置ROI cvAddWeighted(src1, alpha, src2, beta,0.0,src1); //AlphaBlend cvResetImageROI(src1); cvResetImageROI(src2); //释放ROI cvNamedWindow("Roi_Add", CV_WINDOW_AUTOSIZE); //创建窗口 cvShowImage("Roi_Add", src1); //显示图片 cvWaitKey(0); cvReleaseImage(&src1); //释放图像内存 cvReleaseImage(&src2); //释放图像内存 cvDestroyWindow("Roi_Add"); //释放窗口 //} return 0;}
运行结果如下图:
例3-4 往磁盘上写一个配置文件 cfg.xml,并将该配置文件读入
笔者未构造相应的色彩转换矩阵,因此省略了编写色彩变换矩阵那个环节,为求方便读入文件时仅打印了部分参数,程序代码如下:
#include <cv.h>#include <highgui.h>using namespace std;int main(){ CvFileStorage* fs = cvOpenFileStorage("cfg.xml",0,CV_STORAGE_WRITE); //创建并打开CvFileStorage写数据 //0:临时内存区域创建 cvWriteInt(fs, "frame_count", 10); //写整型数据 cvStartWriteStruct(fs,"frame_size",CV_NODE_SEQ); //创建结构 cvWriteInt(fs, 0, 320); //编写结构 cvWriteInt(fs, 0, 200); cvEndWriteStruct(fs); //结束结构编写// cvWrite(fs, "color_cvt_matrix", cmatrix); //编写色彩变换矩阵 cvReleaseFileStorage(&fs); //释放CvFileStorage句柄 CvFileStorage* fs1 = cvOpenFileStorage("cfg.xml", 0, CV_STORAGE_READ); //创建并打开CvFileStorage写数据 //0:临时内存区域创建 int frame_cout = cvReadIntByName(fs1, 0, "frame_count", 5); //读一个有名称整数 0:文件节点 CvSeq* s = cvGetFileNodeByName(fs1, 0, "frame_size")->data.seq; //获取文件节点 int frame_width = cvReadInt((CvFileNode*)cvGetSeqElem(s,0)); //读一个无名称整数。 int frame_height = cvReadInt((CvFileNode*)cvGetSeqElem(s,1)); //cvGetSeqElem:指向指定序列元素指针 CvMat * color_cvt_matrix = (CvMat*)cvReadByName(fs1, 0, "color_cvt_matrix"); //找到对象并解码 cvReleaseFileStorage(&fs1); //释放CvFileStorage句柄 cout << "frame_width = " << frame_width << endl << endl; //输出cfg.xml中存储的宽度 system("pause"); //暂停}
运行结果如下图:
此处应当注意,生成的cfg.xml文件的位置,与程序运行的根目录有关。
当在VS环境下使用本地Windows调试器调试运行时,生成的cfg.xml文件位置与项目文件的根目录在一起,如下图:
而直接运行已经编译生成的.exe文件进行写入,此时生成的cfg.xml文件位置,则是.exe文件存放的根目录,如下图:
例3-5 使用OpenCV库函数实现数据类型操作
本例完成的工作如下:
1. 选取一个负的浮点数,取绝对值,四舍五入后取极值; 2. 以系统时间作为种子产生一些随机数; 3. 创建CvPoint2D32f和CvPoint,并进行互相转换;
具体代码如下:
#include <cv.h>#include <highgui.h> #include <stdlib.h> #include <stdio.h> using namespace std;int main(){ float in, absolute; int extremum; in = -1.55; absolute = abs(in); //取绝对值 extremum = cvRound(absolute); //四舍五入取整 cout << "输入= " << in << endl; cout << "绝对值= " << absolute << endl; cout << "四舍五入极值= " << extremum << endl; system("pause"); CvRNG rng; rng = cvRNG(cvGetTickCount()); //64位长整数的时间数据作为种子 for (int i = 0; i<5; i++) { printf("%d\n", cvRandInt(&rng) % 6); //返回均匀分布32位的随机数,%6将会是0~255的正整数 printf("%.2f\n", cvRandReal(&rng)); //返回均匀分布,0~1之间的随机小数 } printf("Tick Frequency= %f\n", cvGetTickFrequency()); //系统时钟频率 system("pause"); CvPoint2D32f pointFloat; CvPoint pointInt; pointFloat = cvPoint2D32f(3.33, 2.22); pointInt = cvPointFrom32f(pointFloat); //CvPoint2D32f-->CvPoint pointFloat = cvPointTo32f(pointInt); //CvPoint2D32f<--CvPoint cout << "整型点= " << pointInt.x << pointInt.y << endl; cout << "浮点型= " << pointFloat.x << pointFloat.y << endl; printf("浮点型= %f %f\n", pointFloat.x, pointFloat.y); system("pause");}
运行结果如下图:
如果使用cout输出发现数值为整数,千万不要认为CvPointf到CvPoint2D32f的转换失败了,而是因为ANSI C++里一个浮点型若是小数部分为0,直接输出必然是不带小数点,结果正如上图。
例3-6 使用OpenCV库函数实现矩阵操作
本例完成的工作如下:
1. 创建一个三通道二维矩阵,字节类型,大小500*500,赋值为0,使用CVCircle()函数画一个圆,并显示,结果如图 1; 2. 通过CVPtrD()函数将指针指向中间的通道并设置为“绿色”,以(20,5)和(40,20)为顶点画一个绿色的长方形,结果如图1; 3. 创建一个100*100的RGB图像,赋值为0,以(20,5)和(40,20)为顶点画一个绿色的平面,结果如图2; 4. 创建一个210*210的单通道图像,赋值为0,使用RIO和cvSet()建立一个增长如金字塔状的数组,最外层为0,第二层为20,第三层40,以此类推,每层为10像素宽度,结果如图3; 5. 读取一个图像,创建两个原点位置设置、深度、通道、行长度都与读取图像相同的图像头。在新的图像头中设置宽度为20,高度为30,将imageData指针指向像素(5,10)和(50,60)像素位置,传递这两个新的图像头给cvNot(),显示读取的图像,大图像中有两个矩形,矩形内的值是原始值的反值,结果如图4。
具体代码如下(代码中附有打印矩阵函数,方便调试时查看矩阵的值):
#include <cv.h>#include <highgui.h> #include <stdlib.h> #include <stdio.h> using namespace std;int main(){ CvMat* firstMat = cvCreateMat(500,500, CV_8UC3); CvPoint center = cvPoint(250, 250); CvPoint rec1 = cvPoint(20, 5); CvPoint rec2 = cvPoint(40, 20); int radius = 100; CvScalar color = CV_RGB(55, 55, 255); CvSize image1size = cvSize(100, 100); IplImage* img1 = cvCreateImage(image1size, IPL_DEPTH_8U, 3); CvSize image2size = cvSize(210, 210); int x = 0; int y = 0; int width = 210; int height = 210; int add = 20; IplImage* img2 = cvCreateImage(image2size, IPL_DEPTH_8U, 1); IplImage* img3 = cvLoadImage("D:\\Template\\OpenCV\\Template16_Create_Mat_Image_Imageheader\\Debug\\3.jpg"); IplImage* img3header1 = cvCreateImageHeader(cvSize(20,30), img3->depth, img3->nChannels); //创建两个新的图像头,通道、深度与原图相同 IplImage* img3header2 = cvCreateImageHeader(cvSize(20, 30), img3->depth, img3->nChannels); //大小20*30 img3header1->widthStep = img3->widthStep; //设置widthStep与原图像相同 img3header2->widthStep = img3->widthStep; img3header1->origin = img3->origin; //设置原点与原图像相同 img3header2->origin = img3->origin; img3header1->imageData = img3->imageData + 5 * img3->widthStep + 10 * img3->nChannels; //指向(5,10)像素位置 img3header2->imageData = img3->imageData + 50 * img3->widthStep + 60 * img3->nChannels; //指向(50,60)像素位置 cvZero(firstMat); //矩阵元素清0 cvZero(img1); //图像元素设置为0 cvZero(img2); //图像元素设置为0 cvNot(img3header1, img3header1); cvNot(img3header2, img3header2); /******************打印矩阵********************/ //for (int i = 0; i<firstMat->cols; i++) //矩阵指针行寻址 //{ // for (int j = 0; j<firstMat->rows; j++) //矩阵指针列寻址 // { // int text = CV_MAT_ELEM(*firstMat,char, i, j); //获取i行j列元素值 // cout << text << " "; //空格 // } // cout << endl; //换行 //} cvCircle(firstMat, center, radius, color); //画一个圆 /**************矩阵上画一个绿色矩形,使用cvPtr2D算法***************/ for (int i = 20; i<40; i++) //矩阵指针行寻址 { for (int j = 5; j<20; j++) //矩阵指针列寻址 { uchar *ptr = cvPtr2D(firstMat, i, j); //index1 行 index2 列 ptr[1] = 255; //*****ptr[0]=255为蓝色 ptr[1]=255为绿色 ptr[2]=255为红色***/ } } /***********图像上画一个绿色矩形,指针算法**************/ for (int i = 20; i<40; i++) //矩阵指针行寻址 { uchar *ptr = (uchar*)img1->imageData + i*img1->widthStep; //index1 行 index2 列 for (int j = 5; j<20; j++) //矩阵指针列寻址 { ptr[3*j+1] = 255; //*****ptr[0]=255为蓝色 ptr[1]=255为绿色 ptr[2]=255为红色***/ } } /******************图像上做一个金字塔状数组,用RIO和cvSet()建立********************/ for (int i = 0; i < 10; i++) { cvSetImageROI(img2, cvRect(x, y, width, height)); //设置ROI// cvAddS(img2, cvScalar(add), img2); //数组与标量的元素级相加 cvSet(img2, cvScalar(20*i)); //设置所选通道所有值 cvResetImageROI(img2); //释放ROI x += 10; y += 10; width -= 20; height -= 20; } cvNamedWindow("Mat", CV_WINDOW_AUTOSIZE); //在窗口中显示 cvShowImage("Mat", firstMat); cvNamedWindow("Image1", CV_WINDOW_AUTOSIZE); //在窗口中显示 cvShowImage("Image1", img1); cvNamedWindow("Image2", CV_WINDOW_AUTOSIZE); //在窗口中显示 cvShowImage("Image2", img2); cvNamedWindow("Image3", CV_WINDOW_AUTOSIZE); //在窗口中显示 cvShowImage("Image3", img3); cvWaitKey(0); cvReleaseMat(&firstMat); cvReleaseImage(&img1); cvReleaseImage(&img2); cvReleaseImage(&img3); cvDestroyWindow("Mat"); cvDestroyWindow("Image1"); cvDestroyWindow("Image2"); cvDestroyWindow("Image3");}
运行结果如下图:
例3-7 使用OpenCV库函数实现图像操作
本例完成的工作如下:
1. 加载一幅真实的图像,使用cvSplit()将图像分割为红、绿、蓝三个通道的图像,找到并显示绿图; 2. 克隆绿图两次,clone1和clone2; 3. 找出绿色平面的最大、最小值; 4. 将clone1的元素赋值为thresh=(max-min)/2.0; 5. 将clone2的元素赋值为0,调用cvCmp()函数,将clone2穿建伟一个标识绿图中值超过thresh的掩码图像; 6. 使用cvSubS()函数进行处理,并显示结果。
具体代码如下(为了显示对比效果明显最后的cvSubS()叠加的值设置为100):
#include <cv.h>#include <highgui.h> #include <stdlib.h> #include <stdio.h> using namespace std;int main(){ IplImage* img = cvLoadImage("D:\\Template\\OpenCV\\Template17_Image_Split_Clone_CmpMask\\Debug\\3.jpg"); IplImage* imgR = cvCreateImage(cvGetSize(img), img->depth, 1); IplImage* imgG = cvCreateImage(cvGetSize(img), img->depth, 1); IplImage* imgB = cvCreateImage(cvGetSize(img), img->depth, 1); IplImage* clone1 = cvCreateImage(cvGetSize(img), img->depth, 1); IplImage* clone2 = cvCreateImage(cvGetSize(img), img->depth, 1); double* minG = NULL; double* maxG = NULL; uchar thresh = (uchar)((maxG - minG) / 2.0); cvSplit(img, imgR, imgG, imgB, NULL); cvNamedWindow("Green", CV_WINDOW_AUTOSIZE); //在窗口中显示绿图 cvShowImage("Green", imgG); cvCopy(imgG, clone1); //克隆绿图 cvCopy(imgG, clone2); cvMinMaxLoc(imgG, minG, maxG); //找出绿图平面中最大值最小值 cvSet(clone1, cvScalar(thresh)); //clone1所有元素赋值为thresh cvZero(clone2); //clone2赋值为0 cvCmp(imgG, clone1, clone2, CV_CMP_GE); //设置clone2为标识绿图中超过thresh的掩码// cvSubS(imgG, cvScalar(thresh / 2), imgG, clone2); cvSubS(imgG, cvScalar(100), imgG, clone2); cvNamedWindow("Change", CV_WINDOW_AUTOSIZE); //在窗口中显示绿图 cvShowImage("Change", imgG); cvWaitKey(0); cvReleaseImage(&img); cvReleaseImage(&imgR); cvReleaseImage(&imgG); cvReleaseImage(&imgB); cvReleaseImage(&clone1); cvReleaseImage(&clone1); cvDestroyWindow("Green"); cvDestroyWindow("Change");}
运行结果如下图:
例3-8 创建一个结构,实现磁盘存储、读入
本例完成的工作如下:
1. 创建一个结构体包含int、CvPoint和CvRect; 2. 构造该结构体的读写函数; 3. 创建一个长度为10的该结构体数组,写入磁盘、读入内存。
具体代码如下(本例中文件名处更改了路径,因此创建的文件出现在D盘):
#include <cv.h>#include <highgui.h> #include <stdlib.h> #include <stdio.h> using namespace std;typedef struct mystruct{ int m_x; CvPoint m_point; CvRect m_rect;}mystruct;void write_mystruct(CvFileStorage *fs, char *name, mystruct *ms){ fs = cvOpenFileStorage(name, 0, CV_STORAGE_WRITE); //创建并打开CvFileStorage写数据 //0:临时内存区域创建 cvWriteInt(fs, "my_int", ms->m_x); //写整型数据 cvStartWriteStruct(fs, "my_point", CV_NODE_SEQ); //创建结构 cvWriteInt(fs, 0, ms->m_point.x); //编写结构 cvWriteInt(fs, 0, ms->m_point.y); cvEndWriteStruct(fs); //结束结构编写 cvStartWriteStruct(fs, "my_rect", CV_NODE_SEQ); cvWriteInt(fs, 0, ms->m_rect.height); cvWriteInt(fs, 0, ms->m_rect.width); cvWriteInt(fs, 0, ms->m_rect.x); cvWriteInt(fs, 0, ms->m_rect.y); cvEndWriteStruct(fs); cvReleaseFileStorage(&fs); //释放CvFileStorage句柄}void read_mystruct(CvFileStorage *fs, CvFileNode* ms_node, mystruct *ms){ fs = cvOpenFileStorage("D:\\mystruct.xml", 0, CV_STORAGE_READ); //创建并打开CvFileStorage读数据 int frame_cout = cvReadIntByName(fs, 0, "my_int", 5); //读一个有名称整数 0:文件节点 CvSeq* s = cvGetFileNodeByName(fs, 0, "my_point")->data.seq; //获取文件节点 int point_x = cvReadInt((CvFileNode*)cvGetSeqElem(s, 0)); //读一个无名称整数 int point_y = cvReadInt((CvFileNode*)cvGetSeqElem(s, 1)); //cvGetSeqElem:指向指定序列元素指针 CvSeq* s1 = cvGetFileNodeByName(fs, 0, "my_rect")->data.seq; int rect_height = cvReadInt((CvFileNode*)cvGetSeqElem(s1, 0)); int rect_width = cvReadInt((CvFileNode*)cvGetSeqElem(s1, 1)); int rect_x = cvReadInt((CvFileNode*)cvGetSeqElem(s1, 2)); int rect_y = cvReadInt((CvFileNode*)cvGetSeqElem(s1, 3)); cvReleaseFileStorage(&fs); //释放CvFileStorage句柄 cout << "rect_height = " << rect_height << endl; //输出cfg.xml中存储的宽度 system("pause"); //暂停}int main(){ mystruct m_array[10]; CvFileStorage *m_fs = NULL; CvFileNode* m_node = NULL; m_array[0] = { 1, cvPoint(1, 1), cvRect(1, 1, 1, 1) }; m_array[1] = { 2, cvPoint(2, 2), cvRect(2, 2, 2, 2) }; write_mystruct(m_fs, "D:\\mystruct.xml", m_array); read_mystruct(m_fs, m_node, m_array);}
运行结果如下图:
- 第三章 学习OpenCV——初探OpenCV
- 第三章 初探opencv
- 《学习opencv》学习笔记 - 第三章 初探opencv
- 学习OpenCV第三章练习题——3-4
- 学习opencv第三章答案
- 《学习OpenCV》练习题第三章第三题
- 《学习OpenCV》练习题第三章第三题
- OpenCV学习笔记(四十四)——初探GPU
- OpenCV学习笔记[1]初探OpenCV
- 【opencv机器学习】SVM 初探
- 学习Opencv第三章IplImage类型
- 学习opencv第四章第三题
- 《学习OpenCV》练习题第二章第三题
- 《学习OpenCV》练习题第三章第一题
- 《学习OpenCV》练习题第三章第二题
- 《学习OpenCV》练习题第三章第四题
- 《学习OpenCV》练习题第三章第五题
- 《学习OpenCV》练习题第三章第六题
- 关于建立技术兴趣小组的方案
- java synchronized详解
- 高效Java08:覆盖equals时遵守通用约定
- ELKstack 学习笔记(2)
- 微信端调用扫一扫
- 第三章 学习OpenCV——初探OpenCV
- Uva1401/LA3942 Remember the Word(trie模板)
- 多任务
- centos下将用户加进sudoers中
- 单链表反转(带头结点版)
- css-响应Web设计-img
- MVP详解
- Java中的23种设计模式详解(转)
- 使用Nginx+集群Tomcat实现负载均衡