一、为什么要用USM锐化?
上一篇讲拉普拉斯锐化,不能提供精细的调整,在photoshop中采用USM(Unsharp mask)可以进一步优化。目的是:
- 可以微调锐化程度
- 设置锐化阈值,想针对边界更清晰的点锐化处理,这个清晰程度就是锐化阈值
二、USM锐化原理
第一步:对原图进行模糊,然后用原图 - 模糊图,得到一张差值,差值即像素颜色突变的点,即边界
第二步:原图 差值,即边界处得到增强
从信号处理的角度理解:
三、代码实现分析
- 定义强度amount[0, 100],处理到[0, 128]的范围,0-100对用户更好理解 amount = amount * 128 / 100;
- 对原图生成高斯模糊图 FastGaussFilter(gaussData, width, height, stride, radius);
- 遍历图片像素,生成一张遮罩pMask // 大于 阈值threshold pMask对应的点设置成128, 否则设置成0
for(j = 0; j < height; j )
{
for(i = 0; i < width; i )
{
pMask[0] = abs(pSrc[0] - pDst[0]) < threshold ? 0 : 128;
pMask[1] = abs(pSrc[1] - pDst[1]) < threshold ? 0 : 128;
pMask[2] = abs(pSrc[2] - pDst[2]) < threshold ? 0 : 128;
pDst = 4;
pSrc = 4;
pMask = 4;
}
pDst = offset;
pSrc = offset;
pMask = offset;
}
- 锐化增强 // 计算像素差 // 原图 像素差 * 系数 (amount决定),到这一步就能看到效果了 // 针对阈值做处理,根据前面生成的pMask遮罩,pMask[0|1|2] == 0则不增强,使用原像素pSrc[0|1|2] (注意 * 128 >> 7 == 1),pMask[0|1|2] == 128,则增强,采用rgb * pMask[0|1|2] >> 7,即rgb * 系数
for(j = 0; j < height; j )
{
for(i = 0; i < width; i )
{
// 计算像素差
b = pSrc[0] - pDst[0];
g = pSrc[1] - pDst[1];
r = pSrc[2] - pDst[2];
// 原值 像素差 * 系数 (amount >> 7 == [0, 128]/128 == [0, 1.0])
// 即得到 rgb = 原值 像素差 * [0, 1]
b = (pSrc[0] ((b * amount) >> 7));
g = (pSrc[1] ((g * amount) >> 7));
r = (pSrc[2] ((r * amount) >> 7));
b = (b * pMask[0] pSrc[0] * (128 - pMask[0])) >> 7;
g = (g * pMask[1] pSrc[1] * (128 - pMask[1])) >> 7;
r = (r * pMask[2] pSrc[2] * (128 - pMask[2])) >> 7;
pSrc[0] = CLIP3(b, 0, 255);
pSrc[1] = CLIP3(g, 0, 255);
pSrc[2] = CLIP3(r, 0, 255);
pSrc = 4;
pDst = 4;
pMask = 4;
}
pSrc = offset;
pDst = offset;
pMask = offset;
}
补充,在最后一步锐化处理前,对mask进行了一次高斯模糊,目的是将遮罩均匀到图像边缘,过渡更自然,“0” 和 “128”过于绝对,锐化的效果太尖锐,这里不明白的,参考下面完整代码
完整代码:
代码语言:javascript复制#include"f_USM.h"
#include"f_GaussFilter.h"
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include"Commen.h"
int f_USM(unsigned char* srcData,int width, int height,int stride,int radius, int amount, int threshold)
{
int ret = 0;
if(radius == 0)
return ret;
radius = CLIP3(radius, 0, 100);
amount = CLIP3(amount, 0,500);
threshold = CLIP3(threshold, 0,255);
unsigned char* gaussData = (unsigned char*)malloc(sizeof(unsigned char) * height * stride);
memcpy(gaussData, srcData, sizeof(unsigned char) * height * stride);
f_FastGaussFilter(gaussData, width, height, stride, radius);
int i, j, r, g, b, offset;
offset = stride - width * 4;
// 将 amount 均匀到[0, 128] 的范围内,如果输入值是[0, 100]
// 128有什么特殊的含义呢?128 = 256 / 2,即RGB色值的一半
// 一半是锐化的临界点
amount = amount * 128 / 100;
unsigned char* pSrc = srcData;
unsigned char* pDst = gaussData;
unsigned char* maskData = (unsigned char*)malloc(sizeof(unsigned char) * height * stride);
unsigned char* pMask = maskData;
for(j = 0; j < height; j )
{
for(i = 0; i < width; i )
{
pMask[0] = abs(pSrc[0] - pDst[0]) < threshold ? 0 : 128;
pMask[1] = abs(pSrc[1] - pDst[1]) < threshold ? 0 : 128;
pMask[2] = abs(pSrc[2] - pDst[2]) < threshold ? 0 : 128;
pDst = 4;
pSrc = 4;
pMask = 4;
}
pDst = offset;
pSrc = offset;
pMask = offset;
}
pDst = gaussData;
pSrc = srcData;
pMask = maskData;
f_FastGaussFilter(maskData, width, height, stride, radius);
for(j = 0; j < height; j )
{
for(i = 0; i < width; i )
{
// 计算像素差
b = pSrc[0] - pDst[0];
g = pSrc[1] - pDst[1];
r = pSrc[2] - pDst[2];
// 原值 像素差 * 系数 (amount >> 7 == [0, 128]/128 == [0, 1.0])
// 即得到 rgb = 原值 像素差 * [0, 1]
b = (pSrc[0] ((b * amount) >> 7));
g = (pSrc[1] ((g * amount) >> 7));
r = (pSrc[2] ((r * amount) >> 7));
b = (b * pMask[0] pSrc[0] * (128 - pMask[0])) >> 7;
g = (g * pMask[1] pSrc[1] * (128 - pMask[1])) >> 7;
r = (r * pMask[2] pSrc[2] * (128 - pMask[2])) >> 7;
pSrc[0] = CLIP3(b, 0, 255);
pSrc[1] = CLIP3(g, 0, 255);
pSrc[2] = CLIP3(r, 0, 255);
pSrc = 4;
pDst = 4;
pMask = 4;
}
pSrc = offset;
pDst = offset;
pMask = offset;
}
free(gaussData);
free(maskData);
return ret;
};
参考:https://baijiahao.baidu.com/s?id=1651538317157891526&wfr=spider&for=pc