Opencv YCbCr 色彩空间

JPEG 压缩——第三步:YCbCr 色彩空间

在 YCbCr 色彩空间内,将 Y 乘以0.7以使对比度变暗。

YCbCr 色彩空间是用于将图像由表示亮度的 Y、表示蓝色色度Cb以及表示红色色度Cr表示的方法。

这用于 JPEG 转换。

使用下式从 RGB 转换到 YCbCr:
Y = 0.299 \ R + 0.5870 \ G + 0.114 \ B\\
Cb = -0.1687\ R – 0.3313 \ G + 0.5 \ B + 128\\
Cr = 0.5 \ R – 0.4187 \ G – 0.0813 \ B + 128

使用下式从 YCbCr 转到 RGB:
R = Y + (Cr – 128) \ 1.402\\
G = Y – (Cb – 128) \ 0.3441 – (Cr – 128) \ 0.7139\\
B = Y + (Cb – 128) \ 1.7718

python实现:

import cv2
import numpy as np
import matplotlib.pyplot as plt

channel = 3

# BGR -> Y Cb Cr
def BGR2YCbCr(img):
  H, W, _ = img.shape

  ycbcr = np.zeros([H, W, 3], dtype=np.float32)

  ycbcr[..., 0] = 0.2990 * img[..., 2] + 0.5870 * img[..., 1] + 0.1140 * img[..., 0]
  ycbcr[..., 1] = -0.1687 * img[..., 2] - 0.3313 * img[..., 1] + 0.5 * img[..., 0] + 128.
  ycbcr[..., 2] = 0.5 * img[..., 2] - 0.4187 * img[..., 1] - 0.0813 * img[..., 0] + 128.

  return ycbcr

# Y Cb Cr -> BGR
def YCbCr2BGR(ycbcr):
  H, W, _ = ycbcr.shape

  out = np.zeros([H, W, channel], dtype=np.float32)
  out[..., 2] = ycbcr[..., 0] + (ycbcr[..., 2] - 128.) * 1.4020
  out[..., 1] = ycbcr[..., 0] - (ycbcr[..., 1] - 128.) * 0.3441 - (ycbcr[..., 2] - 128.) * 0.7139
  out[..., 0] = ycbcr[..., 0] + (ycbcr[..., 1] - 128.) * 1.7718

  out = np.clip(out, 0, 255)
  out = out.astype(np.uint8)

  return out


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

# bgr -> Y Cb Cr
ycbcr = BGR2YCbCr(img)

# process
ycbcr[..., 0] *= 0.7

# YCbCr > RGB
out = YCbCr2BGR(ycbcr)

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

c++实现:

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

// BGR -> Y Cb Cr
cv::Mat BGR2YCbCr(cv::Mat img, cv::Mat out){
  int width = img.rows;
  int height = img.cols;

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

  for (int j = 0; j < height; j ++){
    for (int i = 0; i < width; i ++){
      // Y
      out.at<cv::Vec3b>(j, i)[0] = (int)((float)img.at<cv::Vec3b>(j,i)[0] * 0.114 + \
                  (float)img.at<cv::Vec3b>(j,i)[1] * 0.5870 + \
                  (float)img.at<cv::Vec3b>(j,i)[2] * 0.299);

      // Cb
      out.at<cv::Vec3b>(j, i)[1] = (int)((float)img.at<cv::Vec3b>(j,i)[0] * 0.5 + \
                  (float)img.at<cv::Vec3b>(j,i)[1] * (-0.3323) + \
                  (float)img.at<cv::Vec3b>(j,i)[2] * (-0.1687) + 128);

      // Cr
      out.at<cv::Vec3b>(j, i)[2] = (int)((float)img.at<cv::Vec3b>(j,i)[0] * (-0.0813) + \
                  (float)img.at<cv::Vec3b>(j,i)[1] * (-0.4187) + \
                  (float)img.at<cv::Vec3b>(j,i)[2] * 0.5 + 128);
    }
  }
  return out;
}

// Y Cb Cr -> BGR
cv::Mat YCbCr2BGR(cv::Mat ycbcr, cv::Mat out){

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

  for (int j = 0; j < height; j ++){
    for (int i = 0; i < width; i ++){
      // R
      out.at<cv::Vec3b>(j, i)[2] = (uchar)(ycbcr.at<cv::Vec3b>(j, i)[0] + (ycbcr.at<cv::Vec3b>(j, i)[2] - 128) * 1.4102);

      // G
      out.at<cv::Vec3b>(j, i)[1] = (uchar)(ycbcr.at<cv::Vec3b>(j, i)[0] - (ycbcr.at<cv::Vec3b>(j, i)[1] - 128) * 0.3441 - (ycbcr.at<cv::Vec3b>(j, i)[2] - 128) * 0.7139);

      // B
      out.at<cv::Vec3b>(j, i)[0] = (uchar)(ycbcr.at<cv::Vec3b>(j, i)[0] + (ycbcr.at<cv::Vec3b>(j, i)[1] - 128) * 1.7718);
    }
  }
  return out;
}

cv::Mat process(cv::Mat ycbcr){
  int width = ycbcr.rows;
  int height = ycbcr.cols;

  for(int y = 0; y < height; y++){
    for(int x = 0; x < width; x++){
      ycbcr.at<cv::Vec3b>(y, x)[0] *= 0.7;
    }
  }

  return ycbcr;
}


// Main
int main(int argc, const char* argv[]){

  // read original image
  cv::Mat img = cv::imread("imori.jpg", cv::IMREAD_COLOR);

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

  // output image
  cv::Mat ycbcr = cv::Mat::zeros(height, width, CV_32FC3);
  cv::Mat out = cv::Mat::zeros(height, width, CV_8UC3);

  // BGR -> Y Cb Cr
  ycbcr = BGR2YCbCr(img, ycbcr);

  // Process
  ycbcr = process(ycbcr);

  // Y Cb Cr -> BGR
  out = YCbCr2BGR(ycbcr, out);


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

  return 0;
}


输入:

Opencv YCbCr 色彩空间

输出:

Opencv YCbCr 色彩空间

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程