opencv 打开图片后,cv::mat存入共享内存的代码,以及如何设置共享内存的大小?图片的3840x2160 pixels

本文主要是介绍opencv 打开图片后,cv::mat存入共享内存的代码,以及如何设置共享内存的大小?图片的3840x2160 pixels,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

opencv 打开图片后,cv::mat存入共享内存的代码,以及如何设置共享内存的大小?图片的3840x2160 pixels。
在OpenCV中,将cv::Mat对象存入共享内存需要几个步骤。首先,你需要创建一个共享内存区域,然后将cv::Mat的数据复制到该区域。下面是一个简单的示例代码,展示了如何实现这一过程:

  • 创建共享内存区域:你可以使用POSIX共享内存(shm_open和mmap)或System V共享内存(shmget和shmat)来创建共享内存区域。这里我们使用POSIX共享内存作为例子。
  • 设置共享内存的大小:共享内存的大小应该至少与cv::Mat的数据部分一样大。对于彩色图像,每个像素通常由多个字节表示(例如,对于BGR图像,每个像素有3个字节)。此外,还需要考虑图像的行对齐(stride)问题。OpenCV的cv::Mat对象可能包含额外的填充字节以确保每行的起始地址对齐。

下面是一个简单的代码示例:

#include <opencv2/opencv.hpp>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>int main() {// 读取图片cv::Mat image = cv::imread("path_to_your_image.jpg", cv::IMREAD_COLOR);if (image.empty()) {std::cerr << "无法打开图片" << std::endl;return -1;}// 计算共享内存的大小// 对于BGR图像,每个像素3个字节,加上可能的行对齐填充size_t shmSize = image.total() * image.elemSize() + getpagesize() - 1;shmSize -= shmSize % getpagesize(); // 确保大小是页面大小的整数倍// 创建共享内存对象int shmFd = shm_open("/my_shared_memory", O_CREAT | O_RDWR, 0666);if (shmFd == -1) {perror("shm_open");return -1;}// 设置共享内存的大小if (ftruncate(shmFd, shmSize) == -1) {perror("ftruncate");return -1;}// 将共享内存映射到进程的地址空间void* shmPtr = mmap(nullptr, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, shmFd, 0);if (shmPtr == MAP_FAILED) {perror("mmap");return -1;}// 将cv::Mat的数据复制到共享内存memcpy(shmPtr, image.data, image.total() * image.elemSize());// ... 在这里,你可以让其他进程访问共享内存中的图像数据 ...// 清理资源munmap(shmPtr, shmSize);close(shmFd);shm_unlink("/my_shared_memory");return 0;
}

注意:

上述代码仅作为示例,可能需要根据你的具体需求进行调整。
共享内存的使用需要谨慎处理同步和互斥问题,以避免数据竞争和不一致。你可能需要使用锁或其他同步机制来确保多个进程安全地访问共享内存。
在使用共享内存时,还需要考虑权限和安全性问题。确保只有授权的进程可以访问共享内存,并遵循最小权限原则。

为何不用read() 用memcpy()?

在涉及共享内存时,使用 memcpy() 而不是 read() 的主要原因在于共享内存的特性。共享内存允许两个或多个进程直接访问同一块物理内存,而不需要通过内核或其他中间层进行数据的复制或传递。

直接访问:由于共享内存是直接映射到每个进程的地址空间的,因此进程可以像访问本地内存一样直接访问它。这意味着进程可以直接读取和写入共享内存,而不需要通过系统调用(如 read() 或 write())来间接操作。
效率:使用 memcpy() 直接在进程的地址空间内复制数据通常比使用 read() 或 write() 进行系统调用要快得多。系统调用涉及内核与用户空间之间的上下文切换,这通常是一个相对昂贵的操作。因此,对于需要频繁访问共享内存的场景,使用 memcpy() 可以显著提高性能。
语义差异:read() 通常用于从文件描述符(如文件、管道或套接字)中读取数据,而共享内存不是文件描述符。因此,从语义上讲,使用 memcpy() 来复制共享内存中的数据更为合适。
同步问题:当多个进程同时访问共享内存时,需要考虑同步问题以避免数据竞争和不一致。使用 memcpy() 并不会解决同步问题,但你可以结合其他同步机制(如互斥锁、信号量或原子操作)来确保对共享内存的访问是安全的。

总之,使用 memcpy() 而不是 read() 来访问共享内存是因为共享内存允许直接访问,使用 memcpy() 可以提高性能,并且从语义上讲更为合适。然而,这并不意味着 read() 在所有情况下都不能用于共享内存;在某些特定的上下文中,它可能仍然是有用的。但在大多数情况下,当涉及到共享内存时,你会更倾向于使用 memcpy() 或其他类似的内存操作函数。

