对图片的操作

英文原文链接:Operations with images

输入/输出

从文件加载一个图像:

        Mat img = imread(filename);

如果你读取一个jpg文件,默认情况下会创建一个3通道的图像。如果你需要一个灰度图像,使用:

Mat img = imread(filename, IMREAD_GRAYSCALE);

文件的格式由它的内容(前几个字节)决定。保存一个图像到一个文件:

imwrite(filename, img);

文件的格式由其扩展名决定。
使用cv::imdecodecv::imencode 读取/写入 图像 从/到 内存,而不是一个文件。

图像的基本操作

为了得到像素强度值,你必须知道图像的类型和通道的数量。下面是一个单通道灰度图像(类型8UC1)和像素坐标x和y的例子:

Scalar intensity = img.at<uchar>(y, x);

只适用于c++版本: intensity.val[0]包含一个从0到255的值。注意x和y的顺序,因为在OpenCV图像中使用与矩阵相同的结构来表示,所以我们对这两种情况使用相同的约定——基于0的行索引(或y坐标)在前面,基于0的列索引(或x坐标)在后面。或者,你可以使用以下符号(仅c++):

            Scalar intensity = img.at<uchar>(Point(x, y));

现在让我们考虑一个BGR颜色顺序的3通道图像(imread返回的默认格式):

            Vec3b intensity = img.at<Vec3b>(y, x);
            uchar blue = intensity.val[0];
            uchar green = intensity.val[1];
            uchar red = intensity.val[2];

你可以对浮点图像使用相同的方法(例如,你可以在一个3通道图像上运行Sobel得到这样的图像)(c++ only):

            Vec3f intensity = img.at<Vec3f>(y, x);
            float blue = intensity.val[0];
            float green = intensity.val[1];
            float red = intensity.val[2];

同样的方法可以用来改变像素强度:

           img.at<uchar>(y, x) = 128;

在OpenCV中,特别是calib3d模块中,有一些函数,比如cv::projectPoints,以Mat的形式取一个二维或三维点数组,矩阵只包含一列,每一行对应一个点,对应的矩阵类型为32FC2或32FC3。这样的矩阵可以很容易地由std::vector (c++ only)构造:

            vector<Point2f> points;
            //... fill the array
            Mat pointsMat = Mat(points);

一个可以访问这个矩阵中的一个点使用相同的方法Mat::at (c++ only):

            Point2f point = pointsMat.at<Point2f>(i, 0);

内存管理和引用计数

Mat是一种保持矩阵/图像特征(行和列数,数据类型等)和数据指针的结构。因此,没有什么能阻止我们拥有几个Mat实例来对应相同的数据。Mat保留一个引用计数,它告诉我们当特定的Mat实例被销毁时,是否需要释放数据。下面是一个创建两个矩阵而不复制数据的例子(仅c++):

        std::vector<Point3f> points;
        // .. fill the array
        Mat pointsMat = Mat(points).reshape(1);

结果,我们得到了一个3列的32FC1矩阵,而不是一个1列的32FC3矩阵。pointsMat使用来自点的数据,并且在被销毁时不会释放内存。然而,在这个特定的实例中,开发人员必须确保点的生命周期长于pointsMat。如果我们需要复制数据,可以使用例如cv::Mat::copyTocv::Mat::clone来完成

        Mat img = imread("image.jpg");
        Mat img1 = img.clone();

可以为每个函数提供一个空的输出 Mat 。每个实现都为目标矩阵调用Mat::create。如果一个矩阵是空的,此方法将为该矩阵分配数据。如果它不是空的,并且具有正确的大小和类型,则该方法不执行任何操作。但是,如果大小或类型与输入参数不同,就会释放(并丢失)数据,并分配新数据。例如:

        Mat img = imread("image.jpg");
        Mat sobelx;
        Sobel(img, sobelx, CV_32F, 1, 0);

基本操作

在一个矩阵上定义了许多方便的算子。例如,下面是我们如何从现有的灰度图像img中创建一个黑色图像

            img = Scalar(0);

选择感兴趣的区域:

            Rect r(10, 10, 100, 100);
            Mat smallImg = img(r);

从彩色到灰度的转换:

        Mat img = imread("image.jpg"); // loading a 8UC3 image
        Mat grey;
        cvtColor(img, grey, COLOR_BGR2GRAY);

图像类型由8UC1改为32FC1:

        src.convertTo(dst, CV_32F);

可视化图像

在开发过程中查看算法的中间结果非常有用。OpenCV提供了一种方便的图像可视化方法。一个8U图像可以显示使用:

        Mat img = imread("image.jpg");
        namedWindow("image", WINDOW_AUTOSIZE);
        imshow("image", img);
        waitKey();

调用waitKey()将启动一个消息传递周期,等待在“image”窗口中按下按键。一个32F的图像需要转换成8U型例如:

        Mat img = imread("image.jpg");
        Mat grey;
        cvtColor(img, grey, COLOR_BGR2GRAY);
        Mat sobelx;
        Sobel(grey, sobelx, CV_32F, 1, 0);
        double minVal, maxVal;
        minMaxLoc(sobelx, &minVal, &maxVal); //find minimum and maximum intensities
        Mat draw;
        sobelx.convertTo(draw, CV_8U, 255.0/(maxVal - minVal), -minVal * 255.0/(maxVal - minVal));
        namedWindow("image", WINDOW_AUTOSIZE);
        imshow("image", draw);
        waitKey();

这里cv::namedWindow可以不要,因为它后面紧跟着cv::imshow。然而,它可以用来改变窗口属性或当使用cv::createTrackbar时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值