Opencv HSV 变换

HSV 变换就是HSV色彩和RGB色彩之间可以互相转换。

HSV 即使用色相(Hue)、饱和度(Saturation)、明度(Value)来表示色彩的一种方式。

  • 色相:将颜色使用0到360度表示,就是平常所说的颜色名称,如红色、蓝色。色相与数值按下表对应:
绿 青色 蓝色 品红
0 60 120 180 240 300 360
  • 饱和度:是指色彩的纯度,饱和度越低则颜色越黯淡( 0<= S < 1);
  • 明度:即颜色的明暗程度。数值越高越接近白色,数值越低越接近黑色 ( 0 <= V < 1);

从 RGB 色彩表示转换到 HSV 色彩表示通过以下方式计算:

R,G,B的值在[0, 1]之间:

Max = max(R,G,B)
Min = min(R,G,B)

H =  { 0                            (if Min=Max)
       60 x (G-R) / (Max-Min) + 60  (if Min=B)
       60 x (B-G) / (Max-Min) + 180 (if Min=R)
       60 x (R-B) / (Max-Min) + 300 (if Min=G)

V = Max

S = Max - Min

从 HSV 色彩表示转换到 RGB 色彩表示通过以下方式计算:

C = S

H' = H / 60

X = C (1 - |H' mod 2 - 1|)

(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)

请将色相反转(色相值加180),然后再用 RGB 色彩空间表示图片。

python实现:

import cv2
import numpy as np

# Read image
img = cv2.imread("imori.jpg").astype(np.float32) / 255.

# RGB > HSV
out = np.zeros_like(img)

max_v = np.max(img, axis=2).copy()
min_v = np.min(img, axis=2).copy()
min_arg = np.argmin(img, axis=2)

H = np.zeros_like(max_v)

H[np.where(max_v == min_v)] = 0
## if min == B
ind = np.where(min_arg == 0)
H[ind] = 60 * (img[..., 1][ind] - img[..., 2][ind]) / (max_v[ind] - min_v[ind]) + 60
## if min == R
ind = np.where(min_arg == 2)
H[ind] = 60 * (img[..., 0][ind] - img[..., 1][ind]) / (max_v[ind] - min_v[ind]) + 180
## if min == G
ind = np.where(min_arg == 1)
H[ind] = 60 * (img[..., 2][ind] - img[..., 0][ind]) / (max_v[ind] - min_v[ind]) + 300

V = max_v.copy()
S = max_v.copy() - min_v.copy()

# Transpose Hue
H = (H + 180) % 360

# HSV > RGB

C = S
H_ = H / 60
X = C * (1 - np.abs( H_ % 2 - 1))
Z = np.zeros_like(H)

vals = [[Z,X,C], [Z,C,X], [X,C,Z], [C,X,Z], [C,Z,X], [X,Z,C]]

for i in range(6):
    ind = np.where((i <= H_) & (H_ < (i+1)))
    out[..., 0][ind] = (V-C)[ind] + vals[i][0][ind]
    out[..., 1][ind] = (V-C)[ind] + vals[i][1][ind]
    out[..., 2][ind] = (V-C)[ind] + vals[i][2][ind]

out[np.where(max_v == min_v)] = 0
out = (out * 255).astype(np.uint8) 

# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()

C++实现:

#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <math.h>

int main(int argc, const char* argv[]){
  cv::Mat img = cv::imread("imori.jpg", cv::IMREAD_COLOR);

  int width = img.rows;
  int height = img.cols;

  double _max, _min;
  double r, g ,b;
  double h, s, v;
  double c, _h, x;
  double _r, _g, _b;

  cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);

  for (int j=0; j<height; j++){
    for (int i=0; i<width; i++){
      // HSV
      r = (float)img.at<cv::Vec3b>(j,i)[2] / 255;
      g = (float)img.at<cv::Vec3b>(j,i)[1] / 255;
      b = (float)img.at<cv::Vec3b>(j,i)[0] / 255;

      _max = fmax(r, fmax(g, b));
      _min = fmin(r, fmin(g, b));

      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;
      }
      v = _max;
      s = _max - _min;

      // inverse hue
      h = fmod((h + 180), 360);

      // inverse HSV
      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>(j,i)[0] = (uchar)(_b * 255);
      out.at<cv::Vec3b>(j,i)[1] = (uchar)(_g * 255);
      out.at<cv::Vec3b>(j,i)[2] = (uchar)(_r * 255);
    }
  }

  //cv::imwrite("out.jpg", out);
  cv::imshow("answer", out);
  cv::waitKey(0);
  cv::destroyAllWindows();

  return 0;

}

输入:

HSV 变换

输出:

HSV 变换

赞(3)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Opencv实例