马老师带你学opencv(HSV变换)


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=060MaxMinGR+6060MaxMinBG+18060MaxMinRB+300( if Min=Max)( if Min=B)( if Min=R)( if Min=G)
饱和度:
S = Max ⁡ − Min ⁡ S=\operatorname{Max}-\operatorname{Min} S=MaxMin
明度:
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)=(VC)(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 0H<1)( if  (if 2H<3) (if 3H<4) (if 4H<5)( if 1H<2)5H<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;
}

结果图

结果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值