您的位置:首页 > 运维架构

数据可视化作业:OpenCV颜色空间转换(RGB-HSV)

2018-03-16 15:44 441 查看
RGB<->HSV
RGB代表三原色Red,Green与Blue,强度可以由三分量的向量表示。
HSV的H代表色彩,S代表深浅,当S=0时只有灰度,V是明亮,代表色彩明亮程度。
RGB到HSV转换公式如下



HSV到RGB转换公式如下



数据结构定义:
struct RGB
//(r, g, b) 分别是一个颜色的红、绿和蓝坐标,
//它们的值是在 0 到 1 之间的实数
{
uchar r;
uchar g;
uchar b;
};

// h ∈[0, 360)是角度的色相角,
//而 s, v ∈[0, 1] 是饱和度和亮度
struct HSV
{
double h;
double s;
double v;
};

struct YUV
{
double y;
double u;
double v;
};

bool IsEquals(double val1, double val2)
{
return fabs(val1 - val2) < 0.001;
}

// BGR(BGR: 0~255)转HSV(H: [0~360), S: [0~1], V: [0~1])

void BGRConvert2HSV(RGB &rgb, HSV &hsv)
{
double b, g, r;
double h, s, v;
double min, max;

b = rgb.b / 255.0;
g = rgb.g / 255.0;
r = rgb.r / 255.0;

//V为r,g,b,中的最大值:
if (r > g)
{
max = MAX(r, b);
min = MIN(g, b);
}
else
{
max = MAX(g, b);
min = MIN(r, b);
}

v = max;//找到v了!

if (v != 0)
{
s = (max - min) / max; //找到s了!
}
else
{
s = 0;
}

if (v == r)
{
h = 60 * (g - b) / (v - min);

}
else if (v == g)
{
h = 120 + 60 * (b - r) / (v - min);
}
else if (v == b)
{
h = 240 + 60 * (r - g) / (v - min);
}
if (h < 0)
{
h = h + 360;
}
//把找到的h,s,v赋给hsv中的h,s,v
hsv.h = h;
hsv.s = s;
hsv.v = v;
}

// HSV转BGR
void HSVConvert2BGR(HSV &hsv, RGB &rgb)
{
//以下按照word文档的公式来进行计算
double h = hsv.h;
double s = hsv.s;
double v = hsv.v;
double r = 0;
double g = 0;
double b = 0;

int hi = (int)abs(h / 60);
double f = h / 60.0 - hi;
double p = v * (1 - s);
double q = v * (1 - f * s);
double t = v * (1 - (1 - f)*s);

switch (hi)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r=q;
g = v;
b=t;
break;
case 2:
r = p;
b = t;
g = v;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
default:
break;
}

//r,g,b范围为[0-255]
int red = int(r * 255);
rgb.r = (red > 255) ? 255 : red;
rgb.r = (red < 0) ? 0 : rgb.r;

int blue = int(b * 255);
rgb.b = (blue > 255) ? 255 : blue;
rgb.b = (blue < 0) ? 0 : rgb.b;

int green = int(g * 255);
rgb.g = (green > 255) ? 255 : green;
rgb.g = (green < 0) ? 0 : rgb.g;

}

int main()
{
//Mat是opencv库的一种基本图像容器,能够读取并保存
//图片的行,列像素信息
Mat image = cv::imread("王力宏.jpg"); //调用cv的读取图片的函数

imshow("王力宏原图", image); //展示原图

if (image.data == NULL) //异常处理
{
cout << "找不到该图片文件" << endl;
return -1;
}

// 色彩空间转换
int row = image.rows; //总行数
int col = image.cols * image.channels(); //每一行元素总个数
uchar * pImg = NULL;
RGB bgr;
HSV hsv;
for (int i = 0; i < row; i++)
{
pImg = image.ptr<uchar>(i); //指针按行遍历读取像素
for (int j = 0; j < col; j ++)
{
bgr.b = pImg[j];
bgr.g = pImg[j + 1];
bgr.r = pImg[j + 2];
BGRConvert2HSV(bgr, hsv);
//色相角范围只能在[0,360]
hsv.h += 30;//加强色相的对比,使得转换效果明显
hsv.h = (hsv.h > 360) ? (hsv.h - 360) : hsv.h;
hsv.h = (hsv.h < 0) ? (hsv.h + 360) : hsv.h;
HSVConvert2BGR(hsv, bgr);
pImg[j] = bgr.b;
pImg[j + 1] = bgr.g;
pImg[j + 2] = bgr.r;
}
}
imshow("转换后", image);
cv::waitKey(); //结束函数

return 0;
}

RGB与YUV转换公式:Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B

R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U}

void RGBConvert2YUV(RGB &rgb, YUV &yuv)
{
double r, g, b;
double y, u, v;

b = rgb.b;
g = rgb.g ;
r = rgb.r;

y = 0.299*r + 0.587*g + 0.114*b;
u = -0.147*r - 0.289*g + 0.436*b;
v = 0.615*r - 0.515*g - 0.1*b;

//y范围在[16,235],u,v范围在[16,239]
yuv.y = (y > 235) ? 235 : y;
yuv.y = (y <16) ? 16: y;

yuv.u = (u > 239) ? 239 : u;
yuv.u = (y <16) ? 16 : u;

yuv.v = (v > 239) ? 239 : v;
yuv.v = (v <16) ? 16 : v;
}

void YUVConvert2RGB(RGB &rgb, YUV &yuv)
{
double r, g, b;
double y, u, v;

y = yuv.y;
u = yuv.u;
v = yuv.v;

r = y + 1.14*v;
g = y - 0.39*u + 0.436*v;
b = y + 2.03*u;
//保证r,g,b范围在[0.255]
rgb.r = (r > 255) ? 255 : r;
rgb.r = (r <0) ? 0 : r;

rgb.g = (g > 255) ? 255 : g;
rgb.g = (g <0) ? 0 : g;

rgb.b = (b > 255) ? 255 : b;
rgb.b = (b<0) ? 0 :b;

}

主函数部分:int main()
{
//Mat是opencv库的一种基本图像容器,能够读取并保存
//图片的行,列像素信息
Mat image = cv::imread("王力宏.jpg"); //调用cv的读取图片的函数

imshow("王力宏原图", image); //展示原图

if (image.data == NULL) //异常处理
{
cout << "找不到该图片文件" << endl;
return -1;
}

// 色彩空间转换
int row = image.rows; //总行数
int col = image.cols * image.channels(); //每一行元素总个数
uchar * pImg = NULL;
RGB bgr;
HSV hsv;
YUV yuv;
//RGB与YUV转换
for (int i = 0; i < row; i++)
{
pImg = image.ptr<uchar>(i); //指针按行遍历读取像素
for (int j = 0; j < col; j +=3)
{
bgr.b = pImg[j];
bgr.g = pImg[j + 1];
bgr.r = pImg[j + 2];
RGBConvert2YUV(bgr, yuv);
YUVConvert2RGB(bgr, yuv);
pImg[j] = bgr.b;
pImg[j + 1] = bgr.g;
pImg[j + 2] = bgr.r;
}
imshow("转换后(YUV-RGB)", image);
}

Mat image2 = cv::imread("王力宏.jpg");//再读取一遍,否则就是在上述变换的基础上再进行变换,而不是在原图上变换。
row = image2.rows;
col = image2.cols * image2.channels();
//RGB与HSV转换
for (int i = 0; i < row; i++)
{
pImg = image2.ptr<uchar>(i); //指针按行遍历读取像素
for (int j = 0; j < col; j += 3)
{
bgr.b = pImg[j];
bgr.g = pImg[j + 1];
bgr.r = pImg[j + 2];
BGRConvert2HSV(bgr, hsv); //BGR->HSV
//色相角范围只能在[0,360]
hsv.h += 30;//加强色相的对比,使得转换效果明显
hsv.h = (hsv.h > 360) ? (hsv.h - 360) : hsv.h;
hsv.h = (hsv.h < 0) ? (hsv.h + 360) : hsv.h;
HSVConvert2BGR(hsv, bgr);//HSV->BGR
pImg[j] = bgr.b;
pImg[j + 1] = bgr.g;
pImg[j + 2] = bgr.r;
}
imshow("转换后(HSV-RGB)", image2);
}

cv::waitKey(); //结束函数

return 0;
}

效果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: