OpenCV中的卷积函数filter2d()只能对整张图像进行卷积而无法对图像中的某一区域进行卷积。本文提供了利用OpenCV实现对图像指定区域卷积的函数(仅限单通道8位图)。
函数如下:
bool ConvolvePartRegionOfImage(uchar* const pImage, const int imageWidth, const int imageHeight, const int regionX, const int regionY, const int regionWidth, const int regionHeight, Mat kernel)
{
//参数保护
if (regionX + regionWidth > imageWidth || regionY + regionHeight > imageHeight)return false;
if (pImage == nullptr)return false;
//提取感兴趣区域
Mat image(imageHeight, imageWidth, CV_8UC1, pImage);
Mat img2(image, Rect(regionX, regionY, regionWidth, regionHeight));
Mat img3 = img2.clone();
//对感兴趣区域进行卷积
filter2D(img3, img2, -1, kernel);
return true;
}
参数详情:
bool ConvolvePartRegionOfImage
(
uchar* const pImage, //图像数据首地址
const int imageWidth, //图像宽度
const int imageHeight, //图像高度
const int regionX, //指定区域的坐标x值
const int regionY, //指定区域的坐标y值
const int regionWidth, //指定区域宽度
const int regionHeight, //指定区域高度
Mat kernel; //使用的卷积核
)
测试用例:
#include<iostream>
#include"./opencv/include/opencv2/highgui.hpp"
#include"./opencv/include/opencv2/opencv.hpp"
using namespace std;
using namespace cv;
bool ConvolvePartRegionOfImage(uchar* const pImage, const int imageWidth, const int imageHeight, const int regionX, const int regionY, const int regionWidth, const int regionHeight, Mat kernel)
{
//参数保护
if (regionX + regionWidth > imageWidth || regionY + regionHeight > imageHeight)return false;
if (pImage == nullptr)return false;
//提取感兴趣区域
Mat image(imageHeight, imageWidth, CV_8UC1, pImage);
Mat img2(image, Rect(regionX, regionY, regionWidth, regionHeight));
Mat img3 = img2.clone();
//对感兴趣区域进行卷积
filter2D(img3, img2, -1, kernel);
return true;
}
int main()
{
//读取图像并获取图像地址
Mat image = imread("./bmp/1.bmp", -1);
uchar* p = image.ptr<uchar>(0);
//创建大小为3x3的十字交叉型卷积核
Mat kernel = getStructuringElement(MORPH_CROSS, Size(3, 3));
//调用函数
ConvolvePartRegionOfImage(p, image.cols, image.rows, 10, 10, 50, 50, kernel);
imshow("卷积后图像", image);
waitKey(0);
return 0;
}
输出结果:
原图像 | 卷积后图像 |
可以看到,图像中的部分区域进行了卷积,其余区域不变。
不难发现,函数中原本可以对img2直接进行卷积,但实际上函数对图像多使用了一次Clone()函数得到img3进行操作,再将img3赋回img2
从逻辑上这是多此一举的操作,但在实际测试中发现,如果不将图像复制出来卷积再赋值回去,在卷积核的尺寸>11的时候,图像的卷积无法生效,原因不明。
所以为了稳定起见,函数内多使用了一次复制操作。
以上函数只能实现图像单个区域的卷积,为了能够同时对图像多个区域进行卷积,提供重载函数如下:
bool ConvolvePartRegionOfImage(uchar* const pImage, const int imageWidth, const int imageHeight, vector<vector<int>> regionXYWH, Mat kernel)
{
//参数保护
if (pImage == nullptr)return false;
if (regionXYWH[0].size() != 4)return false;
Mat image(imageHeight, imageWidth, CV_8UC1, pImage);
for (int i = 0; i < regionXYWH.size(); i++)
{
if (regionXYWH[i][0] + regionXYWH[i][2] > imageWidth || regionXYWH[i][1] + regionXYWH[i][3] > imageHeight)return false;
Mat img2(image, Rect(regionXYWH[i][0], regionXYWH[i][1], regionXYWH[i][2], regionXYWH[i][3]));
Mat img3 = img2.clone();
//对感兴趣区域进行卷积
filter2D(img3, img2, -1, kernel);
}
return true;
}
参数详情:
bool ConvolvePartRegionOfImage
(
uchar* const pImage, //图像数据首地址
const int imageWidth, //图像宽度
const int imageHeight, //图像高度
vector<vector<int>> regionXYWH, //二维向量,指定区域{x坐标,y坐标,宽度,高度}
Mat kernel //使用的卷积核
)
谢谢观看!