如何实现可处理不同类型图像的OpenCV函数及Mat行删除问题
嘿,我来帮你搞定这两个问题——既要学会编写能处理不同类型图像的OpenCV通用函数,还要把你现在写的两个重复的「删除指定行」函数合并成一个通用版本,避免冗余代码。
处理多类型图像的OpenCV函数实现方案
一、编写通用型OpenCV函数的核心思路
要适配不同数据类型的图像(比如单通道的CV_8UC1、CV_32SC1,或者多通道的CV_64FC3),最省心的方法是用C++模板函数。它能让同一套逻辑自动适配多种数据类型,不用为每个类型单独写重复代码。
关键技巧:
- 用模板参数
<typename T>指定像素的数据类型,比如int、float、cv::Vec3b(对应三通道8位图像) - 搭配OpenCV自带的
DataType<T>traits类,可以方便获取类型对应的OpenCV枚举值(比如CV_32SC1) - 处理多通道图像时,记得用对应的向量类型(比如
cv::Vec3f对应三通道float图像)
二、把你的「删除指定行」函数改成通用版本
你现在写的是针对CV_32SC1(int类型单通道)的函数,我们把它改成模板函数,这样不管是int、float还是其他类型的Mat,都能用同一个函数处理:
通用版完整代码
#include <opencv2/opencv.hpp> #include <algorithm> #include <vector> template<typename T> cv::Mat drop_rows(const cv::Mat& mat, const std::vector<int>& rows_to_drop) { // 先做基础合法性检查 if (mat.empty()) { return cv::Mat(); } if (rows_to_drop.empty()) { return mat.clone(); } // 对要删除的行号排序并去重,提升后续查找效率 std::vector<int> sorted_drop_rows = rows_to_drop; std::sort(sorted_drop_rows.begin(), sorted_drop_rows.end()); auto last = std::unique(sorted_drop_rows.begin(), sorted_drop_rows.end()); sorted_drop_rows.erase(last, sorted_drop_rows.end()); // 计算新矩阵的行数,若删除后无行则返回空矩阵 int new_row_count = mat.rows - sorted_drop_rows.size(); if (new_row_count <= 0) { return cv::Mat(); } // 创建和输入类型完全一致的新矩阵 cv::Mat new_mat(new_row_count, mat.cols, mat.type()); int dst_idx = 0; auto drop_iter = sorted_drop_rows.begin(); for (int src_idx = 0; src_idx < mat.rows; ++src_idx) { // 判断当前行是否在删除列表中 if (drop_iter != sorted_drop_rows.end() && *drop_iter == src_idx) { ++drop_iter; continue; } // 直接复制整行到新矩阵,比逐像素拷贝更高效 mat.row(src_idx).copyTo(new_mat.row(dst_idx)); ++dst_idx; } return new_mat; }
使用示例(适配不同类型)
// 测试int类型单通道矩阵 cv::Mat int_mat = (cv::Mat_<int>(3, 2) << 1, 2, 3, 4, 5, 6); std::vector<int> drop_int = {1}; cv::Mat result_int = drop_rows<int>(int_mat, drop_int); // 测试float类型单通道矩阵 cv::Mat float_mat = (cv::Mat_<float>(4, 3) << 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.1, 11.2, 12.3); std::vector<int> drop_float = {0, 2}; cv::Mat result_float = drop_rows<float>(float_mat, drop_float); // 测试三通道8位图像(用cv::Vec3b作为模板参数) cv::Mat rgb_mat = cv::imread("test.jpg"); std::vector<int> drop_rgb = {50, 100}; cv::Mat result_rgb = drop_rows<cv::Vec3b>(rgb_mat, drop_rgb);
三、其他通用图像处理函数的示例
再举个简单例子:写一个给所有像素加常数的通用函数,适配任意类型:
template<typename T> cv::Mat add_pixel_constant(const cv::Mat& mat, const T& constant) { cv::Mat result(mat.size(), mat.type()); // 用OpenCV的遍历器更简洁,也支持多通道 cv::Mat_<T> src_mat = mat; cv::Mat_<T> dst_mat = result; for (int i = 0; i < src_mat.rows; ++i) { for (int j = 0; j < src_mat.cols; ++j) { dst_mat(i, j) = src_mat(i, j) + constant; } } return result; }
避坑小贴士
- 模板函数要放在头文件里实现,或者在使用前显式实例化(不然编译器可能找不到定义)
- 可以用
CV_Assert做严格的类型检查,比如确保输入Mat的类型和模板参数匹配:CV_Assert(mat.type() == cv::DataType<T>::type); - 处理多通道图像时,一定要用对应的向量类型(比如
cv::Vec3b对应CV_8UC3,cv::Vec3f对应CV_32FC3)
内容的提问来源于stack exchange,提问作者tem




