OpenCV二维Mat索引与值互换:求(X,Y)=Z转(X,Z)=Y的高效实现方案
解决方案
结合你给出的输入输出规则、矩阵尺寸和稀疏特性,有两种比逐元素遍历效率更高的实现方案:
方案1:需要输出稠密Mat的场景
你输出的Mat尺寸仅为100×1000,总元素数才10万,内存占用可忽略,优先用这个方案:
- 先初始化输出Mat为你需要的默认填充值(示例中为0),尺寸为
z的取值上限 × x维度数,数据类型选能覆盖y最大值的最小类型即可(比如y最大为20,用CV_8U就足够) - 仅遍历原始输入Mat的所有有效元素(总共有100×20=2000个),直接按映射规则给输出Mat对应位置赋值,不需要遍历输出Mat的空值位置
- 可搭配OpenCV内置的
cv::parallel_for_做并行加速,耗时可以压到毫秒级
示例代码(C++):
// 假设输入src的行对应y维度、列对应x维度,z的取值范围为[0,999],默认填充值为0 int x_cnt = src.cols; int z_max = 1000; int y_cnt = src.rows; cv::Mat dst = cv::Mat::zeros(z_max, x_cnt, CV_8UC1); // 并行遍历原始矩阵的y维度 cv::parallel_for_(cv::Range(0, y_cnt), [&](const cv::Range& range) { for (int y = range.start; y < range.end; y++) { const uchar* src_row_ptr = src.ptr<uchar>(y); for (int x = 0; x < x_cnt; x++) { int z = src_row_ptr[x]; // 你要求的z范围校验,不符合的跳过不处理 if (z >= 0 && z < z_max) { // 示例中y从1开始计数,所以加1;如果是0起始直接赋值y即可 dst.ptr<uchar>(z)[x] = y + 1; } } } });
方案2:不需要输出稠密Mat的场景
如果后续仅需要查询(x,z)对应的y值,不需要用稠密Mat做矩阵运算,直接用稀疏存储结构更省空间,查询效率也更高:
- 不需要提前申请10万元素的大矩阵,用
cv::SparseMat或者std::vector<std::unordered_map<int, int>>存储即可,每个x对应一个z:y的键值对映射 - 同样仅遍历输入的2000个有效点,把映射关系存入稀疏结构即可,总占用空间只有2000组键值对,比稠密Mat省98%以上的内存
效率对比说明
你的场景稀疏特性反而会大幅提升效率:如果原来的实现是遍历输出矩阵的每个(x,z)位置反查y值,时间复杂度是O(xz)也就是10万次操作;现在的方案仅需要处理输入的2000个点,时间复杂度为O(xy),速度至少快50倍,就算不用并行加速也足够快。
内容的提问来源于stack exchange,提问作者already puzzled
相关产品推荐
相关产品推荐

