OpenCV4.9的是如何进行图像操作(29)

79 篇文章 0 订阅
78 篇文章 0 订阅

返回:OpenCV系列文章目录(持续更新中......)

上一篇:OpenCV4.9矩阵上的掩码操作(28)

下一篇:使用 OpenCV 添加(混合)两个图像(30) 

输入/输出

C++

图像

从文件加载图像

 Mat img = imread(filename);

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

 Mat img = imread(filename, IMREAD_GRAYSCALE);

注意

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

 imwrite(filename, img);

Java

从文件加载图像

Mat img = Imgcodecs.imread(filename);

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

Mat img = Imgcodecs.imread(filename, Imgcodecs.IMREAD_GRAYSCALE);

 注意

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

 Imgcodecs.imwrite(filename, img);

  Python

从文件加载图像

 img = cv.imread(filename)

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

 img = cv.imread(filename, cv.IMREAD_GRAYSCALE)

注意

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

 cv.imwrite(filename, img)

Note

Format of the file is determined by its extension.

Use cv::imdecode and cv::imencode to read and write an image from/to memory rather than a file.

图像的基本操作

访问像素强度值

为了获得像素强度值,您必须知道图像的类型和通道数。以下是单通道灰度图像(类型 8UC1)和像素坐标 x 和 y 的示例:

C++:

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

Java:

 byte[] imgData = new byte[(int) (img.total() * img.channels())];
 img.get(0, 0, imgData);
 byte intensity = imgData[y * img.cols() + x];

 Python

 _intensity = img[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 返回的默认格式):

C++ code

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

Python Python

 _blue = img[y,x,0]
 _green = img[y,x,1]
 _red = img[y,x,2]

您可以对浮点图像使用相同的方法(例如,您可以通过在 3 通道图像上运行 Sobel 来获取此类图像)(仅限 C++):

 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;

Java: 

 byte[] imgData = new byte[(int) (img.total() * img.channels())];
 imgData[y * img.cols() + x] = (byte) 128;
 img.put(0, 0, imgData);

 Python:

 img[y,x] = 128

OpenCV 中有一些函数,尤其是来自 calib3d 模块的函数,例如 cv::p rojectPoints,它们以 Mat 的形式采用 2D 或 3D 点数组。 矩阵应该只包含一列,每行对应一个点,矩阵类型应该相应为 32FC2 或 32FC3。这样的矩阵可以很容易地从(仅限 C++ )构造:std::vector

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

可以使用相同的方法(仅限 C++)访问此矩阵中的点:Mat::at

 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使用来自点的数据,并且在销毁时不会释放内存。但是,在这种特定情况下,开发人员必须确保points的生存期长于pointsMat如果我们需要复制数据,则可以使用例如, cv::Mat::copyTo or cv::Mat::clone:

 img = cv.imread('image.jpg')
 _img1 = np.copy(img)

可以为每个功能提供一个空的输出垫。每个实现都为目标矩阵调用 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 

参考文献:

1、《Operations with images》

  • 34
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚梦者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值