[C++][opencv]基于opencv实现photoshop算法色相和饱和度调整

【测试环境】

vs2019

opencv==4.8.0

【效果演示】

【核心实现代码】

HSL.hpp

#ifndef OPENCV2_PS_HSL_HPP_
#define OPENCV2_PS_HSL_HPP_

#include "opencv2/core.hpp"
using namespace cv;

namespace cv {

enum HSL_COLOR
{
	HSL_ALL,
	HSL_RED,
	HSL_YELLOW,
	HSL_GREEN,
	HSL_CYAN,
	HSL_BLUE,
	HSL_MAGENTA,
};

/**
 * Class of HSL parameters for one channel
 */
class HSLChannel {
public:
	int hue;          //色度调整值,     数据范围:  [-180, 180]
	int saturation;   //饱和度调整值,数据范围:  [-100, 100]
	int brightness;   //明度调整值,    数据范围:  [-100, 100]

	int   colorIndex;  //color index: 0 = RED, 1 = YELLOW, 2 = GREEN
	float left_left;  //hue range left-left
	float left;       //hue range left
	float right;	  //hue range right
	float right_right;//hue range right-right
	bool defined;     //

	HSLChannel();
	virtual ~HSLChannel();

	void calcDefined();
	void setColorIndex(int index);
	bool match(float hue);
	void adjust(int h, float *delta_hsb);
};

/**
 * Class of HSL
 */
class HSL {
public:
	HSL();
	virtual ~HSL();

	HSLChannel channels[7];

	int adjust(InputArray src, OutputArray dst);
};

} /* namespace cv */

#endif /* OPENCV2_PS_HSL_HPP_ */

 HSL.cpp

#include "HSL.hpp"
#include "ColorSpace.hpp"
#include <math.h>

#define CLIP_RANGE(value, min, max)  ( (value) > (max) ? (max) : (((value) < (min)) ? (min) : (value)) )
#define COLOR_RANGE(value)  CLIP_RANGE(value, 0, 255)

