java opencv bytearray转mat_【2】OpenCV核心模块(4)图像操作

9731ce12311d9294e9fbf9535c6a0ee3.png

本节内容是OpenCV中的一些图像的操作,内容上与前面有重复。但是tutorials有这个文档,所以还是再梳理一遍吧。原文有C++、Java、Python三种代码示例,这里只说明C++部分。

  • 原文网址Operations with images
  • 本地目录D:opencvsourcesdoctutorialscore
  • 代码目录D:opencvsourcessamplescpptutorial_codecoremat_operations
  • GitHub 有相应文档和OpenCV源代码
  • 版本OpenCV4.1.2(版本兼容性见英文原文,部分文档适用于OpenCV2.0和3.0)
  • 环境Windows、C++、VS2019 Community

输入/输出

从文件中读取图像:

Mat 

如果读取一个jpg图片,默认是三个通道。如果想读取为灰度图像,用下面方法:

Mat img = imread(filename, IMREAD_GRAYSCALE);

保存图像到文件:

imwrite(filename, img);

图像文件格式由扩展名决定。另外imdecode和imencode函数是读取和写入到内存,而不是文件。

图像的基本操作

获取像素的灰度值Accessing pixel intensity values

为了获取图像灰度值,需要知道图像的数据类型和通道数。

下面是单通道灰度图像(8UC1)和像素坐标(x,y):

Scalar intensity = img.at<uchar>(y, x);//注意是行、列坐标

其中,intensity.val[0]就是该点的灰度值,取值范围是0到255。需要注意x和y的顺序,是从0开始的列索引(column对应x坐标)还是行索引(row对应y坐标)。也可以用下面的:

Scalar intensity = img.at<uchar>(Point(x, y));//注意是点(x,y)

下面,考虑3通道的BGR图像

Vec3b intensity = img.at<Vec3b>(y, x);//注意是点的行、列位置
uchar blue = intensity.val[0];//蓝色分量
uchar green = intensity.val[1];//绿色分量
uchar red = intensity.val[2];//红色分量

浮点图像,像素的数据类型是float,不是前面的uchar。(例如,三个通道进行sobel运算得到的结果就是float型的图像)

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

上面的方法也可用于改变像素值,如:

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

OpenCV的某些函数,尤其是calib3d模块中,如cv::projectPoints,会使用2D和3D点组成Mat数据。这些点存储为一列,每行只对应一个点。矩阵类型分别对应32FC2或32FC3。这样的矩阵可以用std::vector来构造。

vector<Point2f> points;
 //...对points数组进行赋值,如points.push(Point2f(x,y))等等
Mat pointsMat = Mat(points);//生成Mat类型数据,这里是2通道

Point2f point = pointsMat.at<Point2f>(i, 0);//访问Mat中第i个点

内存管理与参考计数Memory Management and reference counting

前面讲过Mat数据类型,Mat由包含矩阵或者图像的参数(行数、列数、数据类型等)和一个指向数据的指针构成。所以对应同一个数据,我们可以创建多个Mat对象。 Mat用引用计数的方法来表明当一个Mat对象销毁时,数据是否必须释放。下面是不用拷贝数据,创建两个矩阵的例子:

        std::vector<Point3f> points;
        // .. 填充数组
        Mat pointsMat = Mat(points).reshape(1);//reshap将通道变为1
       //先将points转换为32FC3的Mat,再reshape为32FC1的pointsMat 

最后,我们得到了一个32FC1的3列矩阵,取代了32FC3的1列矩阵。当pointsMat 使用来自points的数据,并且pointsMat销毁时不会释放内存。在这种特殊情况下,points的使用寿命必须必pointsMat长才行。如果需要拷贝数据,用下面的方法。cv::Mat::copyTo 或者cv::Mat::clone。

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

提供给一个函数空的Mat对象作为输出,函数内部会调用Mat::create,为该矩阵分配数据内存。如果非空,Mat对象大小和数据类型正确,则什么也不做。如果大小或数据类型不同于输入参数,矩阵数据会释放并且分配新的数据。如下:

        Mat img = imread("image.jpg");
        Mat sobelx;
        Sobel(img, sobelx, CV_32F, 1, 0);//函数执行,并为sobelx分配内存

一些基本操作 Primitive operations

有一些很方便的定义矩阵的方式。例如,下面是由一副灰度图像img创建一副黑色图像

            img = Scalar(0);//所有元素赋值为0

选择感兴趣区域:

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

彩色转换为灰度:

Mat img = imread("image.jpg"); // 加载8UC3图像
Mat grey;  
cvtColor(img, grey, COLOR_BGR2GRAY); 

图像类型从8UC1到32FC1:

src.convertTo(dst, CV_32F);

显示图像 Visualizing images

在调试程序过程中可以显示图像。显示8U图像:

        Mat img = imread("image.jpg");
        namedWindow("image", WINDOW_AUTOSIZE);//如果不改变窗口属性,可以不写该行
        imshow("image", img);
        waitKey();

32F图像需要转换为8U类型才能显示:

        Mat img = imread("image.jpg");
        Mat grey;
        cvtColor(img, grey, COLOR_BGR2GRAY);
        Mat sobelx;
        Sobel(grey, sobelx, CV_32F, 1, 0);//Soble结果为32F图像
        double minVal, maxVal;
        minMaxLoc(sobelx, &minVal, &maxVal); //找到最小和最大值
        Mat draw;
        //sobelx图像灰度拉伸,并转换为8U显示
        sobelx.convertTo(draw, CV_8U, 255.0/(maxVal - minVal), -minVal * 255.0/(maxVal - minVal));
        namedWindow("image", WINDOW_AUTOSIZE);
        imshow("image", draw);
        waitKey();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值