当前位置:   article > 正文

Opencv C++图像处理:亮度+对比度+饱和度+高光+暖色调+阴影+漫画效果+白平衡+浮雕+羽化+锐化+颗粒感_c++对比度调整

c++对比度调整

更多详细信息请看:OpenCV专栏:翟天保Steven

一、多功能色彩调整

1.1、亮度

在这里插入图片描述

//--------------------------------------------------------------------------------
// 亮度与对比度
cv::Mat Brightness(cv::Mat src, float brightness, int contrast)
{
	cv::Mat dst;
    dst = cv::Mat::zeros(src.size(), src.type());		//新建空白模板:大小/类型与原图像一致,像素值全0。
    int height = src.rows;								//获取图像高度
    int width = src.cols;								//获取图像宽度
    float alpha = brightness;							//亮度(0~1为暗,1~正无穷为亮)
    float beta = contrast;								//对比度

    cv::Mat template1;
    src.convertTo(template1, CV_32F);					//将CV_8UC1转换为CV32F1数据格式。
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            if (src.channels() == 3)
            {
                float b = template1.at<cv::Vec3f>(row, col)[0];		//获取通道的像素值(blue)
                float g = template1.at<cv::Vec3f>(row, col)[1];		//获取通道的像素值(green)
                float r = template1.at<cv::Vec3f>(row, col)[2];		//获取通道的像素值(red)

                //cv::saturate_cast<uchar>(vaule):需注意,value值范围必须在0~255之间。
                dst.at<cv::Vec3b>(row, col)[0] = cv::saturate_cast<uchar>(b * alpha + beta);		//修改通道的像素值(blue)
                dst.at<cv::Vec3b>(row, col)[1] = cv::saturate_cast<uchar>(g * alpha + beta);		//修改通道的像素值(green)
                dst.at<cv::Vec3b>(row, col)[2] = cv::saturate_cast<uchar>(r * alpha + beta);		//修改通道的像素值(red)
            }
            else if (src.channels() == 1)
            {
                float v = src.at<uchar>(row, col);											//获取通道的像素值(单)
                dst.at<uchar>(row, col) = cv::saturate_cast<uchar>(v * alpha + beta);		//修改通道的像素值(单)
				//saturate_cast<uchar>:主要是为了防止颜色溢出操作。如果color<0,则color等于0;如果color>255,则color等于255。
            }
        }
    }
    return dst;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

1.2、对比度

在这里插入图片描述

//--------------------------------------------------------------------------------
// 亮度与对比度
cv::Mat Brightness(cv::Mat src, float brightness, int contrast)
{
	cv::Mat dst;
    dst = cv::Mat::zeros(src.size(), src.type());		//新建空白模板:大小/类型与原图像一致,像素值全0。
    int height = src.rows;								//获取图像高度
    int width = src.cols;								//获取图像宽度
    float alpha = brightness;							//亮度(0~1为暗,1~正无穷为亮)
    float beta = contrast;								//对比度

    cv::Mat template1;
    src.convertTo(template1, CV_32F);					//将CV_8UC1转换为CV32F1数据格式。
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            if (src.channels() == 3)
            {
                float b = template1.at<cv::Vec3f>(row, col)[0];		//获取通道的像素值(blue)
                float g = template1.at<cv::Vec3f>(row, col)[1];		//获取通道的像素值(green)
                float r = template1.at<cv::Vec3f>(row, col)[2];		//获取通道的像素值(red)

                //cv::saturate_cast<uchar>(vaule):需注意,value值范围必须在0~255之间。
                dst.at<cv::Vec3b>(row, col)[0] = cv::saturate_cast<uchar>(b * alpha + beta);		//修改通道的像素值(blue)
                dst.at<cv::Vec3b>(row, col)[1] = cv::saturate_cast<uchar>(g * alpha + beta);		//修改通道的像素值(green)
                dst.at<cv::Vec3b>(row, col)[2] = cv::saturate_cast<uchar>(r * alpha + beta);		//修改通道的像素值(red)
            }
            else if (src.channels() == 1)
            {
                float v = src.at<uchar>(row, col);											//获取通道的像素值(单)
                dst.at<uchar>(row, col) = cv::saturate_cast<uchar>(v * alpha + beta);		//修改通道的像素值(单)
				//saturate_cast<uchar>:主要是为了防止颜色溢出操作。如果color<0,则color等于0;如果color>255,则color等于255。
            }
        }
    }
    return dst;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

1.3、饱和度

在这里插入图片描述

