我从未使用OpenMP或C ++优化,所以欢迎所有帮助。我可能正在做一些非常愚蠢的事情,这会大大减缓这个过程。它不需要是最快的,但我认为一些简单的技巧将显着加快它。任何人?非常感谢!
在给定内核大小和灰度OpenCV图像的情况下,此函数计算补丁的标准差。如果补丁的中间像素低于给定阈值,则保留其中间像素,否则拒绝。这是为除边框之外的每个像素完成的。
#include "stdafx.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/photo/photo.hpp"
#include <stdlib.h>
#include <stdio.h>
#include "utils.h"
#include <windows.h>
#include <string.h>
#include <math.h>
#include <numeric>
using namespace cv;
using namespace std;
Mat low_pass_filter(Mat img, int threshold, int kernelSize)
{
unsigned char *input = (unsigned char*)(img.data);
Mat output = Mat::zeros(img.size(), CV_8UC1);
unsigned char *output_ptr = (unsigned char*)(output.data);
#pragma omp parallel for
for (int i = (kernelSize - 1) / 2; i < img.rows - (kernelSize - 1) / 2; i++){
for (int j = (kernelSize - 1) / 2; j < img.cols - (kernelSize - 1) / 2; j++){
double sum, m, accum, stdev;
vector<double> v;
// Kernel Patch
for (int kx = i - (kernelSize - 1) / 2; kx <= i + (kernelSize - 1) / 2; kx++){
for (int ky = j - (kernelSize - 1) / 2; ky <= j + (kernelSize - 1) / 2; ky++){
v.push_back((double)input[img.step * kx + ky]);//.at<uchar>(kx, ky));
}
}
sum = std::accumulate(std::begin(v), std::end(v), 0.0);
m = sum / v.size();
accum = 0.0;
std::for_each(std::begin(v), std::end(v), [&](const double d) {
accum += (d - m) * (d - m);
});
stdev = sqrt(accum / (v.size() - 1));
if (stdev < threshold){
output_ptr[img.step * i + j] = input[img.step * i + j];
}
}
}
return output;
}
答案 0 :(得分:2)
不需要Vector v。不要向其中添加项目,而是维护d
和d*d
的累加器,然后使用variance = E(v²) / E(v)²以便内部代码变为:
double sum = 0;
double sum2 = 0;
int n = kernelSize * kernelSize;
// Kernel Patch
for (int kx = ...) {
for (int ky = ...) {
sum += d;
sum2 += d*d;
}
}
double mean = sum/n;
double stddev = sqrt(sum2/n - mean*mean);
if (stddev < threshold) {
...;
}
之后,考虑以(x + 1,y)为中心的元素之和可以从(x,y)的结果中找到,只需减去前一个左栏中的所有元素,然后添加全部新右栏中的元素。类似的操作垂直工作。
另外,检查您的编译器选项 - 您是自动向量化循环,还是使用SIMD指令(如果可用)?