本文主要是介绍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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!