为何cv::mat的内存比图片本身大很多?图片只有1.5M,但是内存有25M

cv::Mat对象在内存中占用的空间可能比图片文件本身大很多,这通常是由以下几个原因造成的:

数据格式和编码:图片文件在存储时,通常会使用某种形式的压缩,例如JPEG、PNG等。这些压缩格式可以有效地减小文件大小,但解压后的原始图像数据会占用更多的内存空间。cv::Mat存储的是解压后的原始图像数据,因此其内存占用会大于压缩后的文件大小。

通道和深度:图像的每个像素可能由多个通道组成(如RGB图像的三个通道),每个通道可能使用不同的数据深度(如8位无符号整数、16位有符号整数、32位浮点数等)。通道数量和深度的增加都会导致内存占用的增加。

行对齐:cv::Mat为了优化内存访问速度,可能会在每行的末尾添加额外的填充字节,以确保每行的起始地址都是某个固定大小的整数倍(通常是16字节或32字节)。这种行对齐会增加内存占用,但可以提高内存访问的效率。

附加信息和元数据:除了图像数据本身外,cv::Mat还可能存储一些附加信息和元数据,如图像的尺寸、类型、步长等。这些信息虽然不直接表示图像内容,但也会占用一定的内存空间。

内存分配机制:在某些情况下,内存分配器可能会为cv::Mat分配比实际所需稍大的内存块,以减少频繁分配和释放小块内存的开销。这也会导致观察到的内存占用大于预期。

因此,即使图片文件本身只有1.5M,cv::Mat对象在内存中占用25M也是可能的。这并不意味着有内存浪费,而是反映了原始图像数据在内存中的实际占用情况。如果需要减小内存占用,可以考虑使用更小的数据类型、减少通道数量或采用其他优化方法。然而,这些优化可能会影响到图像的质量和处理能力。

另外一个进程显示

#include <opencv2/opencv.hpp>
#include <sys/mman.h> // 对于共享内存映射
#include <fcntl.h>    // 对于文件控制操作
#include <unistd.h>   // 对于unistd系统调用
#include <cstring>    // 对于memcpy// 假设你已经有了共享内存的标识符(例如,通过shm_open或ftruncate创建)
int shm_fd = ...; // 共享内存的文件描述符// 假设你已经知道了图片的尺寸和类型
int width = ...;
int height = ...;
int channels = ...; // 例如,对于BGR图片,channels是3
int type = CV_8UC3; // 假设是8位无符号字符的3通道BGR图片// 计算共享内存的大小
size_t shmSize = width * height * channels * sizeof(uchar);// 将共享内存映射到当前进程的地址空间
uchar* sharedMemoryData = static_cast<uchar*>(mmap(nullptr, shmSize, PROT_READ, MAP_SHARED, shm_fd, 0));
if (sharedMemoryData == MAP_FAILED) {perror("mmap");// 错误处理...
}// 创建cv::Mat对象来包装共享内存中的数据
cv::Mat image(height, width, type, sharedMemoryData);// 显示图片
cv::imshow("Stitching Image", image);
cv::waitKey(0); // 等待按键,0表示无限等待// 在不再需要时,解除映射
if (munmap(sharedMemoryData, shmSize) == -1) {perror("munmap");// 错误处理...
}// 关闭共享内存的文件描述符
close(shm_fd);

个人实践

https://gitee.com/hiyanyx/share-memory-mmap-opencv

这篇关于opencv 打开图片后,cv::mat存入共享内存的代码,以及如何设置共享内存的大小?图片的3840x2160 pixels的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072829

相关文章

opencv图像处理之指纹验证的实现

《opencv图像处理之指纹验证的实现》本文主要介绍了opencv图像处理之指纹验证的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、简介二、具体案例实现1. 图像显示函数2. 指纹验证函数3. 主函数4、运行结果三、总结一、

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

PyCharm如何设置新建文件默认为LF换行符

《PyCharm如何设置新建文件默认为LF换行符》:本文主要介绍PyCharm如何设置新建文件默认为LF换行符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录PyCharm设置新建文件默认为LF换行符设置换行符修改换行符总结PyCharm设置新建文件默认为LF

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在

Java中&和&&以及|和||的区别、应用场景和代码示例

《Java中&和&&以及|和||的区别、应用场景和代码示例》:本文主要介绍Java中的逻辑运算符&、&&、|和||的区别,包括它们在布尔和整数类型上的应用,文中通过代码介绍的非常详细,需要的朋友可... 目录前言1. & 和 &&代码示例2. | 和 ||代码示例3. 为什么要使用 & 和 | 而不是总是使