基于OpenCV的RGB和HSV色彩空间相互转换C++程序

       之所以说基于opencv,由于转换程序用到了一些OpenCV函数及数据类型。
       OpenCV全称:Open Source Computer Vision Library,开源 、免费, 很好很强大。


       但凡图像处理软件,都会提供色相、饱和度、明度调整功能,比如常见的PS或者美图秀秀。在调整色相、饱和度、明度时,需要将每个像素点的rgb色彩空间转换到hsv色彩空间,然后做相应计算调整,最后在将计算结果转换回rgb颜色空间进行显示。有关概念及转换公式可以参考: http://zh.wikipedia.org/wiki/HSL%E5%92%8CHSV%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4
对于每个颜色向量 (r, g, b),参照转换公式,两个空间的相互转换就十分简单了。
       下面为C++转换代码:
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;
}

// BGR(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;
}

// HSV转BGR
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 = "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;//调整色相 +60.取值范围为[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("my", img);

    // 色彩空间转换>>调用OpenCV
    cvtColor(tmp, tmp, CV_BGR2HSV); 
    vector<Mat> channels; 
    split(tmp, channels); 
    channels[0] += 30;// 调整色相 +30.这里没有做范围判断,opencv的h取值范围为[0, 180) 
    merge(channels, tmp); 
    cvtColor(tmp, tmp, CV_HSV2BGR); 
    imshow("opencv", tmp); 
    cv::waitKey();
    
    return 0;
}
ps:main()函数中同时提供了调用opencv函数实现的色相调整功能,主要使用了cvtColor():色彩空间转换、split():通道分离及merge():通道合并等函数。程序使用的opencv版本为210,运行上述程序还需添加opencv头文件引用以及配置相应lib文件。由于程序只是作为验证demo,所以写的有点乱、不够优化。
  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值