C++ OpenCV和像Adobe Photoshop一样的反锐化掩蔽
我正在尝试像在Adobe Photoshop中一样实现反锐化掩蔽。我收集了很多关于互联网的信息,但我不确定我是否遗漏了什么。代码如下:C++ OpenCV和像Adobe Photoshop一样的反锐化掩蔽,c++,opencv,image-processing,reverse-engineering,photoshop,C++,Opencv,Image Processing,Reverse Engineering,Photoshop,我正在尝试像在Adobe Photoshop中一样实现反锐化掩蔽。我收集了很多关于互联网的信息,但我不确定我是否遗漏了什么。代码如下: void unsharpMask( cv::Mat* img, double amount, double radius, double threshold ) { // create blurred img cv::Mat img32F, imgBlur32F, imgHighContrast32F, imgDiff32F, unsharpMas32F, c
void unsharpMask( cv::Mat* img, double amount, double radius, double threshold ) {
// create blurred img
cv::Mat img32F, imgBlur32F, imgHighContrast32F, imgDiff32F, unsharpMas32F, colDelta32F, compRes, compRes32F, prod;
double r = 1.5;
img->convertTo( img32F, CV_32F );
cv::GaussianBlur( img32F, imgBlur32F, cv::Size(0,0), radius );
cv::subtract( img32F, imgBlur32F, unsharpMas32F );
// increase contrast( original, amount percent )
imgHighContrast32F = img32F * amount / 100.0f;
cv::subtract( imgHighContrast32F, img32F, imgDiff32F );
unsharpMas32F /= 255.0f;
cv::multiply( unsharpMas32F, imgDiff32F, colDelta32F );
cv::compare( cv::abs( colDelta32F ), threshold, compRes, cv::CMP_GT );
compRes.convertTo( compRes32F, CV_32F );
cv::multiply( compRes32F, colDelta32F, prod );
cv::add( img32F, prod, img32F );
img32F.convertTo( *img, CV_8U );
}
目前我正在用灰度图像进行测试。如果我在Photoshop中尝试完全相同的参数,我会得到更好的结果。我自己的代码会导致嘈杂的图像。我做错了什么
第二个问题是,如何在RGB图像上应用反锐化遮罩?我是否必须取消锐化3个通道中的每个通道的遮罩,或者在另一个颜色空间中效果更好?这些事情是如何在Photoshop中完成的
谢谢你的帮助 我也在尝试复制Photoshop的反锐化遮罩。 让我们暂时忽略阈值 我将向您展示如何使用高斯模糊复制Photoshop的反锐化遮罩 假设O是原始图像层 创建一个新的层GB,它是应用于O上的高斯模糊。 使用ApplyImage创建一个O-GB的新图层。 通过反转GB-invGB创建新图层。 使用图像应用创建一个新图层,该图层为O+invGB。 创建一个与上一层相反的新层,即invO+invGB。 创建一个新图层,它是O+O-GB-invO+invGB 当你在Photoshop中这样做的时候,你会得到一个完美的非锐化掩模的复制品 如果你重新计算invL=1-L,你会得到反锐化掩模是 USMO=3O-2B 然而,当我直接在MATLAB中这样做时,我并没有得到Photoshop的结果 希望有人会知道确切的数学 使现代化 嗯, 我想出来了。 在Photoshop中USMO=O+2*数量/100*O-GB 其中GB是高斯模糊版本的O
然而,为了复制Photoshop的结果,您必须执行上述步骤,并像在Photoshop中那样将每个步骤的结果剪裁到[0,1]中。我也在尝试复制Photoshop的取消锐化遮罩。 让我们暂时忽略阈值 我将向您展示如何使用高斯模糊复制Photoshop的反锐化遮罩 假设O是原始图像层 创建一个新的层GB,它是应用于O上的高斯模糊。 使用ApplyImage创建一个O-GB的新图层。 通过反转GB-invGB创建新图层。 使用图像应用创建一个新图层,该图层为O+invGB。 创建一个与上一层相反的新层,即invO+invGB。 创建一个新图层,它是O+O-GB-invO+invGB 当你在Photoshop中这样做的时候,你会得到一个完美的非锐化掩模的复制品 如果你重新计算invL=1-L,你会得到反锐化掩模是 USMO=3O-2B 然而,当我直接在MATLAB中这样做时,我并没有得到Photoshop的结果 希望有人会知道确切的数学 使现代化 嗯, 我想出来了。 在Photoshop中USMO=O+2*数量/100*O-GB 其中GB是高斯模糊版本的O 然而,为了复制Photoshop的结果,您必须执行上述步骤,并像在Photoshop中那样将每个步骤的结果剪切到[0,1]中。根据文档: C++:void GaussianBlur输入阵列src、输出阵列dst、大小ksize、, double sigmaX,double sigmaY=0,int borderType=BORDER\u默认值 第四个参数不是半径,而是西格玛-高斯核标准差。半径相当大。无论如何,Photoshop不是开源的,因此我们不能确定他们使用与OpenCV相同的方法从sigma计算半径 渠道 是的,您应该将夏普应用于任何或所有频道,这取决于您的目的。当然,您可以使用任何空间:如果您想要仅夏普亮度组件,并且不想增加颜色噪声,您可以将其转换为HSL或实验室空间,夏普仅L通道Photoshop也有所有这些选项。根据文档: C++:void GaussianBlur输入阵列src、输出阵列dst、大小ksize、, double sigmaX,double sigmaY=0,int borderType=BORDER\u默认值 第四个参数不是半径,而是西格玛-高斯核标准差。半径相当大。无论如何,Photoshop不是开源的,因此我们不能确定他们使用与OpenCV相同的方法从sigma计算半径 渠道
是的,您应该将夏普应用于任何或所有频道,这取决于您的目的。当然,你可以使用任何空间:如果你想要夏普纯亮度组件,不想增加颜色噪声,你可以将其转换为HSL或实验室空间,夏普纯L通道Photoshop也有所有这些选项。以下是我所做的代码。 我正在使用这段代码来实现反锐化掩码,它对我来说工作得很好。 希望对你有用
void USM(cv::Mat &O, int d, int amp, int threshold)
{
cv::Mat GB;
cv::Mat O_GB;
cv::subtract(O, GB, O_GB);
cv::Mat invGB = cv::Scalar(255) - GB;
cv::add(O, invGB, invGB);
invGB = cv::Scalar(255) - invGB;
for (int i = 0; i < O.rows; i++)
{
for (int j = 0; j < O.cols; j++)
{
unsigned char o_rgb = O.at<unsigned char>(i, j);
unsigned char d_rgb = O_GB.at<unsigned char>(i, j);
unsigned char inv_rgb = invGB.at<unsigned char>(i, j);
int newVal = o_rgb;
if (d_rgb >= threshold)
{
newVal = o_rgb + (d_rgb - inv_rgb) * amp;
if (newVal < 0) newVal = 0;
if (newVal > 255) newVal = 255;
}
O.at<unsigned char>(i, j) = unsigned char(newVal);
}
}
}
这是我所做的代码。 我正在使用这段代码来实现反锐化掩码,它对我来说工作得很好。 希望对你有用
void USM(cv::Mat &O, int d, int amp, int threshold)
{
cv::Mat GB;
cv::Mat O_GB;
cv::subtract(O, GB, O_GB);
cv::Mat invGB = cv::Scalar(255) - GB;
cv::add(O, invGB, invGB);
invGB = cv::Scalar(255) - invGB;
for (int i = 0; i < O.rows; i++)
{
for (int j = 0; j < O.cols; j++)
{
unsigned char o_rgb = O.at<unsigned char>(i, j);
unsigned char d_rgb = O_GB.at<unsigned char>(i, j);
unsigned char inv_rgb = invGB.at<unsigned char>(i, j);
int newVal = o_rgb;
if (d_rgb >= threshold)
{
newVal = o_rgb + (d_rgb - inv_rgb) * amp;
if (newVal < 0) newVal = 0;
if (newVal > 255) newVal = 255;
}
O.at<unsigned char>(i, j) = unsigned char(newVal);
}
}
}
作为对@Royi的响应,2x乘数是由于在该公式中假设无箝位而产生的:
USM(Original) = Original + Amount / 100 * ((Original - GB) - (1 - (Original + (1 - GB))))
忽略夹紧,这将导致:
USM(Original) = Original + 2 * Amount / 100 * (Original - GB)
USM(Original) = Original + Amount / 100 * (Original - GB)
但是,正如您所指出的,Original-GB和Origin
al+invGB被钳制到[0,1]:
USM(Original) = Original + Amount / 100 *
(Max(0, Min(1, Original - GB)) - (1 - (Max(0, Min(1, Original + (1 - GB))))))
这正确地归结为:
USM(Original) = Original + 2 * Amount / 100 * (Original - GB)
USM(Original) = Original + Amount / 100 * (Original - GB)
以下是一个示例,说明了原因:
作为对@Royi的响应,2x乘数是由于在该公式中假设无箝位而产生的:
USM(Original) = Original + Amount / 100 * ((Original - GB) - (1 - (Original + (1 - GB))))
忽略夹紧,这将导致:
USM(Original) = Original + 2 * Amount / 100 * (Original - GB)
USM(Original) = Original + Amount / 100 * (Original - GB)
但是,正如您也指出的,Original-GB和Original+invGB被钳制到[0,1]:
USM(Original) = Original + Amount / 100 *
(Max(0, Min(1, Original - GB)) - (1 - (Max(0, Min(1, Original + (1 - GB))))))
这正确地归结为:
USM(Original) = Original + 2 * Amount / 100 * (Original - GB)
USM(Original) = Original + Amount / 100 * (Original - GB)
以下是一个示例,说明了原因:
你是如何在这个公式中找到神奇的2*乘数的?我在pixastic和其他源代码中也看到过同样的数学,但是没有2x乘法,尽管通过理解Photoshop的功能,它们并不假装等于Photoshop。你能看看这个演示吗?我已经实现了你的公式。将其应用于亮度0.299*R+0.587*G+0.114*B。然后发现亮度差用于缩放RBG通道。这么大的不锐化量会导致颜色漂移吗?@Vitaly,我不确定我是否理解你的意思。无论如何,Photoshop将其应用于所有RGB通道。如果只需要亮度,则需要通过转换来实现。@Vitaly,正如我所说,默认情况下,它在所有通道上独立工作。如果只想将其应用于亮度,可以使用混合模式进行,也可以转到实验室,选择L通道,应用并转换回。同样,它对输入图像的所有通道都起作用。你是如何在这个公式中找到神奇的2*乘法器的?我在pixastic和其他源代码中也看到过同样的数学,但是没有2x乘法,尽管通过理解Photoshop的功能,它们并不假装等于Photoshop。你能看看这个演示吗?我已经实现了你的公式。将其应用于亮度0.299*R+0.587*G+0.114*B。然后发现亮度差用于缩放RBG通道。这么大的不锐化量会导致颜色漂移吗?@Vitaly,我不确定我是否理解你的意思。无论如何,Photoshop将其应用于所有RGB通道。如果只需要亮度,则需要通过转换来实现。@Vitaly,正如我所说,默认情况下,它在所有通道上独立工作。如果只想将其应用于亮度,可以使用混合模式进行,也可以转到实验室,选择L通道,应用并转换回。同样,它在输入图像的所有通道上运行。我想你的意思是说转换为HSV,而不是HSL,如果你只想提高亮度的话。V是亮度。L是轻盈。锐化V避免了颜色偏移。我想如果你只想锐化亮度,你的意思是说转换为HSV,而不是HSL。V是亮度。L是轻盈。锐化V避免了颜色偏移。