您的位置:首页 > 编程语言 > C语言/C++

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

2017-09-27 22:12 856 查看
http://docs.opencv.org/index.html

       但凡图像处理软件,都会提供色相、饱和度、明度调整功能,比如常见的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++转换代码:

[cpp] view
plain copy

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,所以写的有点乱、不够优化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: