OpenCV中读取RGB格式图像转成HSV格式图像显示

#include <math.h>
#include "highgui.h"
#include "cv.h"
#include "time.h"
#include <iostream>

 
int main()
{
	IplImage* image = cvLoadImage("test.png");  
	IplImage* hsv = cvCreateImage( cvGetSize(image), 8, 3 );
	cvCvtColor(image,hsv,CV_BGR2HSV);

	cvNamedWindow("saturate_SV",CV_WINDOW_AUTOSIZE);  
	cvShowImage("saturate_SV",hsv);  
	cvWaitKey(0);  
	cvReleaseImage(&hsv);  
	cvDestroyWindow("saturate_SV");  
	return 0;
}

函数 cvCvtColor 将输入图像从一个色彩空间转换为另外一个色彩空间。但凡图像处理软件,都会提供色相、饱和度、明度调整功能,比如常见的PS或者美图秀秀在调整色相、饱和度、明度时,需要将每个像素点的rgb色彩空间转换到hsv色彩空间,然后做相应计算调整,最后在将计算结果转换回rgb颜色空间进行显示。 

补充:

HSL 和 HSV(也叫HSB)是对RGB 色彩空间中点的两种有关系的表示,它们尝试描述比 RGB 更准确的感知颜色联系,并仍保持在计算上简单。

H指hue(色相)、S指saturation(饱和度)、L指lightness(亮度)、V指value(色调)、B指brightness(明度)。

  • 色相(H)是色彩的基本属性,就是平常所说的颜色名称,如红色黄色等。
  • 饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。
  • 明度(V),亮度(L),取0-100%。

HSL 和 HSV 二者都把颜色描述在圆柱坐标系内的点,这个圆柱的中心轴取值为自底部的黑色到顶部的白色而在它们中间是的灰色,绕这个轴的角度对应于“色相”,到这个轴的距离对应于“饱和度”,而沿着这个轴的高度对应于“亮度”,“色调”或“明度”。

这两种表示在用目的上类似,但在方法上有区别。二者在数学上都是圆柱,但 HSV(色相,饱和度,色调)在概念上可以被认为是颜色的倒圆锥体(黑点在下顶点,白色在上底面圆心),HSL 在概念上表示了一个双圆锥体和圆球体(白色在上顶点,黑色在下顶点,最大横切面的圆心是半程灰色)。注意尽管在 HSL 和 HSV 中“色相”指称相同的性质,它们的“饱和度”的定义是明显不同的。

因为 HSL 和 HSV 是设备依赖的 RGB 的简单变换,(hsl) 或 (hsv) 三元组定义的颜色依赖于所使用的特定红色绿色蓝色加法原色”。每个独特的 RGB 设备都伴随着一个独特的 HSL 和 HSV 空间。但是 (hsl) 或 (hsv) 三元组在被约束于特定 RGB 空间比如 sRGB 的时候就变成明确的了。

HSV 模型在 1978 年由埃尔维·雷·史密斯创立,它是三原色光模式的一种非线性变换。

HSV 色轮允许用户快速的选择众多颜色。
HSV 模型的圆锥表示适合于在一个单一物体中展示整个 HSV 色彩空间。

HSV 模型通常用于计算机图形应用中。在用户必须选择一个颜色应用于特定图形元素各种应用环境中,经常使用 HSV 色轮(如右图)。


HSV编辑器:

GIMP 支持在 HSV 色彩空间内的选取颜色的多种方法,包括带有色相滑块的色轮和色方。


从 HSV 到 RGB 的转换: 

类似的,给定在 HSV 中 (hsv) 值定义的一个颜色,带有如上的 h,和分别表示饱和度和明度的 s 和 v 变化于 0 到 1 之间,在 RGB 空间中对应的 (rgb) 三原色可以计算为(R,G,B变化于 0 到 1 之间):

h_i \equiv \left\lfloor \frac{h}{60} \right\rfloor \pmod{6}
f = \frac{h}{60} - h_i
p = v \times (1 - s) \,
q = v \times (1 - f \times s) \,
t = v \times (1 - (1 - f) \times s) \,


对于每个颜色向量 (rgb),


(r, g, b) = \begin{cases}(v, t, p), & \mbox{if } h_i = 0  \\(q, v, p), & \mbox{if } h_i = 1  \\(p, v, t), & \mbox{if } h_i = 2  \\(p, q, v), & \mbox{if } h_i = 3  \\(t, p, v), & \mbox{if } h_i = 4  \\(v, p, q), & \mbox{if } h_i = 5  \\\end{cases}

