Opencv 基本操作四 指针数组、vector与Mat之间的相互转换 | Mat切片成Vector<mat>并还原

这篇具有很好参考价值的文章主要介绍了Opencv 基本操作四 指针数组、vector与Mat之间的相互转换 | Mat切片成Vector<mat>并还原。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在深度学习模型部署中通常存在读取图像为mat,然后将mat转换为float指针传入模型的操作。为了快捷开发,因此对指针数组、vector与Mat之间的相互转换进行整理。实现了指针数组、vector之间的相互转换;vector与Mat之间的相互转换(含单通道图像和多通道图像)。vector转mat主要应用在语义分割结果的处理中。

1、指针数组与vector之间的相互转换

这里强调一下为什么使用vector而不使用指针数组,因为使用vector可以更为方便的操作数据,就比如说数据的拷贝,裁剪、拼接等。就比如,博主的代码实现了vector的加法重载,可以便捷的实现vector的拼接。

指针转vector

std::vector vp(p, p + 1000);,其中p为指针的名称,1000为指针的数据长度

vector转指针

int* p2 = vp.data();//浅拷贝(p2与vp共用同一片内存区域)

//重载vector的运算符
template <typename T>
vector<T>& operator +(vector<T>& v1, vector<T>& v2)
{
	v1.insert(v1.end(), v2.begin(), v2.end());
	return v1;
}

//指针数组转vector
int* p = new int[100];//空间分配方式一
p = (int*)malloc(1000*sizeof(p));//空间分配方式二:malloc赋值方式
p[0] = -1;

std::vector<int> vp(p, p + 1000);//深拷贝(把起始地址到结束地址的值拷贝一遍)
vp[1] = 222;
//-------实现vector的拼接--------
std::vector<int> vp2 = vp + vp;
//vecort转指针数组
int* p2 = vp.data();//浅拷贝(p2与vp共用同一片内存区域)
p2[2] = 3333;
std::cout << "int* p: " << p[0] << ", " << p[1] <<", " << p[2] << std::endl;
std::cout << "vector vp: " << vp[0] << ", " << vp[1] << ", " << vp[2] << std::endl;
std::cout << "int* p2: " << p2[0] << ", " << p2[1] << ", " << p2[2] << std::endl;

在指针与数组的相互转换过程中需要注意的是内存空间的变化,指针转vector后数据被拷贝了一次,而vector转指针后数据并没有被拷贝。具体可以见上述代码的输出,改变vp不会影响p,而改变p2会影响vp
Opencv 基本操作四 指针数组、vector与Mat之间的相互转换 | Mat切片成Vector<mat>并还原

vector的类型转换

有的时候需要转换vector的数据类型,可以使用以下方法

std::vector<int64> output_data0;//对应seg结果  argmax后为int64
std::vector<uchar> int2uchar(output_data0.begin(), output_data0.end());

2、mat转vector

通常来说mat转vector是十分便捷的,仅需要一个reshape操作即可,reshape(int cn, int rows)表示把数据的通道变为cn,行数变为rows。具体如下所示,下面代码表示把单通道mat转换为vector。

std::vector<float> vec = mat.reshape(1, 1);

然而,对于三通道的mat转换略为麻烦,需要将多通道split为三个单通道才行,具体实现的转换函数如下所示。

std::vector<float> mat2vector(cv::Mat img, cv::Size2d size = {512,512}) {
	cv::resize(img, img, size);
	cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
	img.convertTo(img, CV_32FC3);
	//数据归一化
	img = img / 255.0;
	//将rgb数据分离为单通道
	std::vector<cv::Mat> mv;
	cv::split(img, mv);
	std::vector<float> R = mv[0].reshape(1, 1);
	std::vector<float> G = mv[1].reshape(1, 1);
	std::vector<float> B = mv[2].reshape(1, 1);
	//RGB数据合并
	std::vector<float> input_data;
	input_data.insert(input_data.end(), R.begin(), R.end());
	input_data.insert(input_data.end(), G.begin(), G.end());
	input_data.insert(input_data.end(), B.begin(), B.end());
	return input_data;
}

3、vector转mat

在深度学习部署场景中,vector转mat分三种情况,情况一:uchar形式的vector转单通道mat;情况二:float形式的vector转单通道mat;情况三:float形式的vector转三通道mat。

vector<uchar>转单通道mat

如果是std::vector<int64>则需要转换为std::vector<uchar>才行,在深度学习中argmax后返回的数据类型通常是int64的。

