文章目录
第二十九周学习笔记
本周主要学习opencv的一些内容
代码在这
图片读取和显示
图片以矩阵形式存储在cv::Mat
中,cv::Mat会根据图片自动分配内存,同时也会自动释放内存
函数和参数
cv::imread("path_to_img")
,读取图片,返回cv::Mat
cv::Mat.empty()
,判断图片是否读取成功,失败则返回truecv::namedWindow("name_of_window")
,用来显示图片的窗口cv::imshow("name_of_window",img)
,将图片img
显示在对应窗口上cv::waitKey(0)
暂停程序,防止程序结束后图片窗口自动销毁cv::destroyWindow("name_of_window")
,手动销毁窗口
示例
#include <opencv2/highgui/highgui.hpp>
int main() {
cv::Mat img = cv::imread("1.jpg");
if (img.empty())
return -1;
cv::namedWindow("Window");
cv::imshow("Window", img);
cv::waitKey(0);
cv::destroyWindow("Window");
return 0;
}
编译命令
g++ -o main Ex2_1Display.cpp -lopencv_core -lopencv_highgui -lopencv_imgcodecs
视频读取和显示
OpenCV中,视频的显示是通过连续的图片显示实现的,OpenCV先使用cv::VideoCapture
读取视频文件,然后将视频的每一帧输入到cv::Mat
中,再连续地显示这些图像,从而实现视频播放
函数和参数
cv::VideoCapture.open("path_to_video")
,读取视频文件cv::VideoCapture >> frame
,输入下一帧到frame
中
示例
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
int main() {
cv::namedWindow("Window1", cv::WINDOW_AUTOSIZE);
cv::VideoCapture cap;
cap.open("1.mp4");
cv::Mat frame;
for (;;) {
cap >> frame;
if (frame.empty())
break;
cv::imshow("Window1", frame);
if (cv::waitKey(33) >= 0) // 这个数字控制了视频的播放速度,也就是两帧之间的间隔,按任意键结束播放
break;
}
}
编译
g++ Ex2_3Video.cpp -o main -lopencv_core -lopencv_highgui -lopencv_imgcodecs -lopencv_videoio -lopencv_video -lopencv_videostab -lopencv_imgproc
视频进度跳转
可以在视频上加一条进度条实现播放进度的控制
函数和参数
cv::createTrackbar("name_of_trackbar", "name_of_window", slider_position, max_value, onTrackbarSlide)
五个参数分别为,trackbar名,窗口名,滑块初始位置,最大值,滑动时的响应函数cv::VideoCapture.set(cv::CAP_PROP_POS_FRAMES, pos)
,设置下一帧读取的位置
示例
#include <opencv4/opencv2/highgui/highgui.hpp>
#include <opencv4/opencv2/imgproc/imgproc.hpp>
using namespace std;
cv::VideoCapture g_cap;
void onTrackbarSlide(int pos, void *) {
g_cap.set(cv::CAP_PROP_POS_FRAMES, pos); //????
}
int main() {
cv::namedWindow("Window1", cv::WINDOW_AUTOSIZE);
g_cap.open("1.mp4");
int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);
cv::createTrackbar("Position", "Window1", 0, frames, onTrackbarSlide);
cv::Mat frame;
for (;;) {
g_cap >> frame;
if (frame.empty())
break;
int current_pos = (int)g_cap.get(cv::CAP_PROP_POS_FRAMES);
cv::setTrackbarPos("Position", "Window1",
current_pos); // 保证进度条的位置和播放进度一致
cv::imshow("Window1", frame);
if (cv::waitKey(33) > 0) {
break;
}
}
return (0);
}
图像变换
- 高斯模糊
cv::GaussianBlur(image, out, cv::Size(5, 5), 3, 3);
- 下采样
cv::pyrDown(in, out);
- BGR2GRAY
cv::cvtColor(img_rgb, img_gry, cv::COLOR_BGR2GRAY);
- Canny边缘提取
cv::Canny(img_gry, img_cny, 10, 100, 3, true);
像素取值和赋值
示例
#include <iostream>
#include <opencv2/opencv.hpp>
int main() {
cv::Mat img = cv::imread("1.jpg");
int x = 16;
int y = 32;
cv::Vec3b intensity = img.at<cv::Vec3b>(y, x);
uchar blue = intensity[0];
uchar green = intensity[1];
uchar red = intensity[2];
std::cout << "----------Before----------" << std::endl;
std::cout << "At (x, y) = (" << x << ", " << y << "): (blue, green, red) = ("
<< (unsigned int)blue << ", " << (unsigned int)green << ", "
<< (unsigned int)red << ")" << std::endl;
img.at<cv::Vec3b>(y, x) = {0, 0, 0};
cv::Vec3b intensity2 = img.at<cv::Vec3b>(y, x);
uchar blue2 = intensity2[0];
uchar green2 = intensity2[1];
uchar red2 = intensity2[2];
std::cout << "----------After----------" << std::endl;
std::cout << "At (x, y) = (" << x << ", " << y << "): (blue, green, red) = ("
<< (unsigned int)blue2 << ", " << (unsigned int)green2 << ", "
<< (unsigned int)red2 << ")" << std::endl;
}
输出视频
与读取视频恰相反的过程
函数和参数
cv::VideoWriter.open(1,2,3,4)
打开一个空的视频,四个参数分别为,文件名,视频编解码器,fps,每帧的Size
示例
#include <opencv4/opencv2/opencv.hpp>
int main() {
cv::VideoCapture cap("1.mp4");
cv::VideoWriter writer;
cv::Size size(cap.get(cv::CAP_PROP_FRAME_WIDTH),
cap.get(cv::CAP_PROP_FRAME_HEIGHT));
writer.open("out.mp4", cv::VideoWriter::fourcc('M', 'J', 'P', 'G'),
cap.get(cv::CAP_PROP_FPS), size);
cv::Mat frame;
for(;;){
cap >> frame;
if(frame.empty())break;
writer << frame;
}
writer.release();
}
cv::waitKey的用法小结
cv::waitKey(int num)
cv::waitKey
暂时中断程序
- num小于等于0,等待键入后程序继续
- num大于0,等待键入或者num毫秒后程序继续
场景1:显示图片
#include <opencv2/highgui/highgui.hpp>
int main() {
cv::Mat img = cv::imread("1.jpg");
if (img.empty())
return -1;
cv::namedWindow("Window");
cv::imshow("Window", img);
cv::waitKey(0); // 在此停下,防止程序直接结束,显示图片的窗口自动关闭
cv::destroyWindow("Window");
return 0;
}
场景2:控制视频播放时间
在播放视频时,cv::waitKey
的参数控制了两帧之间的播放间隔(毫秒),可以通过计算得到每帧占多少毫秒来实现视频的原速播放
#include <iostream>
#include <opencv4/opencv2/opencv.hpp>
using namespace std;
int main() {
cv::VideoCapture cap("1.mp4");
cv::Mat frame;
cv::namedWindow("Window1");
double fps = cap.get(cv::CAP_PROP_FPS);
cout << fps;
for (;;) {
cap >> frame;
if (frame.empty())
break;
cv::imshow("Window1", frame);
if (cv::waitKey(1000/fps) >= 0) { // 等待的时间即是两帧之间的间隔
break;
}
}
}
场景3:等待键入,并执行相应操作
...
char c = (char)cv::waitKey(10); // 好像不写(char)也行
if (c == 's') {
cout << "input s" << endl;
}
if (c == 'r') {
cout << "input r" << endl;
}
if (c == 27) { // Esc
cout << "input esc" << endl;
}
...
一些属性
cv::VideoCapture cap("1.mp4");
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); \\ 高
double fps = cap.get(cv::CAP_PROP_FPS); \\ fps
注意事项
- opencv代码的编译样例
g++ Ex2_1Display.cpp -o main -lopencv_core -lopencv_highgui -lopencv_imgcodecs -lopencv_videoio -lopencv_video -lopencv_videostab -lopencv_imgproc
- fps用double类型读取
cv::VideoCapture cap("1.mp4");
double fps = cap.get(cv::CAP_PROP_FPS);
- 建议手动输入命名空间
cv::
- 头文件
opencv2/opencv.hpp
可以导入所有的OpenCV模块,也可以仅仅导入需要的模块来减少编译的时间 - 在大的程序中,需要手动调用
cv::destroyWindow(Windowname)
,防止内存泄露 - 程序中图片的相对目录使用的是相对编译位置的相对目录
- namedWindow的默认
size=cv::WINDOW_AUTOSIZE
下周目标
同时学习opencv和CS231n,并完成上周报告中问题的回答和额外资料的阅读