//--------------------------------------------------------------------------------
// 饱和度
cv::Mat Saturation(cv::Mat src, int saturation)
{
	float Increment = saturation * 1.0f / 100;
	cv::Mat temp = src.clone();
	int row = src.rows;
	int col = src.cols;
	for (int i = 0; i < row; ++i)
	{
		uchar *t = temp.ptr<uchar>(i);
		uchar *s = src.ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			uchar b = s[3 * j];
			uchar g = s[3 * j + 1];
			uchar r = s[3 * j + 2];
			float max = max3(r, g, b);
			float min = min3(r, g, b);
			float delta, value;
			float L, S, alpha;
			delta = (max - min) / 255;
			if (delta == 0)
				continue;
			value = (max + min) / 255;
			L = value / 2;
			if (L < 0.5)
				S = delta / value;
			else
				S = delta / (2 - value);
			if (Increment >= 0)
			{
				if ((Increment + S) >= 1)
					alpha = S;
				else
					alpha = 1 - Increment;
				alpha = 1 / alpha - 1;
				t[3 * j + 2] =static_cast<uchar>( r + (r - L * 255) * alpha);
				t[3 * j + 1] = static_cast<uchar>(g + (g - L * 255) * alpha);
				t[3 * j] = static_cast<uchar>(b + (b - L * 255) * alpha);
			}
			else
			{
				alpha = Increment;
				t[3 * j + 2] = static_cast<uchar>(L * 255 + (r - L * 255) * (1 + alpha));
				t[3 * j + 1] = static_cast<uchar>(L * 255 + (g - L * 255) * (1 + alpha));
				t[3 * j] = static_cast<uchar>(L * 255 + (b - L * 255) * (1 + alpha));
			}
		}
	}
	return temp;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

1.4、高光

在这里插入图片描述

//--------------------------------------------------------------------------------
// 高光
cv::Mat HighLight(cv::Mat src, int highlight)
{
	// 生成灰度图
	cv::Mat gray = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat f = src.clone();
	f.convertTo(f, CV_32FC3);
	std::vector<cv::Mat> pics;
	split(f, pics);
	gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
	gray = gray / 255.f;
 
	// 确定高光区
	cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());
	thresh = gray.mul(gray);
	// 取平均值作为阈值
	cv::Scalar t = mean(thresh);
	cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
	mask.setTo(255, thresh >= t[0]);
 
	// 参数设置
	int max = 4;
	float bright = highlight / 100.0f / max;
	float mid = 1.0f + max * bright;
 
	// 边缘平滑过渡
	cv::Mat midrate = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat brightrate = cv::Mat::zeros(src.size(), CV_32FC1);
	for (int i = 0; i < src.rows; ++i)
	{
		uchar *m = mask.ptr<uchar>(i);
		float *th = thresh.ptr<float>(i);
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			if (m[j] == 255)
			{
				mi[j] = mid;
				br[j] = bright;
			}
			else {
				mi[j] = (mid - 1.0f) / t[0] * th[j] + 1.0f;
				br[j] = (1.0f / t[0] * th[j])*bright;
			}
		}
	}
 
	// 高光提亮,获取结果图
	cv::Mat result = cv::Mat::zeros(src.size(), src.type());
	for (int i = 0; i < src.rows; ++i)
	{
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		uchar *in = src.ptr<uchar>(i);
		uchar *r = result.ptr<uchar>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));
				if (temp > 1.0f)
					temp = 1.0f;
				if (temp < 0.0f)
					temp = 0.0f;
				uchar utemp = uchar(255*temp);
				r[3 * j + k] = utemp;
			}
 
		}
	}
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

1.5、暖色调

在这里插入图片描述

//--------------------------------------------------------------------------------
// 暖色调
cv::Mat ColorTemperature(cv::Mat src, int warm)
{
	cv::Mat result = src.clone();
	int row = src.rows;
	int col = src.cols;
	int level = warm/2;
	for (int i = 0; i < row; ++i)
	{
		uchar* a = src.ptr<uchar>(i);
		uchar* r = result.ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int R,G,B;
			// R通道
			R = a[j * 3 + 2];
			R = R + level;
			if (R > 255) {
				r[j * 3 + 2] = 255;
			}
			else if (R < 0) {
				r[j * 3 + 2] = 0;
			}
			else {
				r[j * 3 + 2] = R;
			}
			// G通道
			G = a[j * 3 + 1];
			G = G + level;
			if (G > 255) {
				r[j * 3 + 1] = 255;
			}
			else if (G < 0) {
				r[j * 3 + 1] = 0;
			}
			else {
				r[j * 3 + 1] = G;
			}
			// B通道
			B = a[j * 3];
			B = B - level;
			if (B > 255) {
				r[j * 3] = 255;
			}
			else if (B < 0) {
				r[j * 3] = 0;
			}
			else {
				r[j * 3] = B;
			}
		}
	}
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

1.6、阴影

在这里插入图片描述

//--------------------------------------------------------------------------------
// 阴影
cv::Mat Shadow(cv::Mat src, int shadow)
{
	// 生成灰度图
	cv::Mat gray = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat f = src.clone();
	f.convertTo(f, CV_32FC3);
	std::vector<cv::Mat> pics;
	split(f, pics);
	gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
	gray = gray / 255.f;
 
	// 确定阴影区
	cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());	
	thresh = (1.0f - gray).mul(1.0f - gray);
	// 取平均值作为阈值
	cv::Scalar t = mean(thresh);
	cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
	mask.setTo(255, thresh >= t[0]);
 
	// 参数设置
	int max = 4;
	float bright = shadow / 100.0f / max;
	float mid = 1.0f + max * bright;
 
	// 边缘平滑过渡
	cv::Mat midrate = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat brightrate = cv::Mat::zeros(src.size(), CV_32FC1);
	for (int i = 0; i < src.rows; ++i)
	{
		uchar *m = mask.ptr<uchar>(i);
		float *th = thresh.ptr<float>(i);
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			if (m[j] == 255)
			{
				mi[j] = mid;
				br[j] = bright;
			}
			else {
				mi[j] = (mid - 1.0f) / t[0] * th[j]+ 1.0f;   
				br[j] = (1.0f / t[0] * th[j])*bright;               
			}
		}
	}
 
	// 阴影提亮,获取结果图
	cv::Mat result = cv::Mat::zeros(src.size(), src.type());
	for (int i = 0; i < src.rows; ++i)
	{
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		uchar *in = src.ptr<uchar>(i);
		uchar *r = result.ptr<uchar>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));
				if (temp > 1.0f)
					temp = 1.0f;
				if (temp < 0.0f)
					temp = 0.0f;
				uchar utemp = uchar(255*temp);
				r[3 * j + k] = utemp;
			}
 
		}
	}
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

1.7、漫画效果

在这里插入图片描述

//--------------------------------------------------------------------------------
// 漫画效果
cv::Mat Cartoon(cv::Mat src, double clevel, int d, double sigma, int size)
{
	// 中值滤波
	cv::Mat m;
	cv::medianBlur(src, m, 7);
	// 提取轮廓
	cv::Mat c;
	clevel = cv::max(40., cv::min(80., clevel));
	cv::Canny(m, c, clevel, clevel *3);
	// 轮廓膨胀加深
	cv::Mat k = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));
	cv::dilate(c, c, k);
	// 反转
	c = c / 255;
	c = 1 - c;
	// 类型转化
	cv::Mat cf;
	c.convertTo(cf, CV_32FC1);
	// 均值滤波
	cv::blur(cf, cf, cv::Size(5, 5));
	// 双边滤波
	cv::Mat srcb;
	d = cv::max(0, cv::min(10, d));
	sigma = cv::max(10., cv::min(250., sigma));
	cv::bilateralFilter(src, srcb, d, sigma, sigma);
	size = cv::max(10, cv::min(25, size));
	cv::Mat temp = srcb / size;
	temp = temp * size;
	// 通道合并
	cv::Mat c3;
	cv::Mat cannyChannels[] = { cf, cf, cf };
	cv::merge(cannyChannels, 3, c3);
	// 类型转化
	cv::Mat tempf;
	temp.convertTo(tempf, CV_32FC3);
	// 图像相乘
	cv::multiply(tempf, c3, tempf);
	// 类型转化
	tempf.convertTo(temp, CV_8UC3);
	return temp;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

1.8、白平衡-灰度世界

在这里插入图片描述

//--------------------------------------------------------------------------------
// 白平衡-灰度世界
cv::Mat WhiteBalcane_Gray(cv::Mat src)
{
	cv::Mat result = src.clone();
	if (src.channels() != 3)
	{
		std::cout << "The number of image channels is not 3." << std::endl;
		return result;
	}
 
	// 通道分离
	std::vector<cv::Mat> Channel;
	cv::split(src, Channel);
 
	// 计算通道灰度值均值
	double Bm = cv::mean(Channel[0])[0];
	double Gm = cv::mean(Channel[1])[0];
	double Rm = cv::mean(Channel[2])[0];
	double Km = (Bm + Gm + Rm) / 3;
 
	// 通道灰度值调整
	Channel[0] *= Km / Bm;
	Channel[1] *= Km / Gm;
	Channel[2] *= Km / Rm;
 
	// 合并通道
	cv::merge(Channel, result);
 
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

1.9、白平衡-完美反射

在这里插入图片描述

//--------------------------------------------------------------------------------
// 白平衡-完美反射
cv::Mat WhiteBalcane_PRA(cv::Mat src)
{
	cv::Mat result = src.clone();
	if (src.channels() != 3)
	{
		std::cout << "The number of image channels is not 3." << std::endl;
		return result;
	}
 
	// 通道分离
	std::vector<cv::Mat> Channel;
	cv::split(src, Channel);
 
	// 定义参数
	int row = src.rows;
	int col = src.cols;
	int RGBSum[766] = { 0 };
	uchar maxR, maxG, maxB;
 
	// 计算单通道最大值
	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			RGBSum[sum]++;
			maxB = cv::max(maxB, b[j]);
			maxG = cv::max(maxG, g[j]);
			maxR = cv::max(maxR, r[j]);
		}
	}
 
	// 计算最亮区间下限T
	int T = 0;
	int num = 0;
	int K = static_cast<int>(row * col * 0.1);
	for (int i = 765; i >= 0; --i)
	{
		num += RGBSum[i];
		if (num > K)
		{
			T = i;
			break;
		}
	}
	
	// 计算单通道亮区平均值
	double Bm = 0.0, Gm = 0.0, Rm = 0.0;
	int count = 0;
	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			if (sum > T)
			{
				Bm += b[j];
				Gm += g[j];
				Rm += r[j];
				count++;
			}
		}
	}
	Bm /= count;
	Gm /= count;
	Rm /= count;
 
	// 通道调整
	Channel[0] *= maxB / Bm;
	Channel[1] *= maxG / Gm;
	Channel[2] *= maxR / Rm;
 
	// 合并通道
	cv::merge(Channel, result);
 
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

1.10、浮雕

在这里插入图片描述

//--------------------------------------------------------------------------------
// 浮雕
cv::Mat Relief(cv::Mat src)
{
	CV_Assert(src.channels() == 3);
	int row = src.rows;
	int col = src.cols;
	cv::Mat temp = src.clone();
	for (int i = 1; i < row-1; ++i)
	{
		uchar *s1 = src.ptr<uchar>(i - 1);
		uchar *s2 = src.ptr<uchar>(i + 1);
		uchar *t = temp.ptr<uchar>(i);
		for (int j = 1; j < col-1; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				int RGB = s1[3 * (j - 1) + k] - s2[3 * (j + 1) + k] + 128;
				if (RGB < 0)RGB = 0;
				if (RGB > 255)RGB = 255;
				t[3*j+k] =(uchar)RGB;
			}
		}
	}
	return temp;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

1.11、羽化

在这里插入图片描述

//--------------------------------------------------------------------------------
// 羽化
cv::Mat Eclosion(cv::Mat src, cv::Point center, float level)
{
	if (level > 0.9)
		level = 0.9f;
	float diff = (1-level) * (src.rows / 2 * src.rows / 2 + src.cols / 2 * src.cols / 2);
	cv::Mat result = src.clone();
	for (int i = 0; i < result.rows; ++i)
	{
		for (int j = 0; j < result.cols; ++j)
		{
			float dx = float(center.x - j);
			float dy = float(center.y - i);
			float ra = dx * dx + dy * dy;
			float m = ((ra-diff) / diff * 255)>0? ((ra - diff) / diff * 255):0;
			int b = result.at<cv::Vec3b>(i, j)[0];
			int g = result.at<cv::Vec3b>(i, j)[1];
			int r = result.at<cv::Vec3b>(i, j)[2];
			b = (int)(b+ m);
			g = (int)(g + m);
			r = (int)(r + m);
			result.at<cv::Vec3b>(i, j)[0] = (b > 255 ? 255 : (b < 0 ? 0 : b));
			result.at<cv::Vec3b>(i, j)[1] = (g > 255 ? 255 : (g < 0 ? 0 : g));
			result.at<cv::Vec3b>(i, j)[2] = (r > 255 ? 255 : (r < 0 ? 0 : r));
		}
	}
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

1.12、锐化

在这里插入图片描述

//--------------------------------------------------------------------------------
// 锐化
cv::Mat Sharpen(cv::Mat input, int percent, int type)
{
	cv::Mat result;
	cv::Mat s = input.clone();
	cv::Mat kernel;
	switch (type)
	{
	case 0:
		kernel = (cv::Mat_<int>(3, 3) <<
			0, -1, 0,
			-1, 4, -1,
			0, -1, 0
			);
	case 1:
		kernel = (cv::Mat_<int>(3, 3) <<
			-1, -1, -1,
			-1, 8, -1,
			-1, -1, -1
			);
	default:
		kernel = (cv::Mat_<int>(3, 3) <<
			0, -1, 0,
			-1, 4, -1,
			0, -1, 0
			);
	}
	cv::filter2D(s, s, s.depth(), kernel);
	result = input + s * 0.01 * percent;
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

1.13、颗粒感

在这里插入图片描述

//--------------------------------------------------------------------------------
// 颗粒感
cv::Mat Grainy(cv::Mat src, int level)
{
	int row = src.rows;
	int col = src.cols;
	if (level > 100)
		level = 100;
	if (level < 0)
		level = 0;
	cv::Mat result = src.clone();
	for (int i = 0; i < row; ++i)
	{
		uchar *t = result.ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				int temp = t[3 * j + k];
				temp += ((rand() % (2 * level)) - level);
				if (temp < 0)temp = 0;
				if (temp > 255)temp = 255;
				t[3 * j + k] = temp;
			}
		}
	}
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

二、实战案例

2.1、主函数

在这里插入图片描述

#include<opencv2\opencv.hpp>
//using namespace cv;
//using namespace std;

#define max2(a,b) (a>b?a:b)
#define max3(a,b,c) (a>b?max2(a,c):max2(b,c))
#define min2(a,b) (a<b?a:b)
#define min3(a,b,c) (a<b?min2(a,c):min2(b,c))

//函数申明
cv::Mat Brightness(cv::Mat src, float brightness, int contrast);				//亮度+对比度。
cv::Mat Saturation(cv::Mat src, int saturation);								//饱和度
cv::Mat HighLight(cv::Mat src, int highlight);									//高光
cv::Mat ColorTemperature(cv::Mat src, int warm);								//暖色调
cv::Mat Shadow(cv::Mat src, int shadow);										//阴影

cv::Mat Sharpen(cv::Mat input, int percent, int type);							//图像锐化
cv::Mat Grainy(cv::Mat src, int level);											//颗粒感
cv::Mat Cartoon(cv::Mat src, double clevel, int d, double sigma, int size);		//漫画效果
cv::Mat WhiteBalcane_PRA(cv::Mat src);											//白平衡-完美反射算法(效果偏白)
cv::Mat WhiteBalcane_Gray(cv::Mat src);											//白平衡-灰度世界算法(效果偏蓝)
cv::Mat Relief(cv::Mat src);													//浮雕
cv::Mat Eclosion(cv::Mat src, cv::Point center, float level);					//羽化


int main(int argc, char* argv[])
{
	//(1)读取图像
	std::string img_path = "test.jpg";
	cv::Mat src = cv::imread(img_path, 1);

	//(2)判断图像是否读取成功
	if (!src.data)
	{
		std::cout << "can't read image!" << std::endl;
		return -1;
	}

	float brightness_value = 1;		//[0, 10]			亮度。暗~亮:[0, 1] ~ [1, 10]
	int contrast_value = 0;			//[-100, 100]		对比度。
	int saturation_value = 0;		//[-100, 100]		饱和度。
	int highlight_value = 0;		//[-100, 100]		高光。
	int warm_value = 0;				//[-100, 100]		暖色调。
	int shadow_value = 0;			//[-100, 100]		阴影。
	int sharpen_value = 0;			//[-100, 100]		锐化。[-1000000, 1000000]
	int grainy_value = 0;			//[0, 100]			颗粒感。

	int eclosion_flag = 0;			//[0, 1]			羽化。
	int cartoon_flag = 0;			//[0, 1]			漫画效果。clevel阈值40-80,d阈值0-10,sigma阈值10-250,size阈值10-25
	int reflect_flag = 0;			//[0, 1]			白平衡-完美反射。
	int world_flag = 0;				//[0, 1]			白平衡-灰度世界。
	int relief_flag = 0;			//[0, 1]			浮雕。


	cv::Mat dst = src.clone();
	if (brightness_value != 1)
		dst = Brightness(dst, brightness_value, 0);
	if (contrast_value != 0)
		dst = Brightness(dst, 1, contrast_value);
	if (saturation_value != 0)
		dst = Saturation(dst, saturation_value);
	if (highlight_value != 0)
		dst = HighLight(dst, highlight_value);
	if (warm_value != 0)
		dst = ColorTemperature(dst, warm_value);
	if (shadow_value != 0)
		dst = Shadow(dst, shadow_value);
	if (sharpen_value != 0)
		dst = Sharpen(dst, sharpen_value, 0);
	if (grainy_value != 0)
		dst = Grainy(dst, grainy_value);

	if (cartoon_flag != 0)
		dst = Cartoon(dst, 80, 5, 150, 20);		//clevel阈值40-80,d阈值0-10,sigma阈值10-250,size阈值10-25说
	if (reflect_flag != 0)
		dst = WhiteBalcane_PRA(dst);
	if (world_flag != 0)
		dst = WhiteBalcane_Gray(dst);
	if (relief_flag != 0)
		dst = Relief(dst);
	if (eclosion_flag != 0)
		dst = Eclosion(dst, cv::Point(src.cols / 2, src.rows / 2), 0.8f);


	//(4)显示图像
	cv::imshow("src", src);
	cv::imshow("锐化", dst);
	cv::waitKey(0);		//等待用户任意按键后结束暂停功能
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

2.2、函数定义

//--------------------------------------------------------------------------------
//调整对比度与亮度
cv::Mat Brightness(cv::Mat src, float brightness, int contrast)
{
	cv::Mat dst;
    dst = cv::Mat::zeros(src.size(), src.type());		//新建空白模板:大小/类型与原图像一致,像素值全0。
    int height = src.rows;								//获取图像高度
    int width = src.cols;								//获取图像宽度
    float alpha = brightness;							//亮度(0~1为暗,1~正无穷为亮)
    float beta = contrast;								//对比度

    cv::Mat template1;
    src.convertTo(template1, CV_32F);					//将CV_8UC1转换为CV32F1数据格式。
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            if (src.channels() == 3)
            {
                float b = template1.at<cv::Vec3f>(row, col)[0];		//获取通道的像素值(blue)
                float g = template1.at<cv::Vec3f>(row, col)[1];		//获取通道的像素值(green)
                float r = template1.at<cv::Vec3f>(row, col)[2];		//获取通道的像素值(red)

                //cv::saturate_cast<uchar>(vaule):需注意,value值范围必须在0~255之间。
                dst.at<cv::Vec3b>(row, col)[0] = cv::saturate_cast<uchar>(b * alpha + beta);		//修改通道的像素值(blue)
                dst.at<cv::Vec3b>(row, col)[1] = cv::saturate_cast<uchar>(g * alpha + beta);		//修改通道的像素值(green)
                dst.at<cv::Vec3b>(row, col)[2] = cv::saturate_cast<uchar>(r * alpha + beta);		//修改通道的像素值(red)
            }
            else if (src.channels() == 1)
            {
                float v = src.at<uchar>(row, col);											//获取通道的像素值(单)
                dst.at<uchar>(row, col) = cv::saturate_cast<uchar>(v * alpha + beta);		//修改通道的像素值(单)
				//saturate_cast<uchar>:主要是为了防止颜色溢出操作。如果color<0,则color等于0;如果color>255,则color等于255。
            }
        }
    }
    return dst;
}

//--------------------------------------------------------------------------------
// 饱和度
cv::Mat Saturation(cv::Mat src, int saturation)
{
	float Increment = saturation * 1.0f / 100;
	cv::Mat temp = src.clone();
	int row = src.rows;
	int col = src.cols;
	for (int i = 0; i < row; ++i)
	{
		uchar *t = temp.ptr<uchar>(i);
		uchar *s = src.ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			uchar b = s[3 * j];
			uchar g = s[3 * j + 1];
			uchar r = s[3 * j + 2];
			float max = max3(r, g, b);
			float min = min3(r, g, b);
			float delta, value;
			float L, S, alpha;
			delta = (max - min) / 255;
			if (delta == 0)
				continue;
			value = (max + min) / 255;
			L = value / 2;
			if (L < 0.5)
				S = delta / value;
			else
				S = delta / (2 - value);
			if (Increment >= 0)
			{
				if ((Increment + S) >= 1)
					alpha = S;
				else
					alpha = 1 - Increment;
				alpha = 1 / alpha - 1;
				t[3 * j + 2] =static_cast<uchar>( r + (r - L * 255) * alpha);
				t[3 * j + 1] = static_cast<uchar>(g + (g - L * 255) * alpha);
				t[3 * j] = static_cast<uchar>(b + (b - L * 255) * alpha);
			}
			else
			{
				alpha = Increment;
				t[3 * j + 2] = static_cast<uchar>(L * 255 + (r - L * 255) * (1 + alpha));
				t[3 * j + 1] = static_cast<uchar>(L * 255 + (g - L * 255) * (1 + alpha));
				t[3 * j] = static_cast<uchar>(L * 255 + (b - L * 255) * (1 + alpha));
			}
		}
	}
	return temp;
}

//--------------------------------------------------------------------------------
// 高光
cv::Mat HighLight(cv::Mat src, int highlight)
{
	// 生成灰度图
	cv::Mat gray = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat f = src.clone();
	f.convertTo(f, CV_32FC3);
	std::vector<cv::Mat> pics;
	split(f, pics);
	gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
	gray = gray / 255.f;
 
	// 确定高光区
	cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());
	thresh = gray.mul(gray);
	// 取平均值作为阈值
	cv::Scalar t = mean(thresh);
	cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
	mask.setTo(255, thresh >= t[0]);
 
	// 参数设置
	int max = 4;
	float bright = highlight / 100.0f / max;
	float mid = 1.0f + max * bright;
 
	// 边缘平滑过渡
	cv::Mat midrate = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat brightrate = cv::Mat::zeros(src.size(), CV_32FC1);
	for (int i = 0; i < src.rows; ++i)
	{
		uchar *m = mask.ptr<uchar>(i);
		float *th = thresh.ptr<float>(i);
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			if (m[j] == 255)
			{
				mi[j] = mid;
				br[j] = bright;
			}
			else {
				mi[j] = (mid - 1.0f) / t[0] * th[j] + 1.0f;
				br[j] = (1.0f / t[0] * th[j])*bright;
			}
		}
	}
 
	// 高光提亮,获取结果图
	cv::Mat result = cv::Mat::zeros(src.size(), src.type());
	for (int i = 0; i < src.rows; ++i)
	{
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		uchar *in = src.ptr<uchar>(i);
		uchar *r = result.ptr<uchar>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));
				if (temp > 1.0f)
					temp = 1.0f;
				if (temp < 0.0f)
					temp = 0.0f;
				uchar utemp = uchar(255*temp);
				r[3 * j + k] = utemp;
			}
 
		}
	}
	return result;
}

//--------------------------------------------------------------------------------
// 暖色调
cv::Mat ColorTemperature(cv::Mat src, int warm)
{
	cv::Mat result = src.clone();
	int row = src.rows;
	int col = src.cols;
	int level = warm/2;
	for (int i = 0; i < row; ++i)
	{
		uchar* a = src.ptr<uchar>(i);
		uchar* r = result.ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int R,G,B;
			// R通道
			R = a[j * 3 + 2];
			R = R + level;
			if (R > 255) 
			{
				r[j * 3 + 2] = 255;
			}
			else if (R < 0) 
			{
				r[j * 3 + 2] = 0;
			}
			else 
			{
				r[j * 3 + 2] = R;
			}
			// G通道
			G = a[j * 3 + 1];
			G = G + level;
			if (G > 255) 
			{
				r[j * 3 + 1] = 255;
			}
			else if (G < 0) 
			{
				r[j * 3 + 1] = 0;
			}
			else 
			{
				r[j * 3 + 1] = G;
			}
			// B通道
			B = a[j * 3];
			B = B - level;
			if (B > 255) 
			{
				r[j * 3] = 255;
			}
			else if (B < 0) 
			{
				r[j * 3] = 0;
			}
			else {
				r[j * 3] = B;
			}
		}
	}
	return result;
}

//--------------------------------------------------------------------------------
// 阴影
cv::Mat Shadow(cv::Mat src, int shadow)
{
	// 生成灰度图
	cv::Mat gray = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat f = src.clone();
	f.convertTo(f, CV_32FC3);
	std::vector<cv::Mat> pics;
	split(f, pics);
	gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
	gray = gray / 255.f;
 
	// 确定阴影区
	cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());	
	thresh = (1.0f - gray).mul(1.0f - gray);
	// 取平均值作为阈值
	cv::Scalar t = mean(thresh);
	cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
	mask.setTo(255, thresh >= t[0]);
 
	// 参数设置
	int max = 4;
	float bright = shadow / 100.0f / max;
	float mid = 1.0f + max * bright;
 
	// 边缘平滑过渡
	cv::Mat midrate = cv::Mat::zeros(src.size(), CV_32FC1);
	cv::Mat brightrate = cv::Mat::zeros(src.size(), CV_32FC1);
	for (int i = 0; i < src.rows; ++i)
	{
		uchar *m = mask.ptr<uchar>(i);
		float *th = thresh.ptr<float>(i);
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			if (m[j] == 255)
			{
				mi[j] = mid;
				br[j] = bright;
			}
			else 
			{
				mi[j] = (mid - 1.0f) / t[0] * th[j]+ 1.0f;   
				br[j] = (1.0f / t[0] * th[j])*bright;               
			}
		}
	}
 
	// 阴影提亮,获取结果图
	cv::Mat result = cv::Mat::zeros(src.size(), src.type());
	for (int i = 0; i < src.rows; ++i)
	{
		float *mi = midrate.ptr<float>(i);
		float *br = brightrate.ptr<float>(i);
		uchar *in = src.ptr<uchar>(i);
		uchar *r = result.ptr<uchar>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));
				if (temp > 1.0f)
					temp = 1.0f;
				if (temp < 0.0f)
					temp = 0.0f;
				uchar utemp = uchar(255*temp);
				r[3 * j + k] = utemp;
			}
 
		}
	}
	return result;
}

//--------------------------------------------------------------------------------
// 漫画效果
cv::Mat Cartoon(cv::Mat src, double clevel, int d, double sigma, int size)
{
	//(1)中值滤波
	cv::Mat m;
	cv::medianBlur(src, m, 7);
	//(2)提取轮廓
	cv::Mat c;
	clevel = cv::max(40., cv::min(80., clevel));
	cv::Canny(m, c, clevel, clevel *3);
	//(3)轮廓膨胀
	cv::Mat k = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(2, 2));
	cv::dilate(c, c, k);
	//(4)图像反转
	c = c / 255;
	c = 1 - c;
	//(5)均值滤波
	cv::Mat cf;
	c.convertTo(cf, CV_32FC1);				// 类型转换		
	cv::blur(cf, cf, cv::Size(5, 5));		
	//(6)双边滤波
	cv::Mat srcb;
	d = cv::max(0, cv::min(10, d));
	sigma = cv::max(10., cv::min(250., sigma));
	cv::bilateralFilter(src, srcb, d, sigma, sigma);
	size = cv::max(10, cv::min(25, size));
	cv::Mat temp = srcb / size;
	temp = temp * size;
	//(7)通道合并
	cv::Mat c3;
	cv::Mat cannyChannels[] = { cf, cf, cf };
	cv::merge(cannyChannels, 3, c3);
	//(8)图像相乘
	cv::Mat tempf;
	temp.convertTo(tempf, CV_32FC3);		// 类型转换
	cv::multiply(tempf, c3, tempf);			
	tempf.convertTo(temp, CV_8UC3);			// 类型转换
	return temp;
}

//--------------------------------------------------------------------------------
// 白平衡-灰度世界
cv::Mat WhiteBalcane_Gray(cv::Mat src)
{
	//(1)3通道处理
	cv::Mat result = src.clone();
	if (src.channels() != 3)
	{
		std::cout << "The number of image channels is not 3." << std::endl;
		return result;
	}
 	//(2)通道分离
	std::vector<cv::Mat> Channel;
	cv::split(src, Channel);
 	//(3)计算通道灰度值均值
	double Bm = cv::mean(Channel[0])[0];
	double Gm = cv::mean(Channel[1])[0];
	double Rm = cv::mean(Channel[2])[0];
	double Km = (Bm + Gm + Rm) / 3;
 	//(4)通道灰度值调整
	Channel[0] *= Km / Bm;
	Channel[1] *= Km / Gm;
	Channel[2] *= Km / Rm;
	//(5)通道合并
	cv::merge(Channel, result);
 	return result;
}

//--------------------------------------------------------------------------------
// 白平衡-完美反射
cv::Mat WhiteBalcane_PRA(cv::Mat src)
{
	//(1)3通道处理
	cv::Mat result = src.clone();
	if (src.channels() != 3)
	{
		std::cout << "The number of image channels is not 3." << std::endl;
		return result;
	}
 	//(2)通道分离
	std::vector<cv::Mat> Channel;
	cv::split(src, Channel);
 	//(3)计算单通道最大值
	int row = src.rows;
	int col = src.cols;
	int RGBSum[766] = { 0 };
	uchar maxR, maxG, maxB;
 	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			RGBSum[sum]++;
			maxB = cv::max(maxB, b[j]);
			maxG = cv::max(maxG, g[j]);
			maxR = cv::max(maxR, r[j]);
		}
	}
 	//(4)计算最亮区间下限T
	int T = 0;
	int num = 0;
	int K = static_cast<int>(row * col * 0.1);
	for (int i = 765; i >= 0; --i)
	{
		num += RGBSum[i];
		if (num > K)
		{
			T = i;
			break;
		}
	}
	//(5)计算单通道亮区平均值
	double Bm = 0.0, Gm = 0.0, Rm = 0.0;
	int count = 0;
	for (int i = 0; i < row; ++i)
	{
		uchar *b = Channel[0].ptr<uchar>(i);
		uchar *g = Channel[1].ptr<uchar>(i);
		uchar *r = Channel[2].ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			int sum = b[j] + g[j] + r[j];
			if (sum > T)
			{
				Bm += b[j];
				Gm += g[j];
				Rm += r[j];
				count++;
			}
		}
	}
	Bm /= count;
	Gm /= count;
	Rm /= count;
 	//(6)通道调整
	Channel[0] *= maxB / Bm;
	Channel[1] *= maxG / Gm;
	Channel[2] *= maxR / Rm;
 	//(7)通道合并
	cv::merge(Channel, result);
 	return result;
}

//--------------------------------------------------------------------------------
// 浮雕
cv::Mat Relief(cv::Mat src)
{
	CV_Assert(src.channels() == 3);
	int row = src.rows;
	int col = src.cols;
	cv::Mat temp = src.clone();
	for (int i = 1; i < row-1; ++i)
	{
		uchar *s1 = src.ptr<uchar>(i - 1);
		uchar *s2 = src.ptr<uchar>(i + 1);
		uchar *t = temp.ptr<uchar>(i);
		for (int j = 1; j < col-1; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				int RGB = s1[3 * (j - 1) + k] - s2[3 * (j + 1) + k] + 128;
				if (RGB < 0)RGB = 0;
				if (RGB > 255)RGB = 255;
				t[3*j+k] =(uchar)RGB;
			}
		}
	}
	return temp;
}

//--------------------------------------------------------------------------------
// 羽化
cv::Mat Eclosion(cv::Mat src, cv::Point center, float level)
{
	if (level > 0.9)
		level = 0.9f;
	float diff = (1-level) * (src.rows / 2 * src.rows / 2 + src.cols / 2 * src.cols / 2);
	cv::Mat result = src.clone();
	for (int i = 0; i < result.rows; ++i)
	{
		for (int j = 0; j < result.cols; ++j)
		{
			float dx = float(center.x - j);
			float dy = float(center.y - i);
			float ra = dx * dx + dy * dy;
			float m = ((ra-diff) / diff * 255)>0? ((ra - diff) / diff * 255):0;
			int b = result.at<cv::Vec3b>(i, j)[0];
			int g = result.at<cv::Vec3b>(i, j)[1];
			int r = result.at<cv::Vec3b>(i, j)[2];
			b = (int)(b+ m);
			g = (int)(g + m);
			r = (int)(r + m);
			result.at<cv::Vec3b>(i, j)[0] = (b > 255 ? 255 : (b < 0 ? 0 : b));
			result.at<cv::Vec3b>(i, j)[1] = (g > 255 ? 255 : (g < 0 ? 0 : g));
			result.at<cv::Vec3b>(i, j)[2] = (r > 255 ? 255 : (r < 0 ? 0 : r));
		}
	}
	return result;
}

//--------------------------------------------------------------------------------
// 锐化
cv::Mat Sharpen(cv::Mat input, int percent, int type)
{
	cv::Mat result;
	cv::Mat s = input.clone();
	cv::Mat kernel;
	switch (type)
	{
	case 0:
		kernel = (cv::Mat_<int>(3, 3) <<
			0, -1, 0,
			-1, 4, -1,
			0, -1, 0
			);
	case 1:
		kernel = (cv::Mat_<int>(3, 3) <<
			-1, -1, -1,
			-1, 8, -1,
			-1, -1, -1
			);
	default:
		kernel = (cv::Mat_<int>(3, 3) <<
			0, -1, 0,
			-1, 4, -1,
			0, -1, 0
			);
	}
	cv::filter2D(s, s, s.depth(), kernel);
	result = input + s * 0.01 * percent;
	return result;
}

//--------------------------------------------------------------------------------
// 颗粒感
cv::Mat Grainy(cv::Mat src, int level)
{
	int row = src.rows;
	int col = src.cols;
	if (level > 100)
		level = 100;
	if (level < 0)
		level = 0;
	cv::Mat result = src.clone();
	for (int i = 0; i < row; ++i)
	{
		uchar *t = result.ptr<uchar>(i);
		for (int j = 0; j < col; ++j)
		{
			for (int k = 0; k < 3; ++k)
			{
				int temp = t[3 * j + k];
				temp += ((rand() % (2 * level)) - level);
				if (temp < 0)temp = 0;
				if (temp > 255)temp = 255;
				t[3 * j + k] = temp;
			}
		}
	}
	return result;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/287341
推荐阅读
相关标签
  

闽ICP备14008679号