之前讲述的是通过做直方图均衡化的方法达到增强图像的方法。除此之外,锐化也是常用的一种手段。通过锐化处理之后的图像,可以使得边缘清晰,颜色更鲜明,可以用于进一步提取图像的边缘进行图像分割,区域形状提取等。
0 锐化方法
图像锐化的方法,通常分为基于空间域的微分法和基于频域的高通滤波法,本文暂时只讲述微分法,之后会补充高通滤波法。
微分法的原理其实就是数学的逆运算,通常图像模糊可能是经过平滑处理(平均或积分运算)的原因。所以从数学角度考虑,进行逆运算,即微分运算可在一定程度增强图像。而微分运算其实也属于梯度运算。所以基于微分法的图像锐化其实是基于梯度的一种处理。如果单纯以梯度值(梯度幅值)进行替换,则会破坏图像。
另外,用梯度算子卷积进行微分锐化时,因为算子分为X和Y方向,所以锐化也分X和Y方向,但如果不是特殊说明都是指进行二阶即同时XY运算(所以选择的梯度算子通常是二阶的)。
1 微分算法实现
虽然原理上是基于梯度算子的卷积运算,但是一些细节的处理上还是有不同的方法的。又可以分为三类,基于标准梯度公式,基于锐化算子模板和较为复杂的USIM。
1.1 基于标准梯度公式
正如你能在网上查阅到的绝大多数资料那样,梯度的算法是标准的公式。最终概括如下图。
通常近似为。
之后需要进一步后处理,也有不同的算法可以辅助,如下所述。
0)辅以阀值判断设T为阀值,像素的梯度值大于T,则像素的灰度(或者RGB的分量)加上某一个值(如100),加上某一个值(如100)像素的灰度值(或RGB的分量值)后若大于255,取255。
1)设以某一特定值设t为阀值,像素的梯度值大于T,则像素的灰度(或者RGB的分量)设置为某一定值La。
2)二值化图像设T为阀值,像素的梯度值大于T,则像素的灰度(或者RGB的分量)设置为255,否则设置为0。
1.2 基于算子模板
即设计一个可以满足二阶运算的梯度算子模板,如下图。
-1 | -1 | -1 |
-1 | 12 | -1 |
-1 | -1 | -1 |
后处理的方法,是设计缩放因子scale,其值等于梯度算子中各个值的累加和。在完成卷积运算后,进行scale处理,即除以缩放因子。
另外模板的选取方面,需要选择满足二阶的梯度算子。如下。
如果是基于缩放的后处理方法,那么scale = 12-1-1-1-1-1-1-1-1= 4。通常中心元素的设计需要保证最终的scale大于0。
效果如果下所示。很明显,锐化之后在边缘效果的表示方面得到了增强。
1.3 USM
UnsharpMask。注Photoshop中的USM锐化是一种特例的USM锐化方法。经典的实现方法如下图。y(n,m) = x(n,m) + λ z(n,m)。其中, x(n,m)为输入图像,y(n,m)为输出图像,而z(n,m)为校正信号,一般是通过对x进行高通滤波获取。λ是用于控制增强效果的的一个缩放因子。
其中z(n,m)通常是x(n,m)经过模板卷积运算后的结果。这个模板要求只体现出差异(因为最终像素是它与原像素的累加和),如下所示,中心像素是4不是5。
0 | -1 | 0 |
-1 | 5 | -1 |
0 | -1 | 0 |
而λ则是一个比例值。如下代码片段所示。
void USMSharp(cv::Mat&src_img, cv::Mat&dst_img, double ratio) { cv::Matkernel = (cv::Mat_<int>(3, 3)<< 0, -1, 0, -1, 4, -1, 0, -1, 0); cv::filter2D(src_img,dst_img, -1, kernel); for (inti = 0; i < src_img.rows; ++i) { for (intj = 0; j < src_img.cols; ++j) { for (intk = 0; k < 3; ++k) { int value = src_img.at<cv::Vec3b>(i,j)[k] +ratio * dst_img.at<cv::Vec3b>(i,j)[k]; dst_img.at<cv::Vec3b>(i,j)[k] =cv::saturate_cast<uchar>(value); } } } } |
效果图如下,从上至下从左至右λ分别为0,0.25,0.5,1。
但是这种方法也有一个很明显的缺点,即在图像边缘的地方很容易出现增强过头的现象。同时细细观察,也可以看到引入了噪声。(如右下角的帽子边缘处),因为线性滤波很容易对噪声敏感。
因此又有人提出了另外一些改进的算法,如https://www.ncbi.nlm.nih.gov/pubmed/18255421。
1.3.1 Photoshop中的USM算法
除半径之外又引入了数量、阈值两个参数,其内部算法可以简单。如下所示。
void ps_usm_sharp(cv::Mat&src_img, cv::Mat&dst_img, int radius, int thresh,double ratio) { cv::GaussianBlur(src_img,dst_img, cv::Size(radius,radius), 0, 0); for (inti = 0; i < src_img.rows; ++i) { for (intj = 0; j < src_img.cols; ++j) { for (intk = 0; k < src_img.channels(); ++k) { int value = src_img.at<cv::Vec3b>(i,j)[k]; int diff = src_img.at<cv::Vec3b>(i,j)[k] -dst_img.at<cv::Vec3b>(i,j)[k]; diff = diff < 0 ? -diff : diff; if (diff >=thresh) { value =src_img.at<cv::Vec3b>(i,j)[k] +ratio * dst_img.at<cv::Vec3b>(i,j)[k]; } dst_img.at<cv::Vec3b>(i,j)[k] =cv::saturate_cast<uchar>(value); } } } } |
固定thresh为0,ratio为0.5;从上至下,从左至右,原图,以及radius分别设置为3,5,9的图。如下所示。