1、显示图片
opencv提供了一些实用工具来读取从视频流到摄像机画面的各式各样的图像格式,
这些工具都是HighGUI的一部分。
而opencv的函数都位于cv这一命名空间下,所以在用opencv函数的时候,需要在函数前面加上cv::,意思就是告诉编译器自己所使用的函数处于cv命名空间下。
在写代码的时候可以只使用必要的头文件以节省编译时间。
#include<opencv2/highgui/highgui.hpp>
//using namespace cv;
int main(int argc,char** argv)
{
cv::Mat img = cv::imread("D:/图片/图2/IU1.jpg", -1); /*imread()可以根据文件名决定载入图像的格式,会自动申请图像需要的内存 它会返回一个Mat结构,opencv用这个结构所有类型的图像,单、多通道、整型等等*/
if (img.empty()) //检查图像是否真的被载入了
return -1;
cv::namedWindow("example", cv::WINDOW_AUTOSIZE); /*这个函数由HighGUI模块提供,它将一个名称赋给窗口第二个参数可以设置为0*/
cv::imshow("example", img); //将图像重绘到窗口上,若使用cv::WINDOW_AUTOSIZE这个参数,窗口会自动调整大小
cv::waitKey(0); /*函数告诉系统暂停,等待键盘事件,若参数大于0,则等待此数值的毫秒时间;若为0,程序会无限等待直到有按键按下*/
cv::destroyWindow("example");//自行销毁窗口,释放掉相关联的内存空间
return 0;
}
2、读取视频
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main(int argc,char** argv)
{
namedWindow("example2", WINDOW_AUTOSIZE);
VideoCapture cap; //视频读取结构
cap.open("D:\\我的视频\\周冬雨.mp4");
Mat frame; //声明一个可以保存视频帧的结构
for (;;)
{
cap >> frame; //视频文件会按照帧从视频流中被读取
if (frame.empty()) break;
imshow("example2", frame);
if (waitKey(33) >= 0) break;
}
return 0;
}
3、添加滑动条的基本浏览窗口
/*添加一个滑动条,让视频可以跳转。允许用户按下S键执行单步模式,R键执行视频连续播放模式。无论何时通过滑动条跳转到视频一个
新的时间点,都会使用单步模式在那个时间点播放*/
/*HighGUI这个模块提供了很多简单的工具处理视频和图像,包括要用到的滑动条。要创建一个滑动条要用到creatTrackbar()函数,
并且指明要在哪个窗口中显示。为了完成所需功能,还需要一个回调函数*/
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
#include<fstream>
using namespace std;
using namespace cv;
//用g_表示全局变量
int g_slider_position = 0; //存储滑动条的位置
int g_run = 1, g_dontset = 0; /*g_run会在新的跳转之后置0,为正,指示程序停止之前要播放多少张图片,为负,表示程序处于连续播放模式。在滑动条跳转到一个新位置的时候让g_run置1使视频进入单步模式。但会存在问题。为了避免调整进度条时进入单步模式引入变量g_dontset*/
VideoCapture g_cap; //回调函数需要用到帧读取结构
//回调程序。它会传入一个32位的整型数值表示当前位置,这将会是进度条存在的新的位置
void onTrackbarSlide(int pos, void*)
{
g_cap.set(CAP_PROP_POS_FRAMES, pos); /*通过g_cap.set()使滑动条移到我们希望的位置,第一个参数指示我们想要帧集合的读取位置*/
if (!g_dontset) g_run = 1;
g_dontset = 0;
}
int main(int argc,char** argv)
{
namedWindow("example", WINDOW_AUTOSIZE);
g_cap.open("D:\\我的视频\\周冬雨.mp4");
int frames = (int)g_cap.get(CAP_PROP_FRAME_COUNT); /*确定视频总帧数以及宽高*/
int tempw = (int)g_cap.get(CAP_PROP_FRAME_WIDTH);
int temph = (int)g_cap.get(CAP_PROP_FRAME_HEIGHT);
cout << "video has " << frames <<"帧."<<" frames of dimensions(" << tempw << "," << temph << ")." << endl;
createTrackbar("Position", "example", &g_slider_position, frames, onTrackbarSlide);
Mat frame;
for (;;)
{
if (g_run != 0)
{
g_cap >> frame;
if (frame.empty()) break;
int current_pos = (int)g_cap.get(CAP_PROP_POS_FRAMES);
g_dontset = 1;
setTrackbarPos("Position", "example", current_pos); //在特定窗口,特定跟踪条下建立标签
imshow("example", frame);
g_run -= 1;
}
char c = (char)waitKey(10); //等待键入,根据键入调整视频播放情况
if (c == 's')
{
g_run = 1;
cout << "single sept,run = " << g_run << endl;
}
if (c == 'r')
{
g_run = -1;
cout << "run mode,ren = " << g_run << endl;
}
if (c == 27) break;
}
return 0;
}
4、简单的图像变换
#include<opencv2/opencv.hpp>
using namespace cv;
void example1(Mat & img)
{
namedWindow("in", WINDOW_AUTOSIZE);
namedWindow("out", WINDOW_AUTOSIZE);
imshow("in", img);
Mat out;
GaussianBlur(img, out, Size(5, 5), 3, 3); //输入图像被5x5大小的高斯核模糊并写入out中
GaussianBlur(out, out, Size(5, 5), 3, 3); //再次调用使,out被分配了临时存储空间,因此可以作为输入与输出
imshow("out", out); //显示被两次模糊的图像
waitKey(0);
}
int main(int argc, char** argv)
{
Mat img = imread("D:/图片/图2/IU1.jpg");
example1(img);
return(0);
}
5、不那么简单的变换
1)、使用pyrDown()创建一个宽高为原图像一半的新图像
#include<opencv2/opencv.hpp>
using namespace cv;
//opencv中高斯模糊以及降采样可以用pyrDown()来实现
int main(int argc, char** argv)
{
Mat img1, img2;
namedWindow("ex1", WINDOW_AUTOSIZE);
namedWindow("ex2", WINDOW_AUTOSIZE);
img1 = imread("D:/图片/图2/IU1.jpg");
imshow("ex1", img1);
pyrDown(img1, img2); //使用pyrDown()创建一个宽高为原图像一半的新图像
imshow("ex2", img2);
waitKey(0);
return(0);
}
2)、canny边缘检测器输出一个单通道灰度图
#include<opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char** argv)
{
Mat rgb, gry, cny;
namedWindow("ex1", WINDOW_AUTOSIZE);
namedWindow("ex2", WINDOW_AUTOSIZE);
rgb = imread("D:/图片/图2/IU1.jpg");
cvtColor(rgb, gry, COLOR_BGR2GRAY); //转灰度图(三通道转单通道)
imshow("ex1",gry);
Canny(gry, cny, 10, 100, 3, true); //边缘检测
imshow("ex2", cny);
waitKey(0);
return(0);
}
3)、两次收缩图片并读取像素值
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat rgb, gry,pyr,pyr1, cny;
namedWindow("ex1", WINDOW_AUTOSIZE);
namedWindow("ex2", WINDOW_AUTOSIZE);
rgb = imread("D:/图片/图2/IU1.jpg");
cvtColor(rgb, gry, COLOR_BGR2GRAY); //转灰度图(三通道转单通道)
pyrDown(gry, pyr);
pyrDown(pyr, pyr1);
imshow("ex1",pyr1);
Canny(pyr1, cny, 10, 100, 3, true); //边缘检测
imshow("ex2", cny);
//读取像素
int x = 16, y = 32;
Vec3b intensity = rgb.at<Vec3b>(y, x);
uchar b = intensity[0];
uchar g = intensity[1];
uchar r = intensity[2];
cout << "At (x,y) = (" << x << "," << y << "):(b,g,r) = (" << (unsigned int)b << "," << (unsigned int)g << "," << (unsigned int)r << ")" << endl;
x /= 4;
y /= 4;
cout << "pyramid2 pixel there is " << (unsigned int)pyr1.at<uchar>(y, x) << endl;
cny.at<uchar>(x, y) = 128;
waitKey(0);
return(0);
}
6、使用cv::VideoWriter()记录一个输入流或者完全不同的图像到视频流中。
读取彩色视频并转换为 对数极坐标 视频。(对数极坐标log-polar 类似于人眼真正捕捉到的图像格式)
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
//Mat argv = imread("D:\\我的视频\\济南一中.mp4");
int main(int argc, char** argv[])
{
namedWindow("ex1", WINDOW_AUTOSIZE);
namedWindow("ex2", WINDOW_AUTOSIZE);
VideoCapture cap("D:/我的视频/周冬雨.mp4");
double fps = cap.get(CAP_PROP_FPS);
Size size(cap.get(CAP_PROP_FRAME_WIDTH), cap.get(CAP_PROP_FRAME_HEIGHT));
VideoWriter writer;/*第一个参数是新建视频文件的文件名。第二个参数是视频编码方式,指明视频是以何种方式压缩。下面使用通用的MJPG编码器。第三第四参数分别是图像帧率以及大小*/
writer.open("D:\\我的视频\\周冬雨.avi", CV_FOURCC('M', 'J', 'P', 'G'), fps, size);
Mat log_frame, bgr_frame;
for (;;)
{
cap >> bgr_frame;
if (bgr_frame.empty()) break;
imshow("ex1", bgr_frame);
logPolar(bgr_frame, log_frame, Point2f(bgr_frame.cols/2, bgr_frame.rows/2), //变换中心
40,//比例因子
WARP_FILL_OUTLIERS //用零填充异常值
);
imshow("ex2", log_frame);
writer << log_frame;
char c = waitKey(10);
if (c == 27) break;
}
cap.release();
return(0);
}
效果图: