计算机视觉,是在图像处理的基础上发展起来的新兴学科,专门研究,让机器“看”的科学;
什么是OpenCV
OpenCV ,Open Source Computer Vision Library,是一个开源的,跨平台的视觉库;是从事机器视觉算法广泛使用的工具;Intel 是OpenCV的诞生地;
OpenCV,包含计算机视觉各个领域的函数有500多个,包括工厂产品检验,医学成像,安全,用户界面,摄像机校正,立体视觉,机器人等。
什么是计算机的视觉
计算机视觉,将静止图像或视频的数据转换成一个决策或者一种新的表达方式的过程,所有的这些转换都是为了达到某个目标;
在计算机视觉系统中,计算机接收的只是一个数值矩阵;
OpenCv的目标是为解决计算机视觉问题提供基本工具,它提供的高层函数可以高效地解决计算机视觉中的一些很复杂的问题;
OpenCV的结构和内容
OpenCV主体2分为五个模块:
OpenCV的CV模块,包含基本的图像处理函数和高级的计算机视觉算法;
OpenCV的ML模块,是机器学习库,包含一些基于统计的分类和聚类工具;
OpenCV的HighGUI,包含图像和视频输入/输出的函数;
OpenCV的CXCore,包含OpenCV的一些基本数据结构和相关函数;
OpenCV的CvAux模块,该模块中一般存放一些将被淘汰的算法和函数,同时还有一些新出现的实验性的算法和函数;
显示图像
#include <opencv2/opencv.hpp> //Include file for every supported OpenCV function int main( int argc, char** argv ) { cv::Mat img = cv::imread(argv[1],-1); if( img.empty() ) return -1; cv::namedWindow( "Example1", cv::WINDOW_AUTOSIZE ); cv::imshow( "Example1", img ); cv::waitKey( 0 ); cv::destroyWindow( "Example1" ); return 0; }
该程序是向内存加载一幅图像,并将图像显示于屏幕上,直至按下任意键,关闭窗口并退出程序;Learning OpenCV 3,英文版的与中文版的代码,所用函数有差别;cv::imread()是一个高层调用接口;cv::Mat是一个结构体,相当于STL的容器,管理图像并可以自动释放内存;cv::namedWindow()是另一个高层函数,用以打开窗口显示图像,该函数是HighGUI库提供;cv::waitKey()函数,参数0,停止程序执行并等待按下任意键,参数为正整数为等待时间并继续程序执行;
播放AVI视频
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" int main( int argc, char** argv ) { cv::namedWindow( "Example3", cv::WINDOW_AUTOSIZE ); cv::VideoCapture cap; cap.open( string(argv[1]) ); cv::Mat frame; for(;;) { cap >> frame; if( frame.empty() ) break; // Ran out of film cv::imshow( "Example3", frame ); if( cv::waitKey(33) >= 0 ) break; } return 0; }
namedWindow创建一个窗口,VideoCapture视频捕捉类,cap对象,open打开视频,Mat结构体,frame容器,打开的视频放入容器,imshow播放,frame为空播放结束;
加滑动条的视频播放
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <fstream> using namespace std; int g_slider_position = 0; int g_run = 1, g_dontset = 0; //start out in single step mode cv::VideoCapture g_cap; void onTrackbarSlide(int pos, void *) { g_cap.set(cv::CAP_PROP_POS_FRAMES, pos); if (!g_dontset) g_run = 1; g_dontset = 0; } int main(int argc, char** argv) { cv::namedWindow("Example2_4", cv::WINDOW_AUTOSIZE); g_cap.open(string(argv[1])); /*打开视频*/ int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);//获取视频的帧数 int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH); //获取视频的宽 int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT); //获取视频的高 cout << "Video has " << frames << " frames of dimensions(" << tmpw << ", " << tmph << ")." << endl; cv::createTrackbar("Position", "Example2_4", &g_slider_position, frames, onTrackbarSlide); //在窗口上创建滑动条 cv::Mat frame; /*Mat容器*/ for (;;) { if (g_run != 0) { g_cap >> frame; if (frame.empty()) break; int current_pos = (int)g_cap.get(cv::CAP_PROP_POS_FRAMES); g_dontset = 1;
//设置滑动条位置 cv::setTrackbarPos("Position", "Example2_4", current_pos); cv::imshow("Example2_4", frame); g_run -= 1; //s停止播放一帧,g_run == 0 } char c = (char)cv::waitKey(10); //获取按键字符 if (c == 's') // single step { g_run = 1; cout << "Single step, run = " << g_run << endl; } if (c == 'r') // run mode { g_run = -1; cout << "Run mode, run = " << g_run << endl; } if (c == 27) break; } return(0); }
前导g_ 表示全局变量的意思
一个简单的变换,载入一个图像并进行平滑处理(模糊处理)
#include <opencv2/opencv.hpp> void example2_5(const cv::Mat & image) { // Create some windows to show the input // and output images in. // cv::namedWindow("Example2_5-in", cv::WINDOW_AUTOSIZE); cv::namedWindow("Example2_5-out", cv::WINDOW_AUTOSIZE); // Create a window to show our input image // cv::imshow("Example2_5-in", image); // Create an image to hold the smoothed output // cv::Mat out; // Do the smoothing // ( Note: Could use GaussianBlur(), blur(), medianBlur() or bilateralFilter(). ) // cv::GaussianBlur(image, out, cv::Size(5, 5), 3, 3); cv::GaussianBlur(out, out, cv::Size(5, 5), 3, 3); // Show the smoothed image in the output window // cv::imshow("Example2_5-out", out); // Wait for the user to hit a key, windows will self destruct // cv::waitKey(0); } int main(int argc, char** argv) { cv::Mat image = cv::imread(argv[1], -1); if (image.empty()) return -1; example2_5(image); return 0; }
一个复杂一点的变换,创建一幅宽高为输入图像一半尺寸的图像
#include <opencv2/opencv.hpp> int main(int argc, char** argv) { cv::Mat img1, img2; cv::namedWindow("Example1", cv::WINDOW_AUTOSIZE); cv::namedWindow("Example2", cv::WINDOW_AUTOSIZE); img1 = cv::imread(argv[1]); cv::imshow("Example1", img1); cv::pyrDown(img1, img2); cv::imshow("Example2", img2); cv::waitKey(0); return 0; };
cv::pyrDown()
Canny边缘检测,将输出写入一个单通道图像
#include <opencv2/opencv.hpp> int main(int argc, char** argv) { cv::Mat img_rgb, img_gry, img_cny; cv::namedWindow("Example Gray", cv::WINDOW_AUTOSIZE); cv::namedWindow("Example Canny", cv::WINDOW_AUTOSIZE); img_rgb = cv::imread(argv[1]); cv::cvtColor(img_rgb, img_gry, cv::COLOR_BGR2GRAY); cv::imshow("Example Gray", img_gry); cv::Canny(img_gry, img_cny, 10, 100, 3, true); cv::imshow("Example Canny", img_cny); cv::waitKey(0); }
cv::cvtColor()将彩图转换为灰度图,cv::Canny()边缘检测器,将灰度图的边缘检测输入到一个单通道图像
两次缩放处理,并Canny边缘检测
#include <opencv2/opencv.hpp> int main(int argc, char** argv) { cv::Mat img_rgb, img_gry, img_cny, img_pyr, img_pyr2; cv::namedWindow("Example Gray", cv::WINDOW_AUTOSIZE); cv::namedWindow("Example Canny", cv::WINDOW_AUTOSIZE); img_rgb = cv::imread(argv[1]); cv::cvtColor(img_rgb, img_gry, cv::COLOR_BGR2GRAY); cv::imshow("Example Gray", img_gry); // cv::pyrDown(img_gry, img_pyr); cv::pyrDown(img_pyr, img_pyr2); cv::Canny(img_pyr2, img_cny, 10, 100, 3, true); // do whatever with 'img_cny' // cv::Canny(img_gry, img_cny, 10, 100, 3, true); cv::imshow("Example Canny", img_cny); cv::waitKey(0); }
在上例中获取设置像素
int x = 16, y = 32; cv::Vec3b intensity = img_rgb.at< cv::Vec3b >(y, x); // ( Note: We could write img_rgb.at< cv::Vec3b >(x,y)[0] ) // uchar blue = intensity[0]; uchar green = intensity[1]; uchar red = intensity[2]; std::cout << "At (x,y) = (" << x << ", " << y << "): (blue, green, red) = (" << (unsigned int)blue << ", " << (unsigned int)green << ", " << (unsigned int)red << ")" << std::endl; std::cout << "Gray pixel there is: " << (unsigned int)img_gry.at<uchar>(y, x) << std::endl; x /= 4; y /= 4; std::cout << "Pyramid2 pixel there is: " << (unsigned int)img_pyr2.at<uchar>(y, x) << std::endl; img_cny.at<uchar>(x, y) = 128; // Set the Canny pixel there to 128
同一个对象,可以从摄像机读取,也可以从文件读取
#include <opencv2/opencv.hpp> #include <iostream> int main(int argc, char** argv) { cv::namedWindow("Example2_10", cv::WINDOW_AUTOSIZE); cv::VideoCapture cap; //打开 if (argc == 1) { cap.open(0); // open the first camera } else { cap.open(argv[1]); } if (!cap.isOpened()) { // check if we succeeded std::cerr << "Couldn't open capture." << std::endl; return -1; } //播放 cv::Mat frame; for (;;) { cap >> frame; if (frame.empty()) break; // Ran out of film cv::imshow("Example2_10", frame); if (cv::waitKey(33) >= 0) break; } cv::waitKey(0); return 0; }
写入AVI视频文件,创建一个写入设备逐帧将视频流写入视频文件
#include <opencv2/opencv.hpp> #include <iostream> int main(int argc, char* argv[]) { cv::namedWindow("Example2_11", cv::WINDOW_AUTOSIZE); cv::namedWindow("Log_Polar", cv::WINDOW_AUTOSIZE); // ( Note: could capture from a camera by giving a camera id as an int.) // cv::VideoCapture capture(argv[1]); double fps = capture.get(cv::CAP_PROP_FPS); cv::Size size( (int)capture.get(cv::CAP_PROP_FRAME_WIDTH), (int)capture.get(cv::CAP_PROP_FRAME_HEIGHT) ); cv::VideoWriter writer; writer.open(argv[2], CV_FOURCC('M', 'J', 'P', 'G'), fps, size); cv::Mat logpolar_frame, bgr_frame; for (;;) { capture >> bgr_frame; if (bgr_frame.empty()) break; // end if done cv::imshow("Example2_11", bgr_frame); cv::logPolar( bgr_frame, // Input color frame logpolar_frame, // Output log-polar frame cv::Point2f( // Centerpoint for log-polar transformation bgr_frame.cols / 2, // x bgr_frame.rows / 2 // y ), 40, // Magnitude (scale parameter) cv::WARP_FILL_OUTLIERS // Fill outliers with 'zero' ); cv::imshow("Log_Polar", logpolar_frame); writer << logpolar_frame; char c = cv::waitKey(10); if (c == 27) break; // allow the user to break out } capture.release(); }
cv::VideoWriter