namespace cv {

HSLChannel::HSLChannel()
{
	hue = 0;
	saturation = 0;
	brightness = 0;
	defined = false;

	setColorIndex(0);
}

HSLChannel::~HSLChannel()
{

}

void HSLChannel::setColorIndex(int index)
{
	int data[][4] = {
			{  0,   0, 360, 360},
			{315, 345,  15,  45},
			{ 15,  45,  75, 105},
			{ 75, 105, 135, 165},
			{135, 165, 195, 225},
			{195, 225, 255, 285},
			{255, 285, 315, 345}
	};

	if (index < 0 ) index = 0;
	if (index > 6 ) index = 6;

	colorIndex = index;
	left_left = data[index][0];
	left      = data[index][1];
	right     = data[index][2];
	right_right = data[index][3];
}

void HSLChannel::calcDefined()
{
	if ( hue != 0 || saturation != 0 || brightness != 0 ) {
		defined = true;
		return;
	}
	defined = false;
}


bool  HSLChannel::match(float hue)
{
	if ( left < right ) {
		if ( hue >= left_left && hue <= right_right )
			return true;
	} else {
		if ( hue >=left_left && hue <= 360 )
			return true;
		if ( hue >=0 && hue <= right_right )
			return true;
	}
	return false;
}

void HSLChannel::adjust(int h, float *delta_hsb)
{
	if (colorIndex == 0 ) {
		delta_hsb[0] += hue;
		delta_hsb[1] += saturation;
		delta_hsb[2] += brightness;
		return;
	}

	if ( left < right ) {
		if ( h >= left_left && h <= right_right ) {
			if ( h >=left && h <= right) {
				delta_hsb[0] += hue;
				delta_hsb[1] += saturation;
				delta_hsb[2] += brightness;
				return;
			}

			if ( h >=left_left && h <= left && left > left_left) {
				delta_hsb[0] += hue * (h - left_left) / (left - left_left);
				delta_hsb[1] += saturation * (h - left_left) / (left - left_left);
				delta_hsb[2] += brightness * (h - left_left) / (left - left_left);
				return;
			}

			if ( h >=right && h <= right_right && right_right > right) {
				delta_hsb[0] += hue * (right_right - h) / (right_right - right);
				delta_hsb[1] += saturation * (right_right - h) / (right_right - right);
				delta_hsb[2] += brightness * (right_right - h) / (right_right - right);
				return;
			}
		}

	} else {
		if ( h >=left && h <= 360 ) {
			delta_hsb[0] += hue;
			delta_hsb[1] += saturation;
			delta_hsb[2] += brightness;
			return;
		}

		if ( h >=0 && h <= right ) {
			delta_hsb[0] += hue;
			delta_hsb[1] += saturation;
			delta_hsb[2] += brightness;
			return;
		}

		if ( h >=left_left && h <= left && left > left_left) {
			delta_hsb[0] += hue * (h - left_left) / (left - left_left);
			delta_hsb[1] += saturation * (h - left_left) / (left - left_left);
			delta_hsb[2] += brightness * (h - left_left) / (left - left_left);
			return;
		}

		if ( h >=right && h <= right_right && right_right > right) {
			delta_hsb[0] += hue * (right_right - h) / (right_right - right);
			delta_hsb[1] += saturation * (right_right - h) / (right_right - right);
			delta_hsb[2] += brightness * (right_right - h) / (right_right - right);
			return;
		}
	}
}


//----------------------------------------------------------
//HSL class

HSL::HSL()
{
	for (int i = 0; i < 7; i++)
		channels[i].setColorIndex(i);
}

HSL::~HSL()
{
}

int HSL::adjust(InputArray src, OutputArray dst)
{
	Mat input = src.getMat();
	if( input.empty() ) {
		return -1;
	}

	dst.create(src.size(), src.type());
	Mat output = dst.getMat();

	const uchar *in;
	uchar *out;
	int width = input.cols;
	int height = input.rows;
	int channel_count = input.channels();

	float hsb[3];
	float delta_hsb[3];

	//calculate defined
	for (int i = 0; i < 7; i++)
		channels[i].calcDefined();

	//scan pixels of image
	for (int y = 0; y < height; y ++) {
		in = input.ptr<uchar>(y);
		out = output.ptr<uchar>(y);

		for (int x = 0; x < width; x ++) {
			//RGB to HSL conversion
			BGR2HSB(in, hsb);

			//adjust each channel
			delta_hsb[0] = delta_hsb[1] = delta_hsb[2] = 0;
			for (int i = 0; i < 7; i++) {
				if ( channels[i].defined ) {
					 channels[i].adjust(hsb[0], delta_hsb);
				}
			}

			//adjust hue
			hsb[0] = int(hsb[0] + delta_hsb[0]) % 360;
			if ( hsb[0] <  0 ) hsb[0] += 360;

			//adjust saturation
			delta_hsb[1] = CLIP_RANGE(delta_hsb[1], -100, 100);
			if ( delta_hsb[1] < 0) {
				hsb[1] = hsb[1] * (1 + delta_hsb[1] / 100.0);
			} else {
				hsb[1] = hsb[1] + ( 1 - hsb[1] ) * delta_hsb[1] / 100.0; //saturation increase
				hsb[2] = hsb[2] + ( 1 - hsb[2] ) * delta_hsb[1] / 100.0; //brightness increase
			}

			//adjust brightness
			delta_hsb[2] = CLIP_RANGE(delta_hsb[2], -100, 100);
			if ( delta_hsb[2] < 0) {
				hsb[2] = hsb[2] * (1 + delta_hsb[2] / 100.0);
			} else {
				hsb[2] = hsb[2] + ( 1 - hsb[2] ) * delta_hsb[2] / 100.0; //brightness increase
				hsb[1] = hsb[1] - hsb[1]  * delta_hsb[2] / 100.0; //saturation decrease
			}

			//save to output
			HSB2BGR(hsb, out);

			//move to next pixel
			in += 3;
			out += 3;
			for (int c = 0; c < channel_count - 3; c++) {
				*out++ = *in++;
			}
		}
	}

	return 0;
}


} /* namespace cv */

【完整演示源码下载】

https://download.csdn.net/download/FL1623863129/88600796

【参考文献】

https://blog.csdn.net/c80486/article/details/52505546

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: opencv是一个开源的计算机视觉库,可以在Python中使用。通过使用opencv色相饱和度转换功能,可以实现类似Photoshop中对图像进行色相饱和度调整。 首先,我们需要导入opencv库,并读取一张图片作为输入图像。可以使用cv2.imread()函数来读取图像。 接下来,我们可以通过调用cv2.cvtColor()函数来将图像转换为HSV色彩空间。HSV颜色模型由色调(Hue),饱和度(Saturation)和亮度(Value)组成。我们只需要调整色调和饱和度,所以我们将图像转换为HSV色彩空间。 然后,我们可以通过使用cv2.convertScaleAbs()函数来调整色相饱和度的值。该函数有三个参数,分别是输入图像、输出图像和缩放因子。我们可以将缩放因子设置为一个小数,以调整图像的色相饱和度。 最后,我们可以使用cv2.cvtColor()函数将图像转换回BGR颜色空间,然后可以使用cv2.imshow()函数显示调整后的图像。 下面是一个简单的示例代码: ```python import cv2 # 读取输入图像 image = cv2.imread('image.jpg') # 将图片转换为HSV颜色空间 hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 调整色相饱和度的值 hue_scale = 0.5 # 色相缩放因子 saturation_scale = 1.5 # 饱和度缩放因子 # 调整色相饱和度的值 hsv_image[:,:,0] = cv2.convertScaleAbs(hsv_image[:,:,0], alpha=hue_scale) hsv_image[:,:,1] = cv2.convertScaleAbs(hsv_image[:,:,1], alpha=saturation_scale) # 将图片转换回BGR颜色空间 new_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) # 显示调整后的图像 cv2.imshow('Adjusted Image', new_image) cv2.waitKey(0) cv2.destroyAllWindows() ``` 这个示例代码中,我们将色相缩放因子设为0.5,饱和度缩放因子设为1.5。你可以根据自己的需要调整这两个值来得到不同的效果。调整后的图像会在一个新的窗口中显示出来。 这样,我们就可以通过opencv和Python来实现简单的色相饱和度调整,类似于Photoshop中的功能。 ### 回答2: 要使用OpenCV和Python实现Photoshop中的色相饱和度功能,可以按照以下步骤进行: 1. 导入必要的库:使用`import cv2`导入OpenCV库。 2. 加载图像:使用`cv2.imread()`函数加载要处理的图像。 3. 转换颜色空间:将加载的图像转换为HSV颜色空间,以便可以对色相饱和度进行调整。使用`cv2.cvtColor()`函数将图像从BGR颜色空间转换为HSV颜色空间。 4. 调整色相饱和度:使用`cv2.cvtColor()`函数的第三个参数来调整色相饱和度。该参数的取值范围为[-180, 180],其中负值表示减少色相饱和度,正值表示增加色相饱和度。 5. 转换颜色空间:将调整后的图像转换回BGR颜色空间,以便显示或保存。使用`cv2.cvtColor()`函数将图像从HSV颜色空间转换为BGR颜色空间。 6. 显示或保存结果:使用`cv2.imshow()`函数显示调整后的图像,并使用`cv2.waitKey()`函数等待用户按下键盘上的任意键。或使用`cv2.imwrite()`函数将调整后的图像保存到文件中。 7. 释放资源:使用`cv2.destroyAllWindows()`函数释放窗口和图像资源。 以下是一个示例代码来实现上述步骤: ```python import cv2 # 加载图像 image = cv2.imread('input.jpg') # 转换颜色空间为HSV hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 调整色相饱和度 hsv_image[..., 0] += 30 # 增加色相 hsv_image[..., 1] *= 1.5 # 增加饱和度 # 转换颜色空间为BGR adjusted_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) # 显示调整后的图像 cv2.imshow('Adjusted Image', adjusted_image) cv2.waitKey(0) # 保存调整后的图像 cv2.imwrite('output.jpg', adjusted_image) # 释放资源 cv2.destroyAllWindows() ``` 这段示例代码实现了将输入图像的色相增加30度,饱和度增加1.5倍的效果。您可以根据实际需求调整这两个参数来实现不同的色相饱和度调整效果。 ### 回答3: 要使用OpenCV在Python中实现Photoshop色相饱和度功能,你需要按照以下步骤进行操作: 1. 导入所需的库和模块: ```python import cv2 import numpy as np ``` 2. 读取图像: ```python image = cv2.imread("your_image.jpg") ``` 3. 将图像转换为HSV颜色空间: ```python hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) ``` 4. 调整色相饱和度参数: ```python hue_shift = 30 # 色相偏移量(取值范围:-180到180) saturation_factor = 1.5 # 饱和度增强因子(取值范围:0到正无穷) hsv_image[:, :, 0] = (hsv_image[:, :, 0] + hue_shift) % 180 hsv_image[:, :, 1] = hsv_image[:, :, 1] * saturation_factor ``` 5. 将修改后的图像转换回BGR颜色空间: ```python result_image = cv2.cvtColor(hsv_image, cv2.COLOR_HSV2BGR) ``` 6. 显示和保存结果图像: ```python cv2.imshow("Result Image", result_image) cv2.imwrite("result_image.jpg", result_image) cv2.waitKey(0) ``` 通过以上步骤,你可以使用OpenCV和Python实现类似Photoshop色相饱和度功能。根据需要,你可以调整色相饱和度的参数来得到不同的效果。记得根据自己的实际情况修改读取和保存图像的路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FL1623863129

你的打赏是我写文章最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值