//语义分割结果转mat
cv::Mat vector2mat(std::vector<uchar> output, cv::Size2d size = { 512,512 }) {
	cv::Mat out_result(size.height, size.width, CV_8UC1, cv::Scalar(0));
	out_result.data = output.data();
	return out_result;
}
vector<float>转单通道mat

因为mat.data 是uchar型的指针,所有vector<float>不能像vector<uchar>那样进行赋值操作,但其有两种赋值方式,分别是memcpy和mat.assign

cv::Mat vector2mat(std::vector<float> output, cv::Size2d size = { 512,512 }) {
	cv::Mat out_result(size.height, size.width, CV_32FC1, cv::Scalar(0));
	memcpy(out_result.data, output.data(), output.size() * sizeof(float));
	//output.assign((float*)out_result.datastart, (float*)out_result.dataend);
	return out_result;
}
vector<float>转三通道mat

这里通过调用上一步实现的函数,实现目标功能,所转换的mat为bgr格式。

//将CHW格式的数据转换为bgr格式的mat
cv::Mat cwhfloat2mat(std::vector<float> output, cv::Size2d size = { 512,512 }) {
	cv::Mat out_result;
	int dis = size.height * size.width;
	//将数据进行切片
	vector<float> r{ &output[0], &output[0] + dis };
	vector<float> g{ &output[0] + dis, &output[0] + 2 * dis };
	vector<float> b{ &output[0] + 2 * dis, &output[0] + 3 * dis };

	vector<cv::Mat> mat_bgr;
	mat_bgr.push_back(vector2mat(b, size));
	mat_bgr.push_back(vector2mat(g, size));
	mat_bgr.push_back(vector2mat(r, size));
	cv::merge(mat_bgr, out_result);
	//out_result = out_result * 255;
	//out_result.convertTo(out_result, CV_8UC3);
	//cv::cvtColor(out_result, out_result, cv::COLOR_BGR2RGB);
	return out_result;
}

4、Mat切片与还原

Mat切片成vector ,vector 还原成mat文章来源地址https://www.toymoban.com/news/detail-478837.html

#include <iostream>
#include <memory>
#include <chrono>
#include <fstream>
#include <string>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
//rows,cols 用于将切片信息带出模型
int crop_img(vector<Mat> &crops,Mat img,int block_size, int &rows, int &cols) {
    float fisze = block_size * 1.0;
    rows = ceil(img.rows / fisze);//向上取整
    cols = ceil(img.cols / fisze);

    //确保切片过程中图像不会超出边界
    if (rows * block_size > img.rows || cols * block_size > img.cols) {
        Mat new_img = Mat::zeros({ cols * block_size,rows * block_size }, img.type());
        Rect rect = { 0,0,img.cols,img.rows };
        img.copyTo(new_img(rect));
        img = new_img;//用新图替换旧图
    }
    //对图像进行切片
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            Rect rect = { j * block_size,i * block_size,block_size,block_size };
            Mat crop = img(rect);
            crops.push_back(crop);
        }
    }
    return 0;
}
//根据信息对切片进行还原
Mat merger_crop(vector<Mat> crops, int block_size, int rows, int cols, Size img_size = {0,0}) {
    Mat save_img = Mat::zeros({ cols * block_size,rows * block_size }, crops[0].type());
    for (int i = 0; i < rows; i++) { // row=>y   行=》高
        for (int j = 0; j < cols; j++) {//cols=>x  列=》宽
            int index = i * cols + j;
            Mat crop = crops[index];
            Rect rect = { j * block_size,i * block_size,block_size,block_size };
            crop.copyTo(save_img(rect));
        }
    }
    //根据输入的size对图像进行裁剪
    if (img_size.area() > 0) {
        Rect rect = { {0,0},img_size };
        save_img = save_img(rect);
    }
    return save_img;
}
int main() {
    Mat img = imread("D:/20141014.jpg");
    int block_size = 256;
    int rows = 0;
    int cols = 0;
    vector<Mat> crops;
    crop_img(crops,img, block_size, rows, cols);

    Mat merge= merger_crop(crops, block_size, rows, cols, img.size());
    imshow("img", img);
    imshow("recover", merge);
    waitKey();
	return -1;
}

