《Learning Opencv3》第二章 Opencv介绍
第二章 介绍OpenCV
文章目录
以下是本人阅读《Learning OpenCV3》后的一些体会和笔记,没有详细的全文翻译,恳请批评指正。
一、头文件和命名空间
OpenCV有很多头文件,你可以用opencv.hpp
包含所有的OpenCV函数,但此时编译时间就会变长。也可以用各个模块的头文件,例如imgproc.hpp
。
命名空间using namespace cv;
不要忘了,可以不用在OpenCV的函数前面写cv::
。
二、读取图片和视频
2.1 读取图片
头文件:
头文件highgui.hpp
(high-level graphical user interface),用在读取、输入输出、鼠标、按键、滑条中。
Mat 类:
Mat img = imread( argv[1], -1 );
Mat类负责图像数据的存储,可以总动分配和释放内存(就像数据结构里面的STL一样)。
显示图像:
namedWindow( "Example 2-1", cv::WINDOW_AUTOSIZE );
创建一个窗口。
imshow( "Example 2-1", img );
显示图像。
destroyWindow( "Example 2-1" );
关闭窗口。
2.2 读取视频
视频是通过for循环,一帧一帧读取的。
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
int main( int argc, char** argv ) {
cv::VideoCapture cap;
cap.open( string(argv[1]) );
cout <<"Opened file: " <<argv[1] <<endl;
cv::Mat frame;
for(;;) {
cap >> frame;
if( frame.empty() ) break; // Ran out of film
cv::imshow( "Example 2-3", frame );
if( (char)cv::waitKey(33) >= 0 ) break;
}
return 0;
}
VideoCapture cap;
VideoCapture类负责视频的读取。
cap.open( string(argv[1]) );
初始化视频的信息,例如大小、路径等
在for循环中使用输出流运算符>>
读取视频的帧,并显示每一帧的图像。waitKey(33) >= 0
,是指每一帧都应该延时33ms。
三、创建滑动条
#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( "Example 2-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","Example 2-4",&g_slider_position,
frames,onTrackbarSlide);
//设置滑动条的位置 并且名为position 在窗口main中显示 滑动条的滑动位置 滑动条的最大值 每次滑动条改变时的回调函数
cv::Mat frame;
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", "Example 2-4", current_pos);//设置滑动条位置
cv::imshow( "Example 2-4", frame );
g_run-=1;
}
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);
}
VideoCapture 的 get()和set() 函数可以获得和设置视频信息,控制条的量程被设置成视频总帧数,在控制条回调函数中设置到相应的位置。
四、对图像进行简单处理
4.1 高斯模糊
#include <opencv.hpp>
using namespace cv;
int main()
{
Mat image = imread("1.jpg", -1);
namedWindow("GaussianBlur-out", WINDOW_AUTOSIZE);
imshow("GaussianBlur-in", image);
Mat out;
namedWindow("GaussianBlur-in", WINDOW_AUTOSIZE);
GaussianBlur(image, out, Size(5, 5), 3, 3);
GaussianBlur(out, out, Size(5, 5), 3, 3);
imshow("GaussianBlur-out", out);
waitKey(0);
return 0;
}
图像结果如图:
4.2 pyDown
pyrDown 采用高斯金字塔算法来向下采样,对图像进行高斯卷积,将所有偶数行、列去掉,最终将图片大小(长、宽)变为原来的一半。
#include <opencv.hpp>
using namespace cv;
int main()
{
Mat img1, img2;
namedWindow("in", WINDOW_AUTOSIZE);
namedWindow("out", WINDOW_AUTOSIZE);
img1 = imread("1.jpg",-1);
imshow("in", img1);
pyrDown(img1, img2);
imshow("out", img2);
waitKey(0);
return 0;
};
图像结果如图:
4.3 canny提取边缘
canny函数的两个阈值参数:低于阈值1的像素点会被认为不是边缘;高于阈值2的像素点会被认为是边缘;在阈值1和阈值2之间的像素点,若与第2步得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘。
int main() {
Mat img_rgb, img_gry, img_cny;
namedWindow("Gray", WINDOW_AUTOSIZE);
namedWindow("Canny", WINDOW_AUTOSIZE);
img_rgb = imread("1.jpg");
cvtColor(img_rgb, img_gry, COLOR_BGR2GRAY);
imshow("Gray", img_gry);
//canny(输入,输出,阈值1,阈值2,Sober算子大小)
Canny(img_gry, img_cny, 50, 100, 3, true);
imshow("Canny", img_cny);
waitKey(0);
}
图像结果如图:
五、摄像头输入
和打开视频的操作对比,打开视频中cap.open()
中初始化视频信息,摄像头输入是打开默认摄像头cap.open(0);
。
int main() {
namedWindow("camera", WINDOW_AUTOSIZE);
VideoCapture cap;
cap.open(0);
Mat frame;
for (;;) {
cap >> frame;
if (frame.empty()) break; // Ran out of film
imshow("camera", frame);
if ((char)cv::waitKey(33) >= 0) break;
}
return 0;
}
六、输出AVI文件
将视频经过对数变换后输出,效果会做噩梦的。
int main()
{
namedWindow("Writing AVI File", cv::WINDOW_AUTOSIZE);
namedWindow("Log_Polar", cv::WINDOW_AUTOSIZE);
VideoCapture capture("1.avi");
double fps = capture.get(CV_CAP_PROP_FPS);
Size size(
(int)capture.get(CV_CAP_PROP_FRAME_WIDTH),
(int)capture.get(CV_CAP_PROP_FRAME_HEIGHT)
);
VideoWriter writer;
writer.open("2.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, size);
Mat logpolar_frame, bgr_frame;
for (;;) {
capture >> bgr_frame;
if (bgr_frame.empty()) break; // end if done
imshow("Example 2-11", bgr_frame);
logPolar(bgr_frame, // Input color frame
logpolar_frame, // Output log-polar frame
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'
);
imshow("Log_Polar", logpolar_frame);
writer << logpolar_frame;
char c = cv::waitKey(10);
if (c == 27) break; // allow the user to break out
}
writer.release();
capture.release();
}
图像结果如图: