摸索了两天,终于把等高线效果做出来了,摸索的过程也有记录的意义。下面开始。
等高线滤镜有色阶、较低、较高三个控制项,根据PS书籍记载,选择"较低"选项时将在基准亮度以下的轮廓上产生等高线,反之,在基准亮度以上的轮廓上产生等高线,这里的基准亮度就是指色阶。根据描述,可知这里进行了阈值处理,可以确定选择“较低”选项时,高于基准亮度的部分会被忽略,即置零,至于低于基准亮度的部分是保持不变还是置为统一值,还不能下结论,下面我们使用photoshop对一张图片应用等高线滤镜,观察结果以得出跟进一步的结论。设置色阶为128,较低,如下所示:
首先可以看到结果是一幅边缘图像,简单起见,直接调用Canny算法实现这个效果;其次,背景为白色,说明进行了反色处理;最后,处理结果中的颜色数量很少,只有黑,白,红,绿,蓝,黄(红绿组合),品红(红蓝组合),青(绿蓝组合)这8种,可见像素各通道的值只有两种(0和255),通过软件读取图像像素值可以发现确实如此,由此可以得出结论,进行阈值处理时,一部分像素被置零,另一部分被置为255,而不是保持不变,可见,等高线滤镜的本质是以基准色阶为界限,将图像分为明暗两部分,它们的分界线就是滤镜处理的结果。
等高线滤镜处理步骤:阈值处理;求边缘;反色。代码如下:
#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
int main()
{
int TH = 128; //基准色阶
int flag = 0; //0: 较低 其他:较高
cv::Mat img = cv::imread("D:\\timg.jpg");
cv::Mat Result;
vector<cv::Mat> channels, outline(3);
cv::ThresholdTypes mode;
cv::split(img, channels);
if (flag == 0)
{
TH--; //PS精确观察结果,不自减对结果影响不大
mode = cv::THRESH_BINARY_INV;
}
else
{
mode = cv::THRESH_BINARY;
}
cv::threshold(channels[0], channels[0], TH, 255, mode);
cv::threshold(channels[1], channels[1], TH, 255, mode);
cv::threshold(channels[2], channels[2], TH, 255, mode);
cv::Canny(channels[0], outline[0], 255, 255);
cv::Canny(channels[1], outline[1], 255, 255);
cv::Canny(channels[2], outline[2], 255, 255);
cv::merge(outline, Result);
Result = cv::Scalar(255, 255, 255) - Result;
cv::imshow("result", Result);
cv::waitKey(200000);
return 0;
}
处理结果
与photoshop的处理结果在细微处略有差别,可能是边缘算法上有所区别,但总体上是基本一致的。