HSV和RGB都是表示色彩的方式。H为色相,S为饱和度,V为明度,RGB代表红绿蓝三种颜色分量。
色相:用0-360度表示颜色。
饱和度:色彩纯度,越低颜色越暗淡,范围0~1。
明度:色彩明暗度,越高越亮越接近白色,越低越暗越接近黑色,范围0~1。
转化公式如下:
从RGB到HSV
从HSV到RGB
RGB和HSV按照公式进行转化,但是要注意r,g,b的范围要从0255变成01参与计算,最后的结果,HSV为float类型,RGB为uchar类型要互相转化。
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
cv::Mat BGR2HSV(cv::Mat img) {
int width = img.cols;
int height = img.rows;
float r, g, b;
float h, s, v;
float _max, _min;
cv::Mat hsv = cv::Mat::zeros(height, width, CV_32FC3);//32位浮点数三通道
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
//r g b变为0~1范围
r = (float)img.at<cv::Vec3b>(y, x)[2] / 255;
g = (float)img.at<cv::Vec3b>(y, x)[1] / 255;
b = (float)img.at<cv::Vec3b>(y, x)[0] / 255;
_max = fmax(r, fmax(g, b));
_min = fmin(r, fmin(g, b));
if (_max == _min) {
h = 0;
}
else if (_min == b) {
h = 60 * (g - r) / (_max - _min) + 60;
}
else if (_min == r) {
h = 60 * (b - g) / (_max - _min) + 180;
}
else if (_min == g) {
h = 60 * (r - b) / (_max - _min) + 300;
}
s = _max - _min;
v = _max;
hsv.at<cv::Vec3f>(y, x)[0] = h;
hsv.at<cv::Vec3f>(y, x)[1] = s;
hsv.at<cv::Vec3f>(y, x)[2] = v;
}
}
return hsv;
}
// 将RGB的uchar转为HSV的float
cv::Mat HSV2BGR(cv::Mat hsv) {
int width = hsv.cols;
int height = hsv.rows;
float h, s, v;
double c, _h, _x;
double r, g, b;
cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
h = hsv.at<cv::Vec3f>(y, x)[0];
s = hsv.at<cv::Vec3f>(y, x)[1];
v = hsv.at<cv::Vec3f>(y, x)[2];
c = s;
_h = h / 60;
_x = c * (1 - abs(fmod(_h, 2) - 1));
r = g = b = v - c;
if (_h < 1) {
r += c;
g += _x;
}
else if (_h < 2) {
r += _x;
g += c;
}
else if (_h < 3) {
g += c;
b += _x;
}
else if (_h < 4) {
g += _x;
b += c;
}
else if (_h < 5) {
r += _x;
b += c;
}
else if (_h < 6) {
r += c;
b += _x;
}
//*255 并变成uchar类型
out.at<cv::Vec3b>(y, x)[0] = (uchar)(b * 255);
out.at<cv::Vec3b>(y, x)[1] = (uchar)(g * 255);
out.at<cv::Vec3b>(y, x)[2] = (uchar)(r * 255);
}
}
return out;
}
cv::Mat inverse_hue(cv::Mat hsv) {
int height = hsv.rows;
int width = hsv.cols;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
//Vec3f可以看作是vector<float, 3> 即float类型的,长度为3的vector向量
//HSV三个分量的表示均为浮点数
hsv.at<cv::Vec3f>(y, x)[0] = fmod(hsv.at<cv::Vec3f>(y, x)[0] + 180, 360);//fmod对360度取余
}
}
return hsv;
}
int main(int argc, const char* argv[]) {
cv::Mat img = cv::imread("C:/Users/zxdn/Desktop/boy.jpg", cv::IMREAD_COLOR);
cv::Mat hsv = BGR2HSV(img);
hsv = inverse_hue(hsv);//色相反转
cv::Mat out = HSV2BGR(hsv);
cv::imshow("原图", img);
cv::imshow("色相反转180度", out);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}