我正在尝试实现用于图像过滤的“自适应”卷积,其将输出像素的最大或最小可能值限制预定界限。我还没有在opencv中找到任何允许我这样做的函数,所以我写了自己的函数来完成我想要的东西。 (可能有不同的库吗?)唯一的问题是这个函数需要大约0.9秒,而cv :: filter2D过滤图像需要大约0.005秒(两者都使用相同的内核)。有谁知道如何加快我的方法?
关于我的内核的一些评论:它是一个9x9自定义锐化过滤器,内核不可分离。我尝试重新设计我的过滤器是可分离的,但我无法达到预期的效果。有什么想法吗?下面是我用于代码的函数:
Mat& adaptive_convolution(Mat& img)
{
fstream in("kernel.txt");
string line;
float v[9][9];
int i = 0, k = 0;
while (getline(in, line))
{
float value;
int k = 0;
stringstream ss(line);
while (ss >> value)
{
v[i][k] = value;
++k;
}
++i;
}
clock_t init, end;
double minVal;
double maxVal;
Point minLoc;
Point maxLoc;
int pad_fact = 4;
int top, left, bottom, right;
Mat new_image = img;
top = pad_fact; bottom = pad_fact;
left = pad_fact; right = pad_fact;
copyMakeBorder(img, new_image, top, bottom, left, right, BORDER_CONSTANT, 0);
minMaxLoc(img, &minVal, &maxVal, &minLoc, &maxLoc);
new_image / 2^8;
init = clock();
double temp = 0;
for (int i = pad_fact; i < img.rows + pad_fact; i++)
{
for (int j = pad_fact; j < img.cols + pad_fact; j++)
{
for (int ii = -pad_fact; ii <= pad_fact; ii++)
{
for (int jj = -pad_fact; jj <= pad_fact; jj++)
{
//temp = double(v[ii + 2*pad_fact][jj + 2*pad_fact]);
temp = temp + double(v[ii + pad_fact][jj + pad_fact] * float(new_image.at<uchar>(i - jj, j - ii)));
//temp = double(new_image.at<uchar>(i - jj, j - ii));
}
}
if (temp > maxVal)
{
temp = maxVal;
}
else
{
if (temp < minVal)
{
temp = minVal;
}
}
new_image.at<uchar>(i, j) = temp;
temp = 0;
}
}
img = new_image;
end = clock();
cout << float(end - init)/1000 << endl;
return img;
}
编辑:
我能够使用Numba在我使用的python脚本中加速卷积约0.2秒。我仍然需要使用c ++看到这种改进。我是否通过使用opencv帮助回来了?
import numba as nb
import numpy as np
@nb.autojit
def custom_convolve(image,kernel,pad_fact):
pad_fact = int(pad_fact)
filt_im = np.zeros(image.shape)
rows = image.shape[0]
columns = image.shape[1]
glob_max = np.max(image)
glob_min = np.min(image)
for x in range(pad_fact,columns-pad_fact,1):
for y in range(pad_fact,rows-pad_fact,1):
pix_sum = 0
for k in range(-pad_fact,pad_fact,1):
for j in range(-pad_fact,pad_fact,1):
pix_sum = pix_sum + kernel[k+pad_fact,j+pad_fact]*image[y-j,x-k]
if pix_sum > glob_max:
pix_sum = glob_max
elif pix_sum < glob_min:
pix_sum = glob_min
filt_im[y,x] = pix_sum
return filt_im
答案 0 :(得分:0)
大多数基本的OpenCV实现都使用SSE function,它允许使用128位变量进行两个进程加法等。另一个技巧是,如果过滤器内核是separable,可以按如下方式组成:
K = D * D'
其中*表示卷积算子,D是矢量,例如[1 2 1],K是最终内核。您可以将图像A的过滤替换为图像B:
B = A * K;
与
B = A * D(*)(A'* D)'
这里(*)表示逐像素乘法,A'表示转置图像,即转置符号。