//NL-means 算法的实现 voidnonlocalMeansFilter(Mat& src, Mat& dst, int templeteWindowSize, int searchWindowSize, double h, double sigma = 0.0){ //邻域的大小不能超过搜索窗口的大小 if (templeteWindowSize > searchWindowSize){ cout <"searchWindowSize should be larger than templeteWindowSize" return; }
if (dst.empty()) dst = Mat::zeros(src.size(), src.type());
constint tr = templeteWindowSize >> 1;//tr为邻域的中心位置 constint sr = searchWindowSize >> 1; //sr为搜索域的中心位置 constint bb = sr + tr;//需增加的边界宽度 constint D = searchWindowSize*searchWindowSize;//搜索域中的元素个数 constint H = D / 2 + 1;//搜索域中的中心点位置 constdouble div = 1.0 / (double)D;//均匀分布时,搜索域中的每个点的权重大小 constint tD = templeteWindowSize*templeteWindowSize;//邻域中的元素个数 constdouble tdiv = 1.0 / (double)(tD);//均匀分布时,搜索域中的每个点的权重大小
//扩充边界 Mat boardSrc; copyMakeBorder(src, boardSrc, bb, bb, bb, bb, cv::BORDER_DEFAULT);
//w[i]保存方差,即邻域平均欧氏距离对应的高斯加权权重,供后面计算出欧式距离后调用 for (int i = 0; i double v = std::exp(max(i - 2.0*gauss_sd*gauss_sd, 0.0)*gauss_color_coeff); w[i] = v; if (v<0.001){ emax = i; break; } }
for (int i = emax; i w[i] = 0.0;
int height = src.rows; int width = src.cols;
if (src.channels() == 3){ constint cstep = (int)boardSrc.step - templeteWindowSize * 3; constint csstep = (int)boardSrc.step - searchWindowSize * 3; #pragma omp parallel for for (int j = 0; j uchar* d = dst.ptr(j); int* ww = newint[D];//D 为搜索域中的元素数量,ww用于记录搜索域每个点的邻域方差 double* nw = newdouble[D];//根据方差大小高斯加权归一化后的权重 for (int i = 0; idouble tweight = 0.0; //search loop uchar* tprt = boardSrc.data + boardSrc.step * (sr + j) + 3 * (sr + i); uchar* sptr2 = boardSrc.data + boardSrc.step * j + 3 * i; for (int l = searchWindowSize, count = D - 1; l--;){ uchar* sptr = sptr2 + boardSrc.step * (l); for (int k = searchWindowSize; k--;){ //templete loop int e = 0; uchar* t = tprt; uchar* s = sptr + 3 * k; for (int n = templeteWindowSize; n--;){ for (int m = templeteWindowSize; m--;){ // computing color L2 norm e += (s[0] - t[0])*(s[0] - t[0]) + (s[1] - t[1])*(s[1] - t[1]) + (s[2] - t[2])*(s[2] - t[2]);//L2 norm s += 3; t += 3; } t += cstep; s += cstep; } constint ediv = e*tdiv; ww[count--] = ediv; //get weighted Euclidean distance tweight += w[ediv]; } }
//weight normalization if (tweight == 0.0){ for (int z = 0; z0; nw[H] = 1; }else{ double itweight = 1.0 / (double)tweight; for (int z = 0; z } double r = 0.0, g = 0.0, b = 0.0; uchar* s = boardSrc.ptr(j + tr); s += 3 * (tr + i); for (int l = searchWindowSize, count = 0; l--;){ for (int k = searchWindowSize; k--;) { r += s[0] * nw[count]; g += s[1] * nw[count]; b += s[2] * nw[count++]; s += 3; } s += csstep; } d[0] = saturate_cast(r); d[1] = saturate_cast(g); d[2] = saturate_cast(b); d += 3; }//i delete[] ww; delete[] nw; }//j } elseif (src.channels() == 1){ constint cstep = (int)boardSrc.step - templeteWindowSize;//在邻域比较时,从邻域的上一行末尾跳至下一行开头 constint csstep = (int)boardSrc.step - searchWindowSize;//搜索域循环中,从搜索域的上一行末尾跳至下一行开头 #pragma omp parallel for for (int j = 0; j uchar* d = dst.ptr(j); int* ww = newint[D]; double* nw = newdouble[D]; for (int i = 0; idouble tweight = 0.0; uchar* tprt = boardSrc.data + boardSrc.step * (sr + j) + (sr + i); uchar* sptr2 = boardSrc.data + boardSrc.step * j + i; for (int l = searchWindowSize, count = D - 1; l--;){ uchar* sptr = sptr2 + boardSrc.step * (l); for (int k = searchWindowSize; k--;){ int e = 0; uchar* t = tprt; uchar* s = sptr + k; for (int n = templeteWindowSize; n--;){ for (int m = templeteWindowSize; m--;){ e += (*s - *t)*(*s - *t); s++; t++; } t += cstep; s += cstep; }