• 阅读数:211发布于2021-01-15 10:42:23

    只看该作者
    学习OpenCV--安装与初探(下) 复制本文链接

    2.初探
    1.显示图片
    我们在来看一下前面的哪个测试程序

    #include <iostream>
    #include<opencv2/opencv.hpp>
    int main()
    {
        cv::Mat img = cv::imread("Hakurei Reimu.png");//图片路径
        if (img.empty())return -1;
        cv::namedWindow("test", cv::WINDOW_AUTOSIZE);
        cv::imshow("test", img);
        cv::waitKey(0);
        cv::destroyWindow("test");
        return 0;
    }
    

    首先OpenCV的函数都位于命名空间cv下,如果想省略cv::,可以在前面用using namespace cv。但这样存在与其他命名空间冲突的风险。
    函数imread()根据文件名来决定图像格式的处理,也会自动申请图像需要的内存,它可以读取很多种图像格式,函数返回一个Mat结构,这个结构是OpenCV中你会接触的最多的自带结构,OpenCV用这个结构来处理所有类型的图像:单通道、多通道、整型、浮点数以及各种类型。
    函数namedWindow由HighGUi模块提供,将一个名称赋予窗口。第二个参数说明了Windows的特性。默认情况下全部设置为0,也可以设置为WINDOW_AUTOSIZE,这样窗口的大小会和载入图像的大小一致,图像会被缩放以使用窗口。
    通过imshow()来进行显示。imshow()将建一个窗口。(如果窗口不存在他会自动调用namedWindow()新建一个窗口)。调用imshow()时窗口将被重绘上要求的图片,并且窗口会自动调整大小(使用参数WINDOW_AUTOSIZE)。
    waitkey(0)函数告诉系统暂停并等待键盘事件。如果传入参数大于0则会意味着程序等待的毫秒数,比如waitkey(100)就是等待100毫秒,如果100毫秒没有键盘事件就会继续执行程序。0或负数表示等待无限长时间。
    最后用函数destroywindow()来让窗口自行销毁。
    2.显示视频

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    using namespace cv;
    int main(int argc, char** argv) {
        namedWindow("test", WINDOW_AUTOSIZE);
        VideoCapture cap;
        cap.open("灵梦.mp4");
        Mat frame;
        for (;;) {
        cap >> frame;
        if (frame.empty())break;
        imshow("test", frame);
        if (waitKey(33) >= 0)break;
       }
        return 0;
    }
    

    由于上面的程序无法在视频中进行跳转,所以我们需要添加一个滑动条来实现视频跳转。
    下面就是一个稍微复杂的程序

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include<iostream>
    #include<fstream>
    using namespace cv;
    using namespace std;
    int g_slider_position = 0;
    int g_run = 1, g_dontset = 0;
    VideoCapture g_cap;
    void onTrackbarSlide(int pos, void*) {
    g_cap.set(CAP_PROP_POS_FRAMES, pos);
    if (!g_dontset)
    g_run = 1;
    g_dontset = 0;
    }
    int main(int argc, char** argv) {
    namedWindow("test", WINDOW_AUTOSIZE);
    g_cap.open("灵梦.mp4");
    int frames = (int)g_cap.get(CAP_PROP_FRAME_COUNT);
    int tmpw = (int)g_cap.get(CAP_PROP_FRAME_WIDTH);
    int tmph = (int)g_cap.get(CAP_PROP_FRAME_HEIGHT);
    cout << "Video has " << frames << " frames of dimension (" << tmpw << " , " << tmph << " )." << endl;
    createTrackbar("Position", "test", &g_slider_position, frames, onTrackbarSlide);
    //不难发现传入的参数分别是 --> name(命名),窗口,事件类型,事件相关联的响应函数
    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", "test", current_pos);
    imshow("test", frame);
    g_run -= 1;
    }
    char c = (char)waitKey(10);
    if (c == 's') {
    g_run = 1;
    cout << "Single step,run= " << g_run << endl;
    }
    if (c == 'r') {
    g_run = -1;
    cout << "Run mode, run= " << g_run << endl;
    }
    if (c == 27)break;//ESC
    }
    return 0;
    }
    

    图片alt
    它允许用户按下s键来执行单步模式,按下r键恢复连续视频播放模式。然和时候都可以通过滑动条跳转到视频一个新的时间点,我们用单步模式在那个时间点播放。
    程序中用createTrackbar()来创建一个滑动条。这些代码理解起来没有太大困难。
    3.简单的变换
    接下来我们会对视频中的每一帧实现一些简单的操作。
    一个最简单的操作就是对图像的平滑处理,通过高斯核或者其他核卷积效减小图像的信息量。
    如下代码在第一个代码的基础上做了一下修改,得到两个窗口,一个显示原图,一个显示处理后的图(图像被5*5大小的高斯核模糊并且被写入out变量中)。高斯核的大小必须是奇数。程序执行了两次模糊操作

    #include <iostream>
    #include<opencv2/opencv.hpp>
    int main()
    {
        cv::namedWindow("in", cv::WINDOW_AUTOSIZE);
        cv::namedWindow("out", cv::WINDOW_AUTOSIZE);
        cv::Mat img = cv::imread("Hakurei Reimu.png");//图片路径
        if (img.empty())return -1;
        cv::imshow("in", img);
        cv::Mat out;
        cv::GaussianBlur(img, out, cv::Size(5, 5), 3, 3);
        cv::GaussianBlur(out, out, cv::Size(5, 5), 3, 3);
        cv::imshow("out", out);
        cv::waitKey(0);
        return 0;
    }
    

    图片alt
    4.不那么简单的变换
    这里我们先用pyrDown()来创建一个新的图像,其宽高均为原始图像的一半

    #include <iostream>
    #include<opencv2/opencv.hpp>
    int main()
    {
        cv::namedWindow("in", cv::WINDOW_AUTOSIZE);
        cv::namedWindow("out", cv::WINDOW_AUTOSIZE);
        cv::Mat img1 = cv::imread("Hakurei Reimu.png");//图片路径
        if (img1.empty())return -1;
        cv::Mat img2;
        cv::imshow("in", img1);
        cv::pyrDown(img1, img2);
        cv::imshow("out", img2);
        cv::waitKey(0);
        return 0;
    }
    

    图片alt
    下面我们用Canny边缘检测器输出一个单通道的(灰色)图像,其中边缘检测器通过cvtColor()函数生成一个和原图一样大小但只有一个通道的图像,从而将图像从BGR图像转换为灰度图,这个操作在OpenCV中定义为宏COLOR_BGR2GRAY。

    #include <iostream>
    #include<opencv2/opencv.hpp>
    int main()
    {
        cv::namedWindow("gray", cv::WINDOW_AUTOSIZE);
        cv::namedWindow("canny", cv::WINDOW_AUTOSIZE);
        cv::Mat img1 = cv::imread("Hakurei Reimu.png");//图片路径
        if (img1.empty())return -1;
        cv::Mat img_gry,img_cny;
        cv::cvtColor(img1, img_gry, cv::COLOR_BGR2GRAY);
        cv::imshow("gray", img_gry);
        cv::Canny(img_gry, img_cny, 10, 100, 3, true);
        cv::imshow("canny", img_cny);
        cv::waitKey(0);
        return 0;
    }
    

    图片alt
    这里我们可以将这些操作组合起来,比如对图像收缩两次再寻找其边缘。然后通过一个简单的方法来读取结果的像素值

    #include <iostream>
    #include<opencv2/opencv.hpp>
    int main()
    {
        cv::namedWindow("gray", cv::WINDOW_AUTOSIZE);
        cv::namedWindow("canny", cv::WINDOW_AUTOSIZE);
        cv::Mat img1 = cv::imread("Hakurei Reimu.png");//图片路径
        if (img1.empty())return -1;
        cv::Mat img_gry,img_cny,pyr,pyr2;
        cv::pyrDown(img1, pyr);
        cv::pyrDown(pyr, pyr2);
        cv::cvtColor(pyr2, img_gry, cv::COLOR_BGR2GRAY);
        cv::imshow("gray", img_gry);
        cv::Canny(img_gry, img_cny, 10, 100, 3, true);
        cv::imshow("canny", img_cny);
        int x = 16, y = 32;
        cv::Vec3b intensity = img1.at<cv::Vec3b>(y, x);
        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)pyr2.at<uchar>(y, x) << std::endl;
        img_cny.at<uchar>(x, y) = 128;
        cv::waitKey(0);
        return 0;
    }
    

    5.从摄像头中读取

    int main(int argc,char** argv)
    {
        cv::namedWindow("test", cv::WINDOW_AUTOSIZE);
        cv::VideoCapture cap;
        if (argc == 1) {
            cap.open(0);
        }
        else {
            cap.open(argv[1]);
        }
        if (!cap.isOpened()) {
            std::cerr << "could not open capture" << std::endl;
            return -1;
        }
        cv::waitKey(0);
        return 0;
    }
    

    同一个对象可以读取时评文件也可以连接摄像头。
    连接一个摄像头需要给它一个相机ID号(如果只有一个摄像头连接,这个ID通常为0),ID的默认值为-1,这意味着随意选择一个。
    6.写入AVI文件
    我们可以创建一个写入对象将帧一次输入到一个视频文件中,通过对象VideoWriter。完成后调用VideoWriter.release()方法。
    下面的这个程序会打开一个视频文件读取它的内容后将其转换为对数极坐标形式,然后将这种形式写入一个新的视频文件。

    #include<opencv2/opencv.hpp>
    #include<iostream>
    int main(int argc, char** argv) {
        cv::namedWindow("test", cv::WINDOW_AUTOSIZE);
        cv::namedWindow("log", cv::WINDOW_AUTOSIZE);
        cv::VideoCapture cap("灵梦.mp4");
        double fps = cap.get(cv::CAP_PROP_FPS);
        cv::Size size(
        (int)cap.get(cv::CAP_PROP_FRAME_WIDTH),
        (int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));
        cv::VideoWriter writer;
        writer.open("leimo.mp4", CV_FOURCC('M', 'J', 'P', 'G'), fps, size);
        cv::Mat log, bgr;
        for (;;) {
            cap >> bgr;
            if (bgr.empty())break;
            cv::imshow("test", bgr);
            cv::logPolar(bgr, log, cv::Point2f(bgr.cols / 2, bgr.rows / 2), 40, cv::WARP_FILL_OUTLIERS);
            cv::imshow("log", log);
            writer << log;
            char c = cv::waitKey(10);
            if (c == 27)break;
      }
        cap.release();
    }
    

    回复 (1)

    举报
举报

请选择举报理由

  • 垃圾广告
  • 违规内容
  • 恶意灌水
  • 重复发帖
提示

奥比中光 · 3D视觉开发者社区...

站长统计