到了这里,关于Opencv 基本操作四 指针数组、vector与Mat之间的相互转换 | Mat切片成Vector<mat>并还原的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV基本操作——算数操作

    两个图像应该具有相同的大小和类型,或者第二个图像可以是标量值 注意:OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加的是模运算 ((414, 500, 3), (429, 499, 3)) (429, 499, 3) 其实也是加法,只是权重不同

    2024年02月13日
    浏览(36)
  • 【MATLAB】 01 基本操作与数组输入

    认识 MATLAB 操作界面 可以通过 Layout 选择需要显示的窗口及布局 使用 MATLAB 编程有两种方法 命令行 (命令窗口) 脚本 ( .m 文件) 运算符 + , - , * , / , ^ 计算的结果 以 ans 显示 优先级 同一优先级从左到右 优先级为 Parenthesis ( () ) Power ( ^ ) Multiplication and division ( * , / ) Addition and sub

    2024年02月06日
    浏览(32)
  • OpenCV基本图像处理操作(一)——图像基本操作与形态学操作

    图像显示 转hsv图像 颜色表示为三个组成部分:色调(Hue)、饱和度(Saturation)和亮度(Value)。常用于图像处理中,因为它允许调整颜色的感知特性,如色彩和亮度,这些在RGB颜色模型中不那么直观。 HSV模型特别适用于任务如图像分割和对象追踪,因为它可以更好地处理光

    2024年04月22日
    浏览(37)
  • OpenCV基本操作——图像的基础操作

    注:opencv图像坐标系中,左上角是原点,y轴向下,x轴向右,单位像素点 有时需要在B,G,R通道图像上单独工作。在这种情况下,需要将BGR图像分割成单个通道。或者在其他情况下,可能需要将这些单独的通道合并到BGR图像 opencv中有150多种颜色空间转换方法。最广泛使用的转

    2024年02月13日
    浏览(44)
  • Opencv基本操作 (上)

    目录 图像基本操作 阈值与平滑处理 图像阈值 图像平滑处理 图像形态学操作 图像梯度计算 Sobel 算子 Canny 边缘检测 图像金字塔与轮廓检测   图像轮廓 接口定义  轮廓绘制 轮廓特征与相似 模板匹配  傅里叶变换 傅里叶变换的作用 滤波 图像基本操作 读取图像: 使用cv2.i

    2024年03月18日
    浏览(36)
  • 【笔记】OpenCV图像基本操作

    目录 一、图像属性 1.1图像格式 1.2图像尺寸 1.3图像分辨率和通道 1.4图像直方图 1.5图像颜色空间 二、基本操作 2.1 图像读取 cv2.imread() 2.2 图像的显示 cv2.imshow() 2.3 图像的保存 cv2.imwrite() 2.4 用matplotlib显示图像 plt.imshow() 2.5 视频读取 cv2.VideoCapture() 2.6 图像截取、颜色通道提取

    2024年02月03日
    浏览(30)
  • Opencv+Python图像基本操作

    目录 图像的读取、显示和保存 获取图像属性  图像截取  绘图功能 画线 画矩形 画圆圈 画椭圆          画多边形 向图像添加文本 cv2.imread() ,  cv2.imshow() ,  cv2.imwrite()分别表示读取图片,显示图片,写入图片   retval = cv2.imread(文件名 [,显示控制参数]) cv2.IMREAD_UNCHANGED:不改

    2024年02月04日
    浏览(33)
  • OpenCV-opencv下载安装和基本操作

    本实验目的是学习如何使用opencv库来读取文件并显示图象,学习opencv中的基本事件——窗口事件,鼠标事件、键盘事件以及滑动条事件,同时熟悉OpenCV库的函数和方法,为进一步学习和应用计算机视觉和图像处理提供基础。 1、opencv的安装 2、opencv的基本操作 - 图像输入输出模

    2024年02月03日
    浏览(37)
  • opencv学习(一)图像的基本操作

    cv2.IMREAD_COLOR:彩色图像 cv2.IMREAD_GRAYSCALE:灰度图像 cv2.imread()读取图片,当括号里面是 1 时,也就是替代了cv2.IMREAD_COLOR,得到 彩色图 。 cv2.imread()读取图片,当括号里面是 0 时,替代了cv2.IMREAD_GRAYSCALE,得到 灰度图 。 cv.inshow()函数为创建一个展示窗口,括号里面分别为 图片名字

    2024年02月05日
    浏览(36)
  • 10- OpenCV:基本阈值操作(Threshold)

    目录 1、图像阈值 2、阈值类型 3、代码演示 1、图像阈值 (1)图像阈值(threshold)含义:是将图像中的像素值划分为不同类别的一种处理方法。通过设定一个特定的阈值,将像素值与阈值进行比较,根据比较结果将像素分为两个或多个类别。         阈值 是什么?简单点

    2024年01月18日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包