写在前面

接着上次的博客写,上次已经介绍完了POSHE部分,也为这次写BERF做了一些铺垫。在这次正式开始之前,还是先放两张图片,以说明执行BERF的必要性: 

仅执行POSHE

                                                                                                 

执行BERF后

从上面两幅图中就可以看出,仅执行POSHE会产生不可避免的快效应,尤其是边界产生了线。为了抑制这种干扰,论文提出来一种名为BERF(blocking effect reduction filter)的滤波器,中文叫块效应抑制滤波器。

原理

步骤:

本质上就是一种空间域的滤波,原理比较简单,我就直接写步骤:

1、判断是否产生块效应。论文没有给出具体的判断方法,按照我的理解,就是计算经过POSHE处理后图像的子块边界相邻两侧两个像素的灰度差异f1,同时计算原图的子块边界相邻两侧两个像素的灰度差异f2,如果f1-f2大于s,则产生了块效应,s可取3~4。比如,边界某像素在图像矩阵第5行,则边界相邻两侧两个像素就分别是第4和第6行。

2、若产生块效应,则计算第一步中相邻两侧两个像素的灰度平均值,并将该边界像素的灰度值替换为平均值。

3、在垂直于边界的方向上,以递增/递减顺序的像素值被缓慢变化的值替换,而且而是从上步计算的平均值开始。简单地说,就是在垂直于边界的方向上,从平均值开始,将本来正在处于递增或递减的像素值,代替为缓慢递增或递减的像素值。比如,边界为第5行,平均灰度值为100,那么这个边界像素的灰度值被替换为100,将另外两侧相邻像素中较大的像素替换为104,较小的替换为96,然后沿着垂直于边界的方向,如果不满足终止条件,就会一直替换下去,递增的一侧就会是104、108、112、116....,递减的一侧就会是96、92、88、84.........,直至满足终止条件。

终止条件:

论文用文字对3个终止条件进行了描述,但是我觉得用文字描述很不直观:

我用公式描述吧,以行边界(垂直边界方向就是列方向咯),且像素向上递增为例:

用x1表示当前已经执行过BERF的像素的灰度值(论文写的pixels that have previously have previously...),x2表示下一个准备执行BERF的像素的灰度值(论文写的the present pixel)。

条件1:x2-x1<4(step size),step size可取4及以下的值;

条件2:x2-x1> 40(large enough),large enough可取40及以上的值;

条件3:x2>X1。

以上就是以行边界(垂直边界方向就是列方向咯),且像素向上递增情况下的终止条件,我们编程时当然用的是执行条件咯:

以上3个终止条件改写成执行条件就是:

                                                             4<=x2-x1<=40;

很简单了有木有。其他情况的条件可以依次类推,或者看我的程序。

 

代码

结果图开篇已经放了,直接把代码放上吧,代码有点多,但都是相似的,搞懂一种情况即可:

PS:这里只放了BERF的代码,整个可以运行的代码在:github

/***************************************
BERF滤波器
src - 输入图像
dst - 输出图像
step_r  - 子块垂直移动步长
step_c  - 子块水平移动步长
step_levels - 灰度级缓慢变化的步长
large_dir  - 最大灰度差异
****************************************/
void BERF(cv::Mat& src, cv::Mat& dst, int step_r, int step_c , int step_levels, int large_dir){
 
	//处理子块的行边界(横向边界)
	for (int i = 0; i < dst.rows;){
		for (int j = 0; j < dst.cols; ++j){
			if (i - 1 >= 0 && i + 1 <= dst.rows - 1){ //图像边界判断,先排除第一行和最后一行
				//块效应检查
				int dfacter_newsrc = abs(src.at<uchar>(i, j) - src.at<uchar>(i + 1, j)) + abs(src.at<uchar>(i, j) - src.at<uchar>(i - 1, j)); //原图子块边界与相邻两侧像素的灰度差异
				int dfacter_dst = abs(dst.at<uchar>(i, j) - dst.at<uchar>(i + 1, j)) + abs(dst.at<uchar>(i, j) - dst.at<uchar>(i - 1, j)); //POSHEed图子块边界与相邻两侧像素的灰度差异
				if (dfacter_dst - dfacter_newsrc > step_levels){
					//存在块效应执行BERF
					int b = 0;
					int ave_bound = (int)(dst.at<uchar>(i - 1, j) + dst.at<uchar>(i + 1, j)) / 2;
					dst.at<uchar>(i, j) = ave_bound;
 
					if (dst.at<uchar>(i - 1, j) > dst.at<uchar>(i + 1, j)){ //垂直于子块边界,向上递增方向( increasing rule)
						if (i - 2 - b >= 0){ //图像边界判断(下一位置像素)
							int pixel_present_add = dst.at<uchar>(i - 1 - b, j);
							int pixel_next_add = dst.at<uchar>(i - 2 - b, j);
							pixel_present_add = ave_bound + step_levels;
							while (i - 2 - b >= 0 && pixel_next_add - pixel_present_add >= step_levels && pixel_next_add - pixel_present_add <= large_dir){
								pixel_next_add = pixel_present_add + step_levels;
								b += 1;
								if (i - 2 - b >= 0){ //图像边界判断(下一位置像素)
									pixel_present_add = dst.at<uchar>(i - 1 - b, j);
									pixel_next_add = dst.at<uchar>(i - 2 - b, j);
								}
							}
						}
						//垂直于子块边界,向下递减方向( decreasing rule)
						if (i + 2 + b <dst.rows){ //图像边界判断
							int pixel_present_dec = dst.at<uchar>(i + 1 + b, j);
							int pixel_next_dec = dst.at<uchar>(i + 2 + b, j);
							pixel_present_dec = ave_bound - step_levels;
							while (i + 2 + b >= 0 && pixel_present_dec - pixel_next_dec >= step_levels && pixel_present_dec - pixel_next_dec <= large_dir){
								pixel_next_dec = pixel_present_dec - step_levels;
								b += 1;
								if (i + 2 + b >= 0){ //图像边界判断
									pixel_present_dec = dst.at<uchar>(i + 1 + b, j);
									pixel_next_dec = dst.at<uchar>(i + 2 + b, j);
								}
							}
						}
 
					}
					else if (dst.at<uchar>(i - 1, j) < dst.at<uchar>(i + 1, j)){ 垂直于子块边界,向下递增方向( increasing rule)
						if (i + 2 + b < dst.rows){ //图像边界判断
							int pixel_present_add = dst.at<uchar>(i + 1 + b, j);
							int pixel_next_add = dst.at<uchar>(i + 2 + b, j);
							pixel_present_add = ave_bound + step_levels;
							while (i + 2 + b >= 0 && pixel_next_add - pixel_present_add >= step_levels && pixel_next_add - pixel_present_add <= large_dir){
								pixel_next_add = pixel_present_add + step_levels;
								b += 1;
								if (i + 2 + b >= 0){ //图像边界判断
									pixel_present_add = dst.at<uchar>(i + 1 + b, j);
									pixel_next_add = dst.at<uchar>(i + 2 + b, j);
								}
							}
						}
						//垂直于子块边界,向上递减方向( decreasing rule)
						if (i - 2 - b >= 0){ //图像边界判断
							int pixel_present_dec = dst.at<uchar>(i - 1 - b, j);
							int pixel_next_dec = dst.at<uchar>(i - 2 - b, j);
							pixel_present_dec = ave_bound - step_levels;
							while (i - 2 - b >= 0 && pixel_present_dec - pixel_next_dec >= step_levels && pixel_present_dec - pixel_next_dec <= large_dir){
								pixel_next_dec = pixel_present_dec - step_levels;
								b += 1;
								if (i - 2 - b >= 0){ //图像边界判断
									pixel_present_dec = dst.at<uchar>(i - 1 - b, j);
									pixel_next_dec = dst.at<uchar>(i - 2 - b, j);
								}
							}
						}
 
					}
				}
			}
		}
		i += step_r;
	}
 
	//处理子块的列边界(纵向向边界)
	for (int j = 0; j <dst.cols;){
		for (int i = 0; i < dst.rows; ++i){
			if (j - 1 >= 0 && j + 1 <= dst.cols - 1){ //图像边界判断,先排除第一列和最后一列
				//块效应检查
				int dfacter_newsrc = abs(src.at<uchar>(i, j) - src.at<uchar>(i, j + 1)) + abs(src.at<uchar>(i, j) - src.at<uchar>(i, j - 1));
				int dfacter_dst = abs(dst.at<uchar>(i, j) - dst.at<uchar>(i, j + 1)) + abs(dst.at<uchar>(i, j) - dst.at<uchar>(i, j + 1));
				if (dfacter_dst - dfacter_newsrc > step_levels){
					//存在块效应执行BERF
					int b = 0;
					int ave_bound = (int)(dst.at<uchar>(i, j - 1) + dst.at<uchar>(i, j + 1)) / 2;
					dst.at<uchar>(i, j) = ave_bound;
 
					if (dst.at<uchar>(i, j - 1) > dst.at<uchar>(i, j + 1)){ //垂直于子块边界,向左递增方向( increasing rule)
						if (j - 2 - b >= 0){ //图像边界判断
							int pixel_present_add = dst.at<uchar>(i, j - 1 - b);
							int pixel_next_add = dst.at<uchar>(i, j - 2 - b);
							pixel_present_add = ave_bound + step_levels;
							while (j - 2 - b >= 0 && pixel_next_add - pixel_present_add >= step_levels && pixel_next_add - pixel_present_add <= large_dir){
								pixel_next_add = pixel_present_add + step_levels;
								b += 1;
								if (j - 2 - b >= 0){ //图像边界判断
									pixel_present_add = dst.at<uchar>(i, j - 1 - b);
									pixel_next_add = dst.at<uchar>(i, j - 2 - b);
								}
							}
						}
						//垂直于子块边界,向右递减方向( decreasing rule)
						if (j + 2 + b <dst.cols){ //图像边界判断
							int pixel_present_dec = dst.at<uchar>(i, j + 1 + b);
							int pixel_next_dec = dst.at<uchar>(i, j + 2 + b);
							pixel_present_dec = ave_bound - step_levels;
							while (j + 2 + b >= 0 && pixel_present_dec - pixel_next_dec >= step_levels && pixel_present_dec - pixel_next_dec <= large_dir){
								pixel_next_dec = pixel_present_dec - step_levels;
								b += 1;
								if (j + 2 + b >= 0){ //图像边界判断
									pixel_present_dec = dst.at<uchar>(i, j + 1 + b);
									pixel_next_dec = dst.at<uchar>(i, j + 2 + b);
								}
							}
						}
 
					}
					else if (dst.at<uchar>(i, j - 1) < dst.at<uchar>(i, j + 1)){ 垂直于子块边界,向右递增方向( increasing rule)
						if (j + 2 + b < dst.cols){ //图像边界判断
							int pixel_present_add = dst.at<uchar>(i, j + 1 + b);
							int pixel_next_add = dst.at<uchar>(i, j + 1 + b);
							pixel_present_add = ave_bound + step_levels;
							while (j + 2 + b >= 0 && pixel_next_add - pixel_present_add >= step_levels && pixel_next_add - pixel_present_add <= large_dir){
								pixel_next_add = pixel_present_add + step_levels;
								b += 1;
								if (j + 2 + b >= 0){ //图像边界判断
									pixel_present_add = dst.at<uchar>(i, j + 1 + b);
									pixel_next_add = dst.at<uchar>(i, j + 2 + b);
								}
							}
						}
						//垂直于子块边界,向左递减方向( decreasing rule)
						if (j - 2 - b >= 0){ //图像边界判断
							int pixel_present_dec = dst.at<uchar>(i, j - 1 - b);
							int pixel_next_dec = dst.at<uchar>(i, j - 2 - b);
							pixel_present_dec = ave_bound - step_levels;
							while (j - 2 - b >= 0 && pixel_present_dec - pixel_next_dec >= step_levels && pixel_present_dec - pixel_next_dec <= large_dir){
								pixel_next_dec = pixel_present_dec - step_levels;
								b += 1;
								if (j - 2 - b >= 0){ //图像边界判断
									pixel_present_dec = dst.at<uchar>(i, j - 1 - b);
									pixel_next_dec = dst.at<uchar>(i, j - 2 - b);
								}
							}
						}
					}
				}
			}
		}
		j += step_c;
	}
}