展示的 RGB 值的范围是 0.0 到 1.0。
RGB HSL HSV 结果
(1, 0, 0)(0°, 1, 0.5)(0°, 1, 1)  
(0.5, 1, 0.5)(120°, 1, 0.75)(120°, 0.5, 1)  
(0, 0, 0.5)(240°, 1, 0.25)(240°, 1, 0.5)  

struct BGR
{
    uchar b;
    uchar g;
    uchar r;
};

struct HSV
{
    int h;
    double s;
    double v;
};

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

//RGB(BGR: 0~255)转HSV(H: [0~360), S: [0~1], V: [0~1])
void BGR2HSV(BGR &bgr, HSV &hsv)
{
    double b, g, r;
    double h, s, v;
    double min, max;
    double delta;

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

    if (r > g)
    {
         max = MAX( r, b);
         min = MIN( g, b);
    }
    else
    {
         max = MAX( g, b);
         min = MIN( r, b);
    }

    v = max;
    delta = max - min;

    if (IsEquals( max, 0))
    {
         s = 0.0;
    }
    else
    {
         s = delta/ max;
    }

    if (max == min)
    {
         h = 0.0;
    }
    else
    {
        if ( IsEquals( r, max) && g >= b)
         {
              h = 60 * ( g - b)/ delta + 0;
         }
         else if ( IsEquals( r, max) && g < b)
         {
              h = 60 * ( g - b)/ delta + 360;
         }
         else if ( IsEquals( g, max))
         {
              h = 60 * ( b - r)/ delta + 120;
         }
         else if ( IsEquals( b, max))
         {
              h = 60 * ( r - g)/ delta + 240;
         }
    }

    hsv.h = ( int)( h + 0.5);
    hsv.h = ( hsv. h > 359) ? ( hsv. h - 360) : hsv. h;
    hsv.h = ( hsv. h < 0) ? ( hsv. h + 360) : hsv. h;
    hsv.s = s;
    hsv.v = v;
}

//RGB(BGR: 0~255)转HSV(H: [0~360), S: [0~1], V: [0~1])
void HSV2BGR(HSV &hsv, BGR &bgr)
{
    int h = hsv.h;
    double s = hsv. s;
    double v = hsv. v;
    double b = 0.0;
    double g = 0.0;
    double r = 0.0;

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

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

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

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

    int red = int( r * 255);
    bgr.r = ( red > 255) ? 255 : red;
    bgr.r = ( red < 0) ? 0 : bgr. r;
}

int main()
{
    string imgName = "e:/MyProjects/image/lena.jpg";
    Mat img = cv::imread(imgName);
    Mat tmp = img.clone();

    if (img.data == NULL)
    {
         cout<< "Could not open or find the image"<<endl;
         return -1;
    }

    int row = img. rows;
    int col = img. cols * img.channels();
    uchar * pImg = NULL;
    BGR bgr;
    HSV hsv;

    for ( int i = 0; i < row; i++)
    {
         pImg = img. ptr< uchar>( i); // 遍历时用img.at()效率会降很多, 很耗时
         for ( int j = 0; j < col; j+=3)
         {
              bgr. b = pImg[ j];
              bgr. g = pImg[ j + 1];
              bgr. r = pImg[ j + 2];
              BGR2HSV( bgr, hsv);
              hsv. h = hsv. h + 60;// h取值范围为[0, 360)
              hsv. h = ( hsv. h > 359) ?  hsv. h - 360) : hsv. h;
              hsv. h = ( hsv. h < 0) ? ( hsv. h + 360) : hsv. h;
              HSV2BGR( hsv, bgr);
              pImg[j]     = bgr. b;
              pImg[j + 1] = bgr. g;
              pImg[j + 2] = bgr. r;
        }
    }
    imshow("dd", img);

    cvtColor(tmp, tmp, CV_BGR2HSV);
    vector< Mat> channels;
    split( tmp, channels);
    channels[0] += 30;// 这里没有做范围判断,opencv的h取值范围为[0, 180)
    merge(channels, tmp);
    cvtColor(tmp, tmp, CV_HSV2BGR);
    imshow("opencv", tmp);
    cv::waitKey();

    return 0;
}


参考网址


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值