opencv第一阶段
opencv学习第五弹
前言
请大家在看提供的代码前,自己先想想解决该问题的基本思路
问题提出
将使用HSV表示色彩的图像的色相反转吧!
HSV即使用色相(Hue)、饱和度(Saturation)、明度(Value)来表示色彩的一种方式。
1.色相:将颜色使用
0
。
0^。{}
0。 到
36
0
。
360^。{}
360。表示,就是平常所说的颜色名称,如红色、蓝色。色相与数值按下表对应:
红 | 黄 | 绿 | 青色 | 蓝色 | 品红 | 红 |
---|---|---|---|---|---|---|
0 。 0^。{} 0。 | 6 0 。 60^。{} 60。 | 12 0 。 120^。{} 120。 | 18 0 。 180^。{} 180。 | 24 0 。 240^。{} 240。 | 300 0 。 3000^。{} 3000。 | 36 0 。 360^。{} 360。 |
2.饱和度:是指色彩的纯度,饱和度越低则颜色越黯淡( 0
≤
\le
≤S
≤
\le
≤ 1 );
3.明度:即颜色的明暗程度。数值越高越接近白色,数值越低越接近黑色 0
≤
\le
≤V
≤
\le
≤ 1 );
从RGB色彩表示转换到HSV色彩表示通过以下方式计算:
RGB的取值范围为 [0,1],令:
Max
=
max
(
R
,
G
,
B
)
Min
=
min
(
R
,
G
,
B
)
\begin{aligned} \operatorname{Max} &=\max (R, G, B) \\ \operatorname{Min} &=\min (R, G, B) \end{aligned}
MaxMin=max(R,G,B)=min(R,G,B)
色相:
H
=
{
0
(
if
Min
=
Max
)
60
⋅
G
−
R
Max
−
Min
+
60
(
if
Min
=
B
)
60
⋅
B
−
G
Max
−
Min
+
180
(
if
Min
=
R
)
60
⋅
R
−
B
Max
−
Min
+
300
(
if
Min
=
G
)
H=\left\{\begin{array}{ll} 0 & (\text { if } \operatorname{Min}=\operatorname{Max}) \\ 60 \cdot \frac{G-R}{\operatorname{Max}-\operatorname{Min}}+60 & (\text { if } \operatorname{Min}=B) \\ 60 \cdot \frac{B-G}{\operatorname{Max}-\operatorname{Min}}+180 & (\text { if } \operatorname{Min}=R) \\ 60 \cdot \frac{R-B}{\operatorname{Max}-\operatorname{Min}}+300 & (\text { if } \operatorname{Min}=G) \end{array}\right.
H=⎩⎪⎪⎨⎪⎪⎧060⋅Max−MinG−R+6060⋅Max−MinB−G+18060⋅Max−MinR−B+300( if Min=Max)( if Min=B)( if Min=R)( if Min=G)
饱和度:
S
=
Max
−
Min
S=\operatorname{Max}-\operatorname{Min}
S=Max−Min
明度:
V
=
Max
V=\operatorname{Max}
V=Max
从HSV色彩表示转换到RGB色彩表示通过以下方式计算:
C
=
S
H
′
=
H
60
(
R
,
G
,
B
)
=
(
V
−
C
)
⋅
(
1
,
1
,
1
)
+
{
(
0
,
0
,
0
)
(if
H
is undefined)
(
C
,
X
,
0
)
(if
0
≤
H
′
<
1
)
(
X
,
C
,
0
)
(
if
1
≤
H
′
<
2
)
(
0
,
C
,
X
)
(if
2
≤
H
′
<
3
)
(
0
,
X
,
C
)
(if
3
≤
H
′
<
4
)
(
X
,
0
,
C
)
(if
4
≤
H
′
<
5
)
(
C
,
0
,
X
)
(
if
5
≤
H
′
<
6
)
\begin{array}{c} C=S \\ H^{\prime}=\frac{H}{60} \\ (R, G, B)=(V-C) \cdot(1,1,1)+\left\{\begin{array}{ll} (0,0,0) & \text { (if } \mathrm{H} \text { is undefined) } \\ (C, X, 0) & \text { (if } \left.0 \leq H^{\prime}<1\right) \\ (X, C, 0) & (\text { if } & \left.1 \leq H^{\prime}<2\right) \\ (0, C, X) & \text { (if } \left.2 \leq H^{\prime}<3\right) \\ (0, X, C) & \text { (if } \left.3 \leq H^{\prime}<4\right) \\ (X, 0, C) & \text { (if } \left.4 \leq H^{\prime}<5\right) \\ (C, 0, X) & (\text { if } & \left.5 \leq H^{\prime}<6\right) \end{array}\right. \end{array}
C=SH′=60H(R,G,B)=(V−C)⋅(1,1,1)+⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧(0,0,0)(C,X,0)(X,C,0)(0,C,X)(0,X,C)(X,0,C)(C,0,X) (if H is undefined) (if 0≤H′<1)( if (if 2≤H′<3) (if 3≤H′<4) (if 4≤H′<5)( if 1≤H′<2)5≤H′<6)
请将色相反转(色相值加 ),然后再用RGB色彩空间表示图片。
代码
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>
// BGR -> HSV
cv::Mat BGR2HSV(cv::Mat img){
// get height and width
int width = img.cols;
int height = img.rows;
float r, g, b;
float h, s, v;
float _max, _min;
// prepare output
cv::Mat hsv = cv::Mat::zeros(height, width, CV_32FC3);
// each y, x
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++){
// BGR -> HSV
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));
// get Hue
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;
}
// get Saturation
s = _max - _min;
// get Value
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;
}
// HSV -> BGR
cv::Mat HSV2BGR(cv::Mat hsv){
// get height and width
int width = hsv.cols;
int height = hsv.rows;
float h, s, v;
double c, _h, _x;
double r, g, b;
// prepare output
cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);
// each y, x
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;
}
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;
}
// inverse Hue
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++){
hsv.at<cv::Vec3f>(y, x)[0] = fmod(hsv.at<cv::Vec3f>(y, x)[0] + 180, 360);
}
}
return hsv;
}
int main(int argc, const char* argv[]){
// read image
cv::Mat img = cv::imread("imori.jpg", cv::IMREAD_COLOR);
// BGR -> HSV
cv::Mat hsv = BGR2HSV(img);
// Inverse Hue
hsv = inverse_hue(hsv);
// Gray -> Binary
cv::Mat out = HSV2BGR(hsv);
//cv::imwrite("out.jpg", out);
cv::imshow("sample", out);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}