因为要参加老师的一个小项目,所以今天开始学习关于Opencv的内容,昨天刚刚配置好Opencv,是在Visual Studio2017上面配置的Opencv 3.4.1,如果大家配置的话,(因为后面博客中配置的版本为3.2.0,我们配置的版本为3.4.1,我们需要将最后一步中的"opencv_world320d.lib",换成“opencv_world341d.lib”即可)可以参考一下: https://blog.csdn.net/sinat_36264666/article/details/73135823?ref=myread
栗子2-1:
#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <highgui.h> using namespace cv; int main(int argc, char **argv) { IplImage *img = cvLoadImage("图片位置"); cvNamedWindow("Example1", 0); cvShowImage("Example1", img); cvWaitKey(0); cvReleaseImage(&img); cvDestroyWindow("Example1"); }
cvLoadImage函数:将图片加载到内存,函数通过文件名确定被加载文件的格式,并且该函数将自动分配图像数据结构所需要的内存,函数结束后返回一个指针,指针的类型为IplImage
cvNamedWindow函数:函数创建一个窗口,第一个参数为窗口的名称,后面如果用到这个窗口就可以调用他的名字,第二个参数可以是0,也可以是CV_WINDOW_AUTOSIZE,不同就是:0可以手动改变窗口的大小,CV_WINDOW_AUTOSIZE则不能手动更改窗口大小
cvShowImage函数:在一个已经创建好的窗口中显示img指向的图像,当再次被调用时,窗口会被重新绘制
cvWaitKey函数:参数可以是任意实数:0或者负数的时候,程序会一直等到用户触发(按下任意一个按键),否则程序会等待相应的ms数
cvReleaseImage cvDestoryWindow函数:分别释放相应的内存
栗子2-2
#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <highgui.h> using namespace cv; int main(int argc, char **argv) { cvNamedWindow("Example2", CV_WINDOW_AUTOSIZE); CvCapture* capture = cvCreateFileCapture("视频位置"); IplImage * frame; while (1) { frame = cvQueryFrame(capture); if (!frame) break; cvShowImage("Example2", frame); char c = cvWaitKey(33); if (c == 27) break; } cvReleaseCapture(&capture); cvDestroyWindow("Example2"); }
CvCreateFileCapture函数:通过参数确定AVI文件位置,返回一个指向CvCapture结构的指针,并且该指针会被初始化为对应AVI文件的开头
cvQueryFrame函数: 装载下一帧视频文件到内存,返回当前帧的指针,而且含住使用的是cvCapture中分配好的内存,所以就不需要通过cvReleaseCapture函数来释放空间
我们观察发现,cvWaitKey函数中参数为33,那么含义就是等到33ms,如果返回值为27(对应键盘中的ESC键),那么就会停止while循环,否则继续进行循环,那么也就是每一帧的效果都是通过固定的时间来进行更新的,我们可以通过cvCaptureFromCamera()函数 来对帧率进行更好地判定
栗子2-3
实现读取视频进度条的添加,这样的,我们首先要知道一个函数的作用以及具体的参数:
int cvCreateTrackbar(//创建滑动条的函数 const char* trackbar_name, //滑动条的名称 const char* window_name, //窗口的名称 int* value, //当滑动条被拖到时,OpenCV会自动将当前位置所代表的值传给指针指向的整数 int count, //滑动条所能达到的最大值(所有的帧数) CvTrackbarCallback on_change //回调函数,每次滑块位置改变时,调用的函数的指针,并且函数应该声明为void Foo(int),如果没有回调函数,则设置为NULL);
两个得到或者修改CvCapture对象的各种属性的函数(如果要知道所有的参数的话,可以参考:OpenCV参考手册之CvCapture结构体):
cvSetCaptureProperty() cvGetCaptureProperty()
我们这里用到的是修改当前的帧数的位置,以及得到当前视频信息的所有帧数,我们知道这三个函数信息,以及2-2的视频播放设置,我们就可以很容易理解下面给出的程序了
#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <highgui.h> using namespace cv; int g_slider_position = 0; //滚动条位置全局变量 CvCapture* g_capture = NULL; //确定要读入AVI文件的指针 void onTrackbarSlide(int pos) { cvSetCaptureProperty(g_capture, CV_CAP_PROP_POS_FRAMES, pos); //以帧数设置读入位置 }//回调函数,当拖时调用这个函数 int main(int argc, char** argv) { cvNamedWindow("Example3", CV_WINDOW_AUTOSIZE); //创建窗口 g_capture = cvCreateFileCapture("视频位置"); int frames = (int)cvGetCaptureProperty(g_capture, CV_CAP_PROP_FRAME_COUNT); //获取总帧数以设定滚动条 if (frames != 0) { cvCreateTrackbar("Position", "Example3", &g_slider_position, frames, onTrackbarSlide); //创建滚动条 } IplImage* frame; while (1) { frame = cvQueryFrame(g_capture); if (!frame) break; cvShowImage("Example3", frame); g_slider_position ++; cvCreateTrackbar("Position", "Example3", &g_slider_position, frames, onTrackbarSlide);//重新更新进度条 char c = cvWaitKey(32); if (c == 27) break; } cvReleaseCapture(&g_capture); cvDestroyWindow("Example3"); return(0); }
实现效果是:进度条在视频的上方,很诡异........
栗子2-4
一个简单的变换,要求我们对图像进行平滑处理,我们这里面会涉及到的函数包括:
cvCreateImage函数,具体参见:https://blog.csdn.net/lixam/article/details/7596074
IplImage* cvCreateImage( CvSize size, int depth, int channels ); //size:图像大小 //depth:图像元素的位深度 //channels:每个元素(像素)通道号
cvGetSize()函数:函数返回图像的长宽
cvsmooth()函数:函数平滑滤波 详见:https://www.cnblogs.com/yangxuebing/p/6896260.html
#include <cv.h> #include <highgui.h> using namespace std; void example2_4(IplImage* image) { cvNamedWindow("Example4-in", CV_WINDOW_AUTOSIZE); cvNamedWindow("Example4-out", CV_WINDOW_AUTOSIZE); cvShowImage("Example4-in", image); IplImage* out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 3); //(图像大小,每个像素点数据类型 ,通道数) cvSmooth(image, out, CV_GAUSSIAN, 3, 3); //对3*3的区域进行高斯平滑处理 cvShowImage("Example4-out", out); cvReleaseImage(&out); cvReleaseImage(&image); cvWaitKey(0); cvDestroyWindow("Example4-in"); cvDestroyWindow("Example4-out"); } int main(int argc, char** argv) { IplImage *img = cvLoadImage("图片地址"); example2_4(img); }
实现效果:
使用opencv3的语法:
#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; int main() { namedWindow("原图",0); namedWindow("图像腐蚀",0); Mat img = imread("图片位置"); imshow("原图", img); Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));(返回指定形状和尺寸的结构元素) Mat dstImage; erode(img, dstImage, element); (进行腐蚀操作) imshow("图像腐蚀", dstImage); waitKey(0); destroyAllWindows(); return 0; }
栗子2-5
实现图片的缩放,那么对应的函数就是:cvPyrUp,cvPyrDown ,他们的类型是类似的,我们需要串的参数也是相同的,但是我们在cvCreateImage上我们所创建的图像大小就不能相同了,在缩小最前会有一个断言,就是只有在长宽像素都是偶数的情况下我们才能进行缩小操作
#include <cv.h> #include <highgui.h> using namespace std; IplImage* doPyrDomn(IplImage *in,int filter = CV_GAUSSIAN_5x5) { assert(in->width % 2 == 0 && in->height % 2 == 0); IplImage *out = cvCreateImage( cvSize(in->width / 2, in->height / 2), in->depth, in->nChannels ); cvPyrDown(in, out); return out; } IplImage* doPyrUp(IplImage *in) { IplImage *out = cvCreateImage( cvSize(in->width * 2, in->height * 2), in->depth, in->nChannels ); cvPyrUp(in, out); return out; } int main(int argc, char** argv) { IplImage *img = cvLoadImage("图片位置"); cvNamedWindow("Example5 - in",CV_WINDOW_AUTOSIZE); cvNamedWindow("Example5 - out1", CV_WINDOW_AUTOSIZE); cvNamedWindow("Example5 - out2", CV_WINDOW_AUTOSIZE); cvShowImage("Example5 - in", img); IplImage *out = doPyrDomn(img); cvShowImage("Example5 - out1", out); out = doPyrUp(img); cvShowImage("Example5 - out2", out); cvWaitKey(0); cvReleaseImage(&img); cvReleaseImage(&out); cvDestroyAllWindows(); }
栗子2-6
要求进行Canny边界检测,那么Canny算法在opencv中的函数是:
Canny(const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size = 3)
具体参照:https://blog.csdn.net/hitwengqi/article/details/6877864
Canny函数要求输入的图像必须是单通道的图片,那么我们在函数cvLoadImage()的第二个参数就有是否加载颜色的表示
-1:默认读取图像原通道数
0:强制转换为灰度图片
1:读取彩色图
除了这种方法还有利用cvCVtColor()函数:
cvCvtColor(img, img_, CV_BGR2GRAY);//将img强制转换为img_灰度图片
#include <cv.h> #include <highgui.h> using namespace std; IplImage * doCanny(IplImage* in, double lowThresh, double highThresh, double aperture) { if (in->nChannels != 1) return 0; IplImage *out = cvCreateImage( cvGetSize(in), IPL_DEPTH_8U, 1 ); cvCanny(in, out, lowThresh, highThresh, aperture); return out; } int main(int argc, char** argv) { IplImage *img = cvLoadImage("图片位置",-1); IplImage *out = doCanny(img, 50, 150, 3); cvNamedWindow("Example5 - in",0); cvNamedWindow("Example5 - out",0); cvShowImage("Example5 - in",img); cvShowImage("Example5 - out", out); cvWaitKey(0); cvReleaseImage(&img); cvReleaseImage(&out); cvDestroyAllWindows(); }
栗子2-7
因为栗子为上面两个的结合,就不在进行叙述
#include <cv.h> #include <highgui.h> using namespace std; IplImage * doCanny(IplImage* in, double lowThresh, double highThresh, double aperture) { if (in->nChannels != 1) return 0; IplImage *out = cvCreateImage( cvGetSize(in), IPL_DEPTH_8U, 1 ); cvCanny(in, out, lowThresh, highThresh, aperture); return out; } IplImage *doPyrDomn(IplImage *in) { assert(in->width % 2 == 0 && in->height % 2 == 0); IplImage *out = cvCreateImage( cvSize(in->width / 2, in->height / 2), in->depth, in->nChannels ); cvPyrDown(in, out); return out; } int main(int argc, char** argv) { cvNamedWindow("Example7", CV_WINDOW_AUTOSIZE); cvNamedWindow("Example7-G", CV_WINDOW_AUTOSIZE); cvNamedWindow("Example7-S", CV_WINDOW_AUTOSIZE); cvNamedWindow("Example7-SG", CV_WINDOW_AUTOSIZE); IplImage *img = cvLoadImage("C:\\Users\\dell\\Desktop\\乱七八糟\\图片\\3.jpg",-1); IplImage *img_ = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,img->nChannels); cvShowImage("Example7", img); //原图 img_ = doPyrDomn(img); img = doPyrDomn(img_);// cvShowImage("Example7-S",img);//缩小两倍 IplImage *Gimg = cvCreateImage(cvGetSize(img), img->depth, 1); cvCvtColor(img, Gimg, CV_BGR2GRAY); cvShowImage("Example7-G", Gimg);//灰度图 IplImage *out = doCanny(Gimg, 50, 150, 3); cvShowImage("Example7-SG", out);//Canny边界检测 cvWaitKey(0); cvReleaseImage(&img); cvReleaseImage(&img_); cvReleaseImage(&out); cvReleaseImage(&Gimg); cvDestroyAllWindows(); }
栗子2-8
从摄像机读入数据,怎么更改设置我的摄像头都是只是有一个灰框,无法成像,所以换做成opencv3的语法成功实现
参考文献
《学